You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
unwrap_expression(symbolic_keep_constants) is exponential on nested constitutive models: 563 s for a 10k-node tree; JIT setup 10-40+ min on the notch #823
unwrap_expression(expr, mode="symbolic_keep_constants") is pathologically slow on nested constitutive models. That mode is the one _jacobian_unwrap uses before every consistent-tangent derivative, and prepare_for_cache_key uses it in the JIT. On the Spiegelman notch, the Jacobian setup alone took 10 to more than 40 minutes before any solve.
_setup_pointwise_functions takes 616 s with the default law and 1,352 s with the powermean law. With a declared plastic_rate_strengthening it exceeds 40 minutes. With the prototype swapped in, the same setup takes 54 s, or 108 s including the JIT, both under cProfile.
The viscosity is a 130-node graph with 18 named sub-expressions. Unwrapped it becomes a 9,913-node tree, so the output is not what costs 563 s.
Cause
unwrap_expression iterates expr.subs(...) passes to a fixed point. Each pass traverses and re-canonicalises the whole growing tree. In symbolic_keep_constants mode, every atom on every pass also calls _is_truly_constant, which is itself a full nondimensional unwrap of that atom. Nothing is memoised.
Fix
Expand each UW atom once (memoised by identity), using the same _unwrap_atom rule and the same truly-constant predicate (also memoised). Then rebuild each expression in one xreplace pass. The output is structurally identical on the notch in both modes.
The rest of the compile (after the fix, profiled)
C source generation: 76 s, of which atoms() scans over the expanded trees are 35 s and printing is 43 s.
debugging_text, a string comment for every kernel, generated whether or not anyone debugs: 23 s.
The sqrt guard's tree-wide .replace in _jacobian_unwrap: 16 s.
Constant extraction: 12 s.
Differentiation: 11 s.
Fixing these is tier 1. Tier 2 would generate code from the shared graph rather than the expanded tree, with each named sub-expression as one C temporary and the Jacobian built by chain rule. That needs a design note.
Found while running the shear-band width scan for PR #794.
Underworld development team with AI support from Claude Code
Fixed by #830, merged into development as f4c19cf: memoised unwrap, real fields with a real-stand-in derivative, and the power-mean sharpness atom. A Newton setup on the notch is down from 616 s / 1,352 s (sqrt / power mean) to 10 s / 13 s. The graph-based code generator (tier 2) is tracked separately on Project 10, with its design note on feature/jit-graph-codegen.
Underworld development team with AI support from Claude Code
Reopened under the issue rule of 2026-10-11 (PR #839): an issue whose fix has merged to development stays open, labelled fixed-in-development, and closes when the fix is released to main. Fixed by #830 (f4c19cf, tier 1) and #836 (45fc612, tier 2).
Activity
Merge pull request #830 from underworldcode/bugfix/jit-setup-cost-823
lmoresi commentedon Oct 7, 2026
Fixed by #830, merged into development as f4c19cf: memoised unwrap, real fields with a real-stand-in derivative, and the power-mean sharpness atom. A Newton setup on the notch is down from 616 s / 1,352 s (sqrt / power mean) to 10 s / 13 s. The graph-based code generator (tier 2) is tracked separately on Project 10, with its design note on feature/jit-graph-codegen.
Underworld development team with AI support from Claude Code
Design note: generate JIT kernels from the shared expression graph (#823
JIT graph route behind UW_JIT_GRAPH (#823, tier 2, staging steps 2 an…
Graph route: conditions stay inline, coordinates spelled from their i…
Design note: suite, iteration spread and #752 results for the graph r…
Design note: the callbacks' share of the notch assembly, per route (#823
assembly_split.py: the constant-viscosity floor drops a viscoelastic …
Design note: the Linux/gcc measurements and the -fmath-errno test (#823)
Design note: generate JIT kernels from the shared expression graph (#823
JIT graph route behind UW_JIT_GRAPH (#823, tier 2, staging steps 2 an…
Graph route: conditions stay inline, coordinates spelled from their i…
Design note: suite, iteration spread and #752 results for the graph r…
Design note: the callbacks' share of the notch assembly, per route (#823
23 remaining items
lmoresi commentedon Oct 10, 2026
Reopened under the issue rule of 2026-10-11 (PR #839): an issue whose fix has merged to
developmentstays open, labelledfixed-in-development, and closes when the fix is released tomain. Fixed by #830 (f4c19cf, tier 1) and #836 (45fc612, tier 2).Merge development (#823 tier 2, #835) into picard-warmup-791
Merge origin/bugfix/picard-warmup-791 (tier 2 graph codegen, #841 guard)
Memoised complete unwrap, identity-walk symbol scans, memoised sqrt g…
Declare realness of field values, coordinates and constant slots (und…
Parameters given with units are known real (underworldcode#823)
plasticity-solvers guide: differentiate with respect to fields as the…
Second review of underworldcode#823: one DiracDelta rule, public fiel…
Power-mean sharpness held as its own constant atom (underworldcode#823)
JIT lowering: shared-graph constants substitution; printer's re() pas…
Review record for underworldcode#823: three adversarial rounds, findi…
Merge development (underworldcode#823 tier 1, underworldcode#829) int…
JIT: always compile kernels with -fno-math-errno (underworldcode#834)