Skip to content

Changes needed for doenet integration - #84

Open
siefkenj wants to merge 57 commits into
Doenet:mainfrom
siefkenj:doenet
Open

Changes needed for doenet integration#84
siefkenj wants to merge 57 commits into
Doenet:mainfrom
siefkenj:doenet

Conversation

@siefkenj

Copy link
Copy Markdown
Contributor

This PR makes changes the AI said were needed for integration of the new version of math-expressions into Doenet

siefkenj and others added 27 commits August 8, 2026 13:43
Update 21 expected values to match current ast-to-latex output: fewer
exponent braces (d^{2} -> d^2), parenthesized unary +/- (a++b -> a+(+b)),
and angle notation (\angleABC -> \angle(A,B,C)).

Co-Authored-By: Claude <noreply@anthropic.com>
Three phases, taking spec/slow_assumptions from 565 to 5 failures:

1. Predicates in element_of_sets defaulted to an empty Assumptions handle,
   so every no-argument query (is_real(me.fromText("x+y"))) ignored the
   global store and answered unknown. Default to the context's live handle.
2. Rust engine: negated assumptions, constant folding before structural
   inference, sign normalization, zero-factor/complex-closure rules, and
   function domain facts. infer.rs split into infer/ per file-size convention.
3. Rebuild get_assumptions to return an oriented AST with transitive closure,
   interval-membership and subset/superset expansion.

Co-Authored-By: Claude <noreply@anthropic.com>
Current state and remaining buckets after the assumptions, polynomial,
and latex-expectation work: 1166 -> 380 failing.

Co-Authored-By: Claude <noreply@anthropic.com>
variables.ts, default_order.ts, linear.ts and logical.ts each decided a
mathematical result in JS that the core already computed: the variable walk,
the legacy sort key, linear isolation, and the not-pushdown. All four are now
marshalling shims over new bindings (-341 lines of JS).

Two gaps surfaced while wiring them up:

ops::query::operators reported only a fixed operator whitelist, not every
array head as the JS did. expression_to_polynomial whitelists operators, so an
unreported `tuple` made (3,4) parse as a polynomial. Now a faithful port.

grade::linear_decomposition has to reject exact fractions, matching the JS
`typeof tree === "number"` test. The rejection is load-bearing: when the
decomposition fails, get_assumptions_for_expr falls back to per-variable facts,
and that fallback is where transitive consequences come from.

Co-Authored-By: Claude <noreply@anthropic.com>
Relation expansion, the operator-composition table, the transitive closure,
per-variable filing and canonical form all lived in JS. None had a Rust
counterpart, so these are genuine ports rather than exposure:
assumptions/{expand,clean,derive/*,tree_store/*}.

Assumptions now carries a TreeStore beside its inference store; the wasm class
gains AST-JSON entry points so the query shape — a name, [["a","b"]], or an
expression — is decided in Rust rather than sniffed in JS. store.ts keeps only
handle marshalling, the glue exception the plan names.

-806 lines of JS. Suite unchanged at 379 failing, zero name-level movement in
either direction; slow_assumptions stays 839/5.

Three details that had to be preserved rather than tidied:

byvar is insertion-ordered, not a map — the closure iterates it to build a
conjunction and the key order reaches that tree before default_order sorts it.

A variable met with no facts differs from one never seen: only the latter picks
up the generic assumption. Modelled as Facts::{Absent, Empty, Tree}.

The closure reads the previous derived map while recomputing it, and
clean_assumptions can return a childless ["and"]. Both are observable through
me.assumptions.derived.

Co-Authored-By: Claude <noreply@anthropic.com>
The last of the JS math: 2141 lines of commutative algebra — multivariate
division, Buchberger, lcm by ideal intersection, gcd, rational reduction, and a
duplicate of every algorithm for a second encoding — replaced by a 136-line
marshalling shim over polynomials::compat.

The engine is new rather than a reuse of multivariate.rs because coefficients
here are not rationals: expression_to_polynomial counts pi, e and i as numbers,
so 9x^(2/3) - pi*x has the coefficient ["-", "pi"]. Variables are Expr trees
compared structurally, which is why sin(x) is already one variable and
stringify_vars/destringify_vars disappeared instead of moving.

ratform::cancel could not back reduce_rational_expression: on (t^100-t)/t it
returns t^(-1)(t^100 - t) rather than cancelling, it hands back a product with a
reciprocal instead of a numerator/denominator pair, and being dense over Q it
cannot represent the t^1000000 rows at all.

slow_polynomial stays 205/205 with no spec expectation touched, and runs in
0.16s instead of dominating the suite. Three JS warts were not reproduced, none
reachable from the spec: multiplying zero by a polynomial read p[1] off a
number, negating a zero polynomial returned false, and mono_gcd on two variables
the default order cannot separate looped forever.

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
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.

1 participant