Skip to content

Allow more Core tests to pass via "capture"#4359

Draft
d-torrance wants to merge 2 commits into
Macaulay2:developmentfrom
d-torrance:capture-tests
Draft

Allow more Core tests to pass via "capture"#4359
d-torrance wants to merge 2 commits into
Macaulay2:developmentfrom
d-torrance:capture-tests

Conversation

@d-torrance
Copy link
Copy Markdown
Member

When running check Core, each test is first attempted via capture (in-process) before falling back to an external M2 subprocess. This PR fixes several tests that were failing the capture step unnecessarily, due to two distinct root causes:

  • ext-total.m2 set a global debugging flag and never reset it, causing subsequent tests in the same process to fail spuriously.
  • Several tests relied on use ring to install named ring generators as global variables, which does not work correctly in the capture context due to how it manages symbol dictionaries. These tests have been rewritten to reference ring generators directly.

After this, all Core tests should pass on the first try, i.e., no more "capture failed" messages.

AI Disclosure

Claude Code did all the hard work. I just copy-pasted error messages and it took it from there.

d-torrance and others added 2 commits May 22, 2026 21:40
…ures

ext-total.m2 sets flagInhomogeneity = true (a debugging flag that turns
inhomogeneous GB computations into errors) but never resets it.  When
tests run via capture in the same process, this global mutation persists:
any subsequent test that triggers a GB computation on an inhomogeneous
matrix (e.g. galois1.m2, which calls GF()) would fail with "internal
error: gb: inhomogeneous matrix flagged" — even though the test is
correct.  The fix is to reset the flag at the end of ext-total.m2.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… mismatch

Root cause: capture() replaces User#"private dictionary" with a fresh empty
one and builds a dictionaryPath that omits the old dictionary.  Symbols such
as T (used by degreesMonoid for degrees-ring generators) and x (used for toric
variety ring generators) were created via getSymbol at M2 startup or package
load time and therefore live in the OLD private dictionary.  When a captured
test encounters T_0, x_1, etc., the parser cannot find the parent symbol in
the new dictionaryPath and creates a fresh symbol there instead.  Subsequent
calls to "use ring" correctly update the IndexedVariableTable of the OLD symbol,
but the captured code reads the NEW symbol (empty table) and gets IndexedVariable
objects rather than ring elements.  A comment in examples.m2 acknowledges the
T case explicitly ("necessary mainly due to T from degreesMonoid"); the
workaround there was removed for an unrelated reason.

Two manifestations, two fixes applied:

  hilbertFunction.m2, hilbertSeries.m2, multidegree.m2, schenck-book-7.m2:
    Replace bare T_0/T_1/x_i references with explicit ring subscripts
    (e.g. HR_0, DR_0, A_0, C_0) using Ring _ ZZ, bypassing symbol lookup.
    "use ring" lines that existed only to bring T_0/T_1 into scope are dropped.

  poincare2.m2:
    r uses degreesRing{1,1} (List-memoized) and R uses degreesRing 2
    (ZZ-memoized); in capture these may be memoized with different T symbols,
    so map(ring poincare r, ring poincare R) matches nothing and sends all
    generators to 0.  Fix: pass explicit generator images so the map does not
    rely on name-based symbol matching.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
t = tally degrees target presentation E
assert ( t === u )

flagInhomogeneity = false
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.

flagInhomogeneity should probably be added to the no-capture regex list.

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.

It's not exported, so I can't imagine too many tests would use it

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.

Oh wait I just saw there's debug Core at the top of these file, shouldn't debug automatically disable capture?

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.

Hmm I guess the side effects of debug itself are usually reverted by other stuff that capture does, but also debug Core enables a whole bunch of shenanigans we don't look for ... maybe debug Core should specifically force not using capture? idk!

assert( degree x === degree X )
assert( degree y === degree Y )
f = map(ring poincare r, ring poincare R)
f = map(ring poincare r, ring poincare R, generators ring poincare r)
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.

Why did this fail without specifying the generators?

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.

Great question! Here's the test failure:

 -- i1 : -- test source: ../tests/normal/poincare2.m2:1:1-50:7
 --      r = QQ[x,y,Degrees => {{2,1},{1,3}}, Heft => {1,1}]
 -- 
 -- o1 = r
 -- 
 -- o1 : PolynomialRing
 -- 
 -- i2 : R = QQ[X,Y,Degrees => {{2,1},{1,3}}]
 -- 
 -- o2 = R
 -- 
 -- o2 : PolynomialRing
 -- 
 -- i3 : assert( degrees source vars R === degrees source vars r )
 -- 
 -- i4 : assert( degrees R^{{2,3},{4,1},{1,0},{0,1}} === degrees r^{{2,3},{4,1},{1,0},{0,1}} )
 -- 
 -- i5 : assert( degree x === degree X )
 -- 
 -- i6 : assert( degree y === degree Y )
 -- 
 -- i7 : f = map(ring poincare r, ring poincare R)
 -- 
 -- o7 = map (ZZ[T ..T ], ZZ[T ..T ], {0, 0})
 --               0   1       0   1
 -- 
 -- o7 : RingMap ZZ[T ..T ] <-- ZZ[T ..T ]
 --                  0   1          0   1
 -- 
 -- i8 : assert( poincare r === f poincare R )
 -- 
 -- i9 : assert( poincare (r/(x)) === f poincare (R/(X)) )
 -- currentString:10:6:(3):[14]: error: assertion failed

I'm guessing that map(Ring, Ring) runs into some shenanigans with the symbol T.

@mahrud
Copy link
Copy Markdown
Member

mahrud commented May 23, 2026

I agree that replacing use R with R_i fixes the problems, but I think there's utility in making sure that 'use R' and 'x_i' and things like that continue to work and don't break unintentionally. I would consider adding no-capture-flag instead for some of these, but don't feel strongly about it.

@d-torrance
Copy link
Copy Markdown
Member Author

I agree that replacing use R with R_i fixes the problems, but I think there's utility in making sure that 'use R' and 'x_i' and things like that continue to work and don't break unintentionally. I would consider adding no-capture-flag instead for some of these, but don't feel strongly about it.

Good point. After these changes, use still appears 110 times in the Core tests, so I think it's probably well tested!

@mahrud
Copy link
Copy Markdown
Member

mahrud commented May 23, 2026

Sorry, let me rephrase: it's worth thinking whether there's a fix in Core (involving use/global symbols/etc) we could make to fix this capture errors. (I mentioned no-capture-flag earlier because to me every no-capture-flag indicates a bug that should be fixed in the future)

added: these may be very very edge cases, but I'm sure some users come upon them and don't know what's going on.

@d-torrance
Copy link
Copy Markdown
Member Author

Good point. I think the underlying bug for most of these might be #2232.

@d-torrance d-torrance marked this pull request as draft May 23, 2026 14:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants