Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
2b3de4d
adding in code for testing weyl algebras, also CLAUDE.md file for eng…
mikestillman Feb 21, 2026
42a92cb
add RingElem: lightweight value-semantics wrapper for unit tests
mikestillman Feb 22, 2026
478ce0c
switch RingElem class to use mRing, mValue as member fields, and usin…
mikestillman Feb 23, 2026
79c0eef
add idealFromStrings, computeGB, simpleQuotientRing utilities and a s…
mikestillman Feb 23, 2026
a4d3cc9
EliminationTemplates v1
timduff35 May 1, 2026
c1c7fea
merge in main
timduff35 May 1, 2026
5195c5d
some requested fixes
timduff35 May 1, 2026
7da035d
more fixes
timduff35 May 1, 2026
66e78d0
more fixes
timduff35 May 1, 2026
8a9dcd1
documentation + fixes
timduff35 May 1, 2026
b7898f8
documentation + fixes
timduff35 May 1, 2026
babece6
update list of distributed packgaes
timduff35 May 1, 2026
d54306e
move files, fix warnings
timduff35 May 1, 2026
1af67b2
typo
timduff35 May 1, 2026
d84f473
Minor addition to util functions
mikestillman May 17, 2026
63aeaa3
First commit of a file that Mike gave us
dswinarski May 17, 2026
bf80699
Changed comments to use doxygen style
haackett May 17, 2026
5228360
small test refactoring
dimpase May 17, 2026
416ccbc
fix IM2 in matrix.h/.cpp
local-ring May 17, 2026
22b9779
updating sagbi.hpp doxygen
timduff35 May 17, 2026
74579de
merge michael
timduff35 May 17, 2026
c1b8a4a
Turned IM2 names to raw
ddale27 May 17, 2026
6a699f6
Merge branch 'unit-testing' of github.com:mikestillman/M2
HansLjy May 17, 2026
0084d39
Fixed broken .d files
ddale27 May 18, 2026
5e44ec2
Merge pull request #12 from timduff35/mburr-group3
MichaelABurr May 18, 2026
aa23519
Merge pull request #11 from local-ring/Group3
MichaelABurr May 18, 2026
cb44e47
Merge pull request #8 from dswinarski/Group2
MichaelABurr May 18, 2026
56fe2c1
Merge pull request #10 from haackett/Group4
MichaelABurr May 18, 2026
514fad8
Merge branch 'Group3' into Group3
MichaelABurr May 18, 2026
9358928
Merge pull request #14 from ddale27/Group3
MichaelABurr May 18, 2026
80c88a5
Merge pull request #13 from dimpase/Group1
MichaelABurr May 18, 2026
3f430f1
set JAVADOC_AUTBRIEF to YES
haackett May 18, 2026
57884e5
add doxygen docs on polynomial and polynomial list parsing
haackett May 18, 2026
c2e6065
reformat comments from Eschreyer, ExponentVector, and complex to doxygen
haackett May 18, 2026
de9d6ea
push logic of rawMatrixEntries down to core from interface
local-ring May 18, 2026
3cf84c9
Refactored free resolutions interface
ddale27 May 18, 2026
5107d38
Fixed segfault issue in make_FreeModule
ddale27 May 18, 2026
8453a8a
Add unit-test for new method Matrix::entries
local-ring May 18, 2026
b0cd5b3
push logic of rawMatrixPromote down to core from interface by introdu…
local-ring May 19, 2026
b82420e
Add unit-test for method Matrix::promote
local-ring May 19, 2026
bf830b2
Merge pull request #17 from local-ring/Group3
MichaelABurr May 19, 2026
33e28d1
Merge pull request #16 from ddale27/Group3
MichaelABurr May 19, 2026
277e9a3
Merge pull request #15 from haackett/Group4
MichaelABurr May 19, 2026
fcea540
Merge pull request #18 from MichaelABurr/Group2
MichaelABurr May 19, 2026
1bc3d72
Merge pull request #19 from MichaelABurr/Group3
MichaelABurr May 19, 2026
6e507f4
Merge pull request #20 from MichaelABurr/Group4
MichaelABurr May 19, 2026
f2e9d73
Push down rawMatrixLift
local-ring May 19, 2026
22554a4
Push down rawMatrixConcat
local-ring May 19, 2026
35092cb
Push down rawMatrixDirectSum
local-ring May 19, 2026
88446c2
Add Unit-test
local-ring May 19, 2026
fea71d1
fix a failed unit-test because of the name migration of IM2*
local-ring May 19, 2026
de861cb
Push down rawMatrixEntry
local-ring May 19, 2026
1c51b13
Merge pull request #26 from local-ring/AtlantaGroups
MichaelABurr May 20, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
326 changes: 326 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,326 @@
# Macaulay2 Engine Development Guide

## Project Overview

Macaulay2 is a software system for algebraic geometry research. This guide focuses on the
C++ engine in `M2/Macaulay2/e/`, which is the computational core.

## Repository Structure

```
M2/ Top-level build directory
CMakeLists.txt CMake entry point (requires 3.24+, C++17)
configure.ac Autotools configuration
Macaulay2/
e/ Engine (C++ computational core, ~500 source files)
CMakeLists.txt Builds M2-engine static library and M2-unit-tests
Makefile.in Autotools build for engine
unit-tests/ GoogleTest-based unit tests
Makefile.in Autotools build for unit tests
Makefile.files List of test source files (shared by autotools)
interface/ Public C/C++ API (ring, matrix, groebner, etc.)
f4/ Faugere F4 algorithm
gb-f4/ GB F4 computation interface
NCAlgebras/ Non-commutative algebra support
schreyer-resolution/ Schreyer resolution (F4-style linear algebra)
bibasis/ Boolean Involutive Groebner Bases
d/ Interpreter
m2/ M2 language libraries
packages/ User packages
submodules/ Git submodules (googletest, flint, bdwgc, etc.)
cmake/ CMake modules (check-libraries, build-libraries, etc.)
libraries/ External library sources
```

## Engine Unit Tests

### Location and Framework

Tests are in `M2/Macaulay2/e/unit-tests/` using **GoogleTest** (gtest).

### Key Files

- `testMain.cpp` - Test entry point; calls `IM2_initialize()` then `RUN_ALL_TESTS()`
- `M2-cpp-replacement.cpp` - Stub for `system_interrupted()` (avoids linking interpreter)
- `ARingTest.hpp` - Templated test helpers for arithmetic ring operations (negate, add,
subtract, multiply, divide, reciprocal, power, axioms, coercions)
- `RingTest.hpp` - Test helpers for Ring interface
- `DMatTest.hpp` - Test helpers for dense matrices
- `RingElem.hpp/cpp` - Lightweight value-semantics wrapper for ring elements (see below)
- `util-polyring-creation.hpp/cpp` - Helpers for creating rings in tests:
- `simplePolynomialRing(p, names)` - polynomial ring over ZZ/p (or QQ if p=0)
- `simpleWeylAlgebra(p, names, comms, derivs)` - Weyl algebra
- `degreeRing(n)` - degree ring with n variables

### Existing Test Files

| Test File | What It Tests |
|-----------|---------------|
| `ARingZZTest.cpp` | Integers (flint) |
| `ARingZZpTest.cpp` | Z/p (multiple implementations) |
| `ARingQQFlintTest.cpp` | Rationals (flint) |
| `ARingQQGmpTest.cpp` | Rationals (GMP) |
| `ARingRRTest.cpp` | Machine reals |
| `ARingCCTest.cpp` | Machine complex |
| `ARingRRRTest.cpp` | Arbitrary-precision reals (MPFR) |
| `ARingRRiTest.cpp` | Arbitrary-precision real intervals (MPFI) |
| `ARingCCCTest.cpp` | Arbitrary-precision complex |
| `RingZZTest.cpp` | ZZ via Ring interface |
| `RingZZpTest.cpp` | ZZp via Ring interface |
| `RingQQTest.cpp` | QQ via Ring interface |
| `RingRRRTest.cpp` | RRR via Ring interface |
| `RingCCCTest.cpp` | CCC via Ring interface |
| `RingTowerTest.cpp` | Tower of polynomial rings |
| `DMatZZpTest.cpp` | Dense matrices over ZZp |
| `MonoidTest.cpp` | Monoid operations |
| `PolyRingTest.cpp` | Polynomial ring operations |
| `NCGroebnerTest.cpp` | Non-commutative Groebner bases |
| `WeylAlgebraTest.cpp` | Weyl algebra creation, commutators, binomial, multinomial, fromString |
| `NewF4Test.cpp` | New F4 algorithm |
| `ResTest.cpp` | Resolutions |
| `MatrixIOTest.cpp` | Matrix I/O |
| `SubsetTest.cpp` | Subset operations |
| `PointArray.cpp` | Point array operations |
| `basics-test.cpp` | Buffer, utility functions |
| `fromStream.cpp` | Stream parsing |

### Excluded Test Files

| Test File | Why Excluded |
|-----------|-------------|
| `ARingGFTest.cpp` | ARingGFFlint API changed: constructor now requires `PolynomialRing` + primitive element (was `(int p, int n)`), and `cardinality()` method is missing |

### Linking Requirements

The unit tests link against the M2 engine library. The only additional file needed is
`M2-cpp-replacement.cpp`, which stubs out `system_interrupted()` — a function normally
supplied by the Macaulay2 executable. `testMain.cpp` calls `IM2_initialize()` to
handle engine initialization (including GC).

### Writing New Tests

Pattern for arithmetic ring tests (standalone `TEST` macros):
```cpp
#include <gtest/gtest.h>
#include "aring-zz-flint.hpp" // or whichever ring
#include "ARingTest.hpp" // templated test helpers

TEST(MyRing, create) {
M2::ARingZZ R;
// ... test ring properties
}

TEST(MyRing, arithmetic) {
M2::ARingZZ R;
testCoercions(R);
testNegate(R, ntrials);
testAdd(R, ntrials);
// ...
}
```

Pattern for tests using polynomial rings (use `util-polyring-creation.hpp`):
```cpp
#include "util-polyring-creation.hpp"
const PolynomialRing* R = simplePolynomialRing(101, {"a", "b", "c"});
const WeylAlgebra* W = simpleWeylAlgebra(0, {"x","y","Dx","Dy"}, {0,1}, {2,3});
```

Pattern for test fixtures with shared setup (use `TEST_F`):
```cpp
class MyTest : public ::testing::Test {
protected:
SomeRing* R = nullptr;
void SetUp() override {
R = /* create ring */;
}
};

TEST_F(MyTest, someTest) {
// R is available here, freshly created for each test
}
```

### Testing Private/Protected Members

Use the friend class pattern. Add `friend class FooTestAccessor;` to the class header,
then define a test accessor in the test file with static forwarding methods:
```cpp
// In the .hpp file:
class Foo {
friend class FooTestAccessor;
// ...
};

// In the test .cpp file:
class FooTestAccessor {
public:
static int privateMethod(const Foo* f, int arg) {
return f->privateMethod(arg);
}
};
```
See `WeylAlgebraTest.cpp` and `weylalg.hpp` for a concrete example.

### RingElem — Lightweight Value Wrapper for Tests

`RingElem` (in `unit-tests/RingElem.hpp`) wraps `const Ring*` + `ring_elem` with
value semantics. Operators return values (not pointers), making test code concise:
```cpp
#include "RingElem.hpp"
auto x = RingElem::var(R, 0);
auto y = RingElem::var(R, 1);
auto one = RingElem::fromInt(R, 1);
EXPECT_EQ(x * y - y * x, one); // value comparison, prints elements on failure

// Parse from string (requires explicit ^ and * in polynomial syntax):
auto f = RingElem::fromString(R, "x^2+3*x*y-1");

// Scalar multiplication:
auto g = x * 3; // RingElem * long
auto h = 3 * x; // long * RingElem
```

Factories: `RingElem::var(R, i)`, `RingElem::fromInt(R, n)`, `RingElem::fromString(R, s)`.
Arithmetic: `+`, `-`, `*`, `/`, unary `-`, `.power(n)`.
Output: `to_string()`, `operator<<` for gtest diagnostics.

**fromString format**: Uses `parseBasicPoly` from `BasicPoly.hpp`. Requires `*` between
factors and `^` for exponents (e.g. `"3*x^2*y-1"`). Note: `to_string()` outputs a
different format (`x2y-1` without `*` or `^`), so round-tripping is not yet supported.

**Naming convention**: Member fields use `m` prefix (e.g., `mRing`, `mValue`).

### RingElement (Legacy Interface)

`RingElement` operators (`*`, `+`, `-`, `/`) return `RingElement*` (pointers), not values.
Prefer `RingElem` for new test code. `RingElement` is still used in the interpreter interface.
```cpp
RingElement *x = new RingElement(W, W->var(0));
RingElement *product = (*x) * (*y); // dereference, then multiply
EXPECT_TRUE(product->is_equal(*expected));
```
`is_equal` checks ring pointer equality first — both elements must come from the same
ring object. Use `IM2_Ring_QQ()` (QQGMP) consistently, not `rawARingQQFlint()`, when
creating rings whose elements will be compared.

### M2_arrayint in Tests

Many engine functions take `M2_arrayint` (a GC-allocated array). Convert from
`std::vector<int>` using:
```cpp
#include "util.hpp"
M2_arrayint arr = stdvector_to_M2_arrayint(std::vector<int>{2, 3, 5});
```

## Building and Running Tests

Build configurations are defined in `M2/BUILD/mike/Makefile`. Existing builds live
under `M2/BUILD/mike/builds.tmp/`.
Comment on lines +218 to +219
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think either this CLAUDE.md file should be in M2/BUILD/mike or if it's in the repository root it should be usable to others.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at the blame, this seems to be from @mikestillman from 3 months ago. Mike, can you comment on these lines?


### CMake Build

The active cmake build directory is:
`M2/BUILD/mike/builds.tmp/cmake-appleclang` (RelWithDebInfo, Ninja)

```sh
# Build unit tests:
ninja -C M2/BUILD/mike/builds.tmp/cmake-appleclang M2-unit-tests

# Run all engine unit tests:
ctest --test-dir M2/BUILD/mike/builds.tmp/cmake-appleclang -R unit-tests

# Run a specific test by name:
ctest --test-dir M2/BUILD/mike/builds.tmp/cmake-appleclang -R "WeylAlgebra" --output-on-failure

# Or run the executable directly:
M2/BUILD/mike/builds.tmp/cmake-appleclang/Macaulay2/e/M2-unit-tests
# With a gtest filter:
M2/BUILD/mike/builds.tmp/cmake-appleclang/Macaulay2/e/M2-unit-tests --gtest_filter="WeylAlgebra*"
```

The CMake build uses `gtest_discover_tests()` with prefix `unit-tests:`.

### Autotools Build

The active autotools build directory is:
`M2/BUILD/mike/builds.tmp/arm64-appleclang`

```sh
# From the autotools build directory, in Macaulay2/e/unit-tests/:
gmake -k check
# Or run the executable directly:
./testMain
```

If `e/unit-tests/Makefile.in` changes, regenerate the build Makefile:
```sh
# From the autotools build root:
./config.status Macaulay2/e/unit-tests/Makefile
```

### Adding a New Test File

1. Add the `.cpp` file to `e/unit-tests/`
2. Add it to `e/CMakeLists.txt` in the `add_executable(M2-unit-tests ...)` section
3. Add it to `e/unit-tests/Makefile.files` in the `UNITTEST_CCFILES` list
4. Build and run tests in **both** cmake and autotools to verify

### Keeping Builds in Sync

The CMake and autotools builds maintain separate lists of test files:
- CMake: `e/CMakeLists.txt` — the `add_executable(M2-unit-tests ...)` block
- Autotools: `e/unit-tests/Makefile.files` — the `UNITTEST_CCFILES` variable

Both should include the same set of test files. Currently 199 tests pass in both builds.

## Engine Dependencies

All of the following are linked to the `M2-engine` target (see `e/CMakeLists.txt`).

### Submodule Dependencies (built as part of engine)
- **memtailor** - Special-purpose memory allocators
- **mathic** - Symbolic algebra data structures
- **mathicgb** - Signature Groebner bases library
- **googletest** - Unit testing framework (for M2-unit-tests only)

### Header-Only Libraries
- **Eigen3** (3.4.0+) - Linear algebra templates

### Libraries (found via pkg-config)
- **FFLAS_FFPACK** (2.4.3+) - Finite field linear algebra routines (needs LAPACK, GIVARO)
- **GIVARO** (4.1.1+) - Prime field and algebraic computations

### Libraries (found via find_package / FindXxx.cmake)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure what's the source of this list, but it seems very incomplete (e.g. tbb and boost are missing). Perhaps we could just write that the list of dependencies should be read from cmake/check-libraries.cmake?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that it would be best for this to be a complete list or to not have the list at all. I believe that this also comes from @mikestillman .

- **GMP** (6.0.0+) - GNU multiprecision arithmetic
- **MPFR** (4.0.1+) - Multiprecision floating-point (needs GMP)
- **MPFI** (1.5.1+) - Multiprecision floating-point intervals (needs GMP, MPFR)
- **FLINT** (3.0.0+) - Fast library for number theory (needs GMP, MPFR)
- **NTL** (10.5.0+) - Number theory library (needs GMP)
- **FACTORY** (4.4.0+) - Polynomial factorization (needs GMP, FLINT, NTL)
- **BDWGC** (7.6.4+) - Boehm-Demers-Weiser garbage collector
- **LAPACK** - Linear algebra (BLAS/LAPACK)
- **MPSOLVE** (3.2.0+) - Multiprecision polynomial solver
- **FROBBY** (0.9.0+) - Computations with monomial ideals
- **NORMALIZ** (3.8.0+) - Discrete convex geometry (needs GMP, Nauty)
Note: READLINE, HISTORY, and GDBM are in the top-level `LIBRARY_LIST` but are only
used by the interpreter (`d/`), not the engine.

### Optional
- **OpenMP** - Parallel processing

## Code Conventions

- C++17 standard (`-std=gnu++17`)
- Arithmetic ring types live in `M2` namespace (e.g., `M2::ARingZZ`, `M2::ARingZZp`)
- Ring elements use init/clear pattern: `R.init(a); ... R.clear(a);`
- `buffer` class (from `buffer.hpp`) used for string building and text output
- Interface functions prefixed with `IM2_` (e.g., `IM2_initialize()`)
- Source files generally come in `.cpp`/`.hpp` pairs
- Use `IM2_Ring_QQ()` for the rationals (QQGMP) in tests, not `rawARingQQFlint()`
- New classes should use `m` prefix for member fields (e.g., `mRing`, `mValue`)

## Branch Info

- Current branch: `unit-testing` (improving engine unit test infrastructure)
- PR target: `stable`
12 changes: 6 additions & 6 deletions M2/Macaulay2/d/actors4.d
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ use pthread;
use regex;

header "// required for toString routines
#include <engine.h> // for IM2_GB_to_string, rawMuta... // TODO: remove this one
#include <engine.h> // for rawGBToString, rawMuta... // TODO: remove this one
#include <interface/NAG.h> // for rawHomotopyToString, rawP...
#include <interface/freemodule.h> // for IM2_FreeModule_to_string
#include <interface/matrix.h> // for IM2_Matrix_to_string
#include <interface/freemodule.h> // for rawFreeModuleToString
#include <interface/matrix.h> // for rawMatrixToString
#include <interface/monoid.h> // for rawMonoidToString
#include <interface/monomial-ordering.h> // for IM2_MonomialOrdering_to_s...
#include <interface/mutable-matrix.h> // for IM2_MutableMatrix_to_string
Expand Down Expand Up @@ -998,8 +998,8 @@ tostringfun(e:Expr):Expr := (
else toExpr("<<a list>>"))
is s:SpecialExpr do tostringfun(s.e)
is x:RawMonomialCell do toExpr(tostring(x.p))
is x:RawFreeModuleCell do toExpr(Ccode(string, "IM2_FreeModule_to_string(",x.p,")" ))
is x:RawMatrixCell do toExpr(Ccode(string, "IM2_Matrix_to_string(",x.p,")" ))
is x:RawFreeModuleCell do toExpr(Ccode(string, "rawFreeModuleToString(",x.p,")" ))
is x:RawMatrixCell do toExpr(Ccode(string, "rawMatrixToString(",x.p,")" ))
is x:RawMutableMatrixCell do toExpr(Ccode(string, "IM2_MutableMatrix_to_string(",x.p,")" ))
is x:RawMutableComplexCell do toExpr(Ccode(string, "rawMutableComplexToString(",x.p,")" ))
-- NAG stuff begin
Expand All @@ -1016,7 +1016,7 @@ tostringfun(e:Expr):Expr := (
is x:RawRingCell do toExpr(Ccode(string, "IM2_Ring_to_string(",x.p,")" ))
is x:RawRingElementCell do toExpr( Ccode(string, "IM2_RingElement_to_string(",x.p,")" ) )
is x:RawMonomialIdealCell do toExpr( Ccode(string, "IM2_MonomialIdeal_to_string(",x.p,")" ) )
is c:RawComputationCell do toExpr(Ccode(string, "IM2_GB_to_string(",c.p,")" ))
is c:RawComputationCell do toExpr(Ccode(string, "rawGBToString(",c.p,")" ))
is pythonObjectCell do toExpr("<<a python object>>")
is x:xmlNodeCell do toExpr(toString(x.v))
is xmlAttrCell do toExpr("<<libxml attribute>>")
Expand Down
8 changes: 4 additions & 4 deletions M2/Macaulay2/d/equality.dd
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ use util;
use tokens;

header "// required for equality checks
#include <interface/freemodule.h> // for IM2_FreeModule_is_equal
#include <interface/matrix.h> // for IM2_Matrix_is_equal
#include <interface/freemodule.h> // for rawFreeModuleIsEqual
#include <interface/matrix.h> // for rawMatrixIsEqual
#include <interface/monomial-ideal.h> // for IM2_MonomialIdeal_is_equal
#include <interface/ringelement.h> // for IM2_RingElement_is_equal
#include <interface/ringmap.h> // for IM2_RingMap_is_equal
Expand Down Expand Up @@ -208,14 +208,14 @@ export equal(lhs:Expr,rhs:Expr):Expr := (
is x:RawFreeModuleCell do (
when rhs
is y:RawFreeModuleCell do (
if Ccode(bool, "IM2_FreeModule_is_equal(",x.p,",",y.p,")")
if Ccode(bool, "rawFreeModuleIsEqual(",x.p,",",y.p,")")
then True else False
)
else False
)
is x:RawMatrixCell do (
when rhs
is y:RawMatrixCell do toExpr(Ccode(bool, "1 == IM2_Matrix_is_equal(",x.p,",",y.p,")"))
is y:RawMatrixCell do toExpr(Ccode(bool, "1 == rawMatrixIsEqual(",x.p,",",y.p,")"))
else False
)
is x:MysqlConnectionWrapper do (
Expand Down
Loading
Loading