From 63d09e45a7357ef113eec2f5df875018f8722f3e Mon Sep 17 00:00:00 2001 From: Rafael Vuijk Date: Wed, 16 Sep 2026 07:28:44 +0000 Subject: [PATCH 1/3] What's new: 2.2.0 to 2.5.0, and the quickstart names 2.5.0 The page stopped at 2.1.0 while four releases shipped. Each block is the release's own notes, cut to the shape the page uses: what the release is, the wrong answers it fixed, what it added, and what it measured -- with the BREAKING-CHANGES.md link pinned to the release's tag rather than to master, so the section it names stays where the link says. The quickstart's "current release" paragraph says 2.5.0, that every 2.x release changes answers, what silent and loud mean in BREAKING-CHANGES.md, and that only 2.2.0 renamed members since 2.0.0. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_012sonx8iAspMiwRwokT1Ura --- src/content/quickstart/index.html | 9 +- src/content/whatsnew/index.html | 160 +++++++++++++++++++++++++++++- 2 files changed, 165 insertions(+), 4 deletions(-) diff --git a/src/content/quickstart/index.html b/src/content/quickstart/index.html index 20319332f..4b6cbcda3 100644 --- a/src/content/quickstart/index.html +++ b/src/content/quickstart/index.html @@ -39,12 +39,15 @@

Install for F#

dotnet add package AngouriMath.FSharp

- The current release is 2.1.0, and both it and 2.0.0 change answers that earlier versions + The current release is 2.5.0, and every 2.x release changes answers that earlier versions got wrong. Whichever version you are coming from, read BREAKING-CHANGES.md first: it lists every input whose result is now different, with the old value and the new one, - under a heading per release. 2.1.0 is a drop-in replacement for 2.0.0 — the assembly version is - pinned at 2.0.0.0 for the whole of 2.x. + under a heading per release, and says whether the change is silent — the call still + succeeds and returns something else — or loud. The assembly version is pinned at + 2.0.0.0 for the whole of 2.x, so each release binds in place of the last; since + 2.0.0 only 2.2.0 renamed members, two of them, and no other release removes anything a caller + can hit. What each release did is on the What's new page.

The library targets netstandard2.0, net8.0 and net10.0. diff --git a/src/content/whatsnew/index.html b/src/content/whatsnew/index.html index 5ef8f61fe..33f23f361 100644 --- a/src/content/whatsnew/index.html +++ b/src/content/whatsnew/index.html @@ -34,7 +34,165 @@

What's new

--> -
2.1.0 +
2.5.0 +

+ Tier 2 of the Math OS roadmap — + the rewrite graph — is finished. An e-graph lives in the kernel rather than in a measurement + harness, every one of the thirty registered rule sets runs as data through a real e-matcher, and each + rule declares its own soundness tier and how much it grows what it matches. The honest result is the + part worth reading: Simplify still does not run on the graph, because the tier + asked for equality saturation to be evaluated against memory cost on real expressions and the + evaluation came back negative. A measurement that says "not by default" is the deliverable. + Every changed answer is in + BREAKING-CHANGES.md + under 2.5.0 — since 2.4.0 — seventy-six entries, twenty-nine of them silent + (the call still succeeds and quietly returns something else) and two loud, where input that + parsed now raises. The recorded public surface has 136 additions and no removals, and + AssemblyVersion stays 2.0.0.0: source- and binary-compatible with 2.4.0. +

+ Wrong answers fixed: +

    +
  • Integrate could recurse without bound and take the process down — a stack overflow is not an exception a caller can handle. Caught by running Rubi's independent suites against the release candidate; the descent is bounded now, and an integral already being worked out is recognised as a cycle, after renaming, and declined at once.
  • +
  • Matrix operations answered wrongly on more than one thread: 38 of 40 determinants computed in parallel carried another computation's values. Two of the three causes were caches grown under a lock and read outside one; the third is GenericTensor handing every caller the same scratch matrix, reported upstream and guarded here meanwhile.
  • +
  • A negation was answered with the empty set, which is a positive claim, for something never settled.
  • +
  • Domain.Any was treated as the universal set when it is a codomain.
  • +
  • A negative arccotan was not negative — this library's arccotan has range (-pi/2, pi/2], and a guard written from the textbook range shipped wrong.
  • +
  • The limit of z / abs(z) lost the phase of z, and a factor of -1 was taken out as though it were a factor rather than read as a sign.
  • +
+ The rewrite graph: +
    +
  • The e-graph is in the kernel behind an explicit opt-in, matched by a genuine e-matcher — a pattern against an e-class, not a term. A cost model is a record you pass (SmallestTree, FewestDivisions, FewestRadicals) rather than a setting you set.
  • +
  • What makes that safe is tests rather than an author's assertion: a rule's declared growth is checked against a corpus, a set that rewrites back to where it started is caught, and so is one that never settles over a whole tree. The runaway once blamed on a whole soundness tier was one inverse pair across two sets.
  • +
+ Speed — each measured at the entry point and answer-identical: +
    +
  • SolveHard allocates 98.6% less: the solver tries the equation as written before asking for its alternatives.
  • +
  • SimplifyHard −64%, −44%, −35% and −25% over four changes: a candidate registered once, a subtree costed once, a sort key spelt once, and a candidate re-simplified at the default level whatever level it was offered at.
  • +
  • Extraction from the graph is a fixed point computed from the leaves up: 1,918 ms to 4 ms on the case that exposed it.
  • +
  • The integrator is about 30% faster than 2.4.0 on the seventeen hardest integrands of Rubi's corpus, measured alone on a quiet machine — an earlier version of the release notes said the opposite, from a run with the test suite beside it, and was corrected.
  • +
+ New notation: +
    +
  • a divides b is a statement node (a \mid b in LaTeX) — divides is a keyword now, so a variable of that name no longer parses.
  • +
  • #S is the number of elements of a set, with card(S) still accepted; the extremum of an expression over a set is a binder; and a lambda is written with an arrow, x => x + 1 beside lambda(x, x + 1).
  • +
+ Closed forms: +
    +
  • sum(k, k, 1, n) is (n + n^2)/2 with its condition on n; sum(x^k, k, 0, +oo) is 1 / (1 - x) provided abs(x) < 1; sum(2^k, k, 0, +oo) is +oo by the nth-term test. Polynomial summands, monomial products, a power over a factorial, binomial sums, geometric and divergent series.
  • +
  • Integration reaches a biquadratic denominator over the reals, fractional powers and the tangent as substitutions, improper quotients divided out first, repeated quadratic denominators, and an integral across a jump split at the jumps. There is an analytical solver for first-order linear ODEs.
  • +
+ Documentation that is checked: +
    +
  • 254 worked examples in the XML documentation say what they print, and 67 were wrong. They are compiled and run against what they claim now, so a changed answer fails a test instead of leaving a wrong promise in the docs.
  • +
+

+
+ +
2.4.0 +

+ Tier 1 of the Math OS roadmap + is finished, and the thing that finished it kept finding wrong answers: writing a rewrite rule out + as data — a pattern and a replacement, rather than an arm of a switch — makes + the correspondence between the two something you have to state, and four times this cycle a rule + did not survive stating it. + Every changed answer is in + BREAKING-CHANGES.md + under 2.4.0 — since 2.3.0 — twenty-seven entries, more than half of them silent. + AssemblyVersion stays 2.0.0.0; the 130 recorded removals are + Stringize() and Latexize() ceasing to be abstract per node, + still public on Entity and inherited by every node, so nothing a caller can hit. +

+ Wrong answers fixed: +

    +
  • Factor("4x² − 4y²", "x") returned (x + y)(x − y), the 4 simply gone: every candidate factor was checked by exact division, but nothing compared the assembled product against the input.
  • +
  • (y < x) or (x = y) simplified to x <= y, its own negation off the diagonal — four of the eight or-with-equality rules carried their neighbour's comparison, reachable only with both operands symbolic.
  • +
  • x! = 0 was False everywhere, including at the negative integers where the factorial has a pole and the statement is NaN; x! / x! → 1 went with it.
  • +
  • ln(1/b) = −ln(b) was applied unconditionally, and is false on the negative reals by a full turn of the argument.
  • +
+ Factorisation: +
    +
  • Factorize was built entirely out of rewrite rules while square-free decomposition, Zassenhaus over ℚ and the multivariate GCD sat unused. Now x^3 - 1 is (x - 1) * (x^2 + x + 1), x^4 - 5x^2 + 4 is (x + 1) * (x + 2) * (x - 2) * (x - 1) and x^2 + 2x + 1 is (x + 1)^2; every answer the rules already gave is unchanged.
  • +
  • Hensel lifting along an evaluation homomorphism factors bivariate polynomials that Kronecker's substitution over-factors: x^12 - y^12 gives its full cyclotomic split, x^7 - y^7 its two factors, and a polynomial the layer can prove irreducible is returned rather than refused.
  • +
+ The rule sets are data: +
    +
  • Thirty of thirty rule sets have a form in which each rule is a value — pattern, replacement, soundness tier, direction — proven to agree with the switch it replaces over thousands of generated expressions; twenty-seven run it, and the three that do not are the canonical orders. 407 individually addressable rules, 181 Sound, 141 SoundUnderAssumptions, 26 readable backwards.
  • +
+ Performance, honestly: +
    +
  • SimplifyEasy is about 13% slower than before the exchange, 82,676 ns to 93,732 ns on one desktop: every conversion measured free against the commit in front of it, nothing measured against the start, and the sum of a run of free steps was +13%. Indexing each set's rules by node type recovered most of it. The same document records that the CI kernel benchmark run twice on one commit is 30–57% apart on every row, while allocation agrees to 0.03% — so its timing columns are evidence only above about 50%.
  • +
+

+
+ +
2.3.0 +

+ A correctness release, and the first whose claim to that is measured on an outside corpus: + against Rubi's integration suite — 1774 problems that each carry an antiderivative known to + exist — it answers 604 where 2.2.0-era master answered 536, and gets 0 wrong where that answered 7, + six of the seven being NaN, a definite claim that no value exists made about integrals + that have one. + Every changed answer is in + BREAKING-CHANGES.md + under 2.3.0 — since 2.2.0. This release removes and renames nothing — 103 additions + and 0 removals against the 2.2.0 public API — so it is a drop-in replacement in both the binding and + the source sense, which 2.2.0 was not. +

+ Wrong answers fixed: +

    +
  • The symbolic determinant was NaN for ordinary matrices: Gaussian elimination left the pivots as literal divisions, undefined wherever a pivot vanishes. It is Laplace expansion now, which never divides, and is faster.
  • +
  • A matrix was a member of every special set at once — BB, ZZ, QQ, RR, CC — because "might this be a member" was reported as "is a member".
  • +
  • Differentiating over pi or e behaved as though they varied: sin(pi) by MathS.pi was -1, and is 0. And a bound pi or e still carried the constant's value, so derivative(e^2, e) was 0 — a name a binder declares is a variable.
  • +
  • Differentiate(x, n) returned raw, compounding chain-rule output for n >= 1; differentiating or integrating over a number renamed it and answered a question nobody asked.
  • +
+ Interoperability and names: +
    +
  • ToSympyCode emitted Python that does not run for every set, lambda, piecewise and non-vector matrix. Measured by executing the generated program: 24 of 45 ran before, 45 of 45 run now.
  • +
  • A set builder leaked its internal placeholder: "{ k : k > 0 }".FreeVariables was { %1 }.
  • +
  • A quotient of two integer literals parses as the Rational it denotes, so Stringize of a Rational round-trips.
  • +
+ Performance: +
    +
  • Every row faster or flat against 2.2.0 on the same runner class; SolveEasy is 21.3 ms to 8.5 ms with a 2.3× allocation drop beside it, which is how you tell work from machine noise.
  • +
+

+
+ +
2.2.0 +

+ An infrastructure release: a real polynomial layer, and a written specification of what + canonical form means here with both halves implemented. The corrected answers in it are mostly + consequences of those two. + Every changed answer is in + BREAKING-CHANGES.md + under 2.2.0 — since 2.1.0. AssemblyVersion stays 2.0.0.0; + see the rename at the bottom before dropping the DLL in without recompiling. +

+ A polynomial layer: +

    +
  • Multivariate GCD, resultants, square-free decomposition, and factorisation over ℚ and finite fields — the single item #746 names as unblocking a large fraction of the tracker.
  • +
  • A polynomial equation that factors is solved through its factors: x^5 + 2x^3 - 2x^2 - 4 returned three of its five roots, one a float, and returns all five, exact.
  • +
  • A rational function is decomposed over the factors of its denominator, so 1/(x^4 + 3x^2 + 2) and 1/(x^4 + 4) integrate instead of coming back unevaluated.
  • +
+ Canonical form, specified and offered: +
    +
  • Docs/Contributing/CanonicalForm.md states the position: canonical is about identity, simplest is about presentation, and there is no canonical form for the whole language, since zero-equivalence is undecidable once pi, exp, the trigonometric functions and abs are in play.
  • +
  • Entity.Canonicalize() (the commutative structure: 0 idempotence and 0 order-independence failures over 834 expressions) and Entity.CanonicalizeAsRationalFunction() (rational functions over ℚ, or null — the library saying it has no answer rather than guessing). Nothing applies by default: Simplify returns exactly what it returned before.
  • +
+ Wrong answers fixed: +
    +
  • sin(-x) + sin(x) was left as written and is 0; cos(-x) and abs(-x) fold too.
  • +
  • InnerSimplified is idempotent again: an exact trigonometric value reached through a half turn came back as -(-1).
  • +
  • log(x, x) was 1 provided x > 0, NaN at every negative x; d/dx x^n carried a provided x > 0 it never needed; a sum of logarithms is gathered only where that is exact, and the two limits lost to that guard in 2.1.0 are back.
  • +
+ One rename: +
    +
  • Transformation.Rationalisation is Rationalization and RewriteRules.RationaliseDenominator is RationalizeDenominator, on a surface that is otherwise Factorize, Latexize. Recompiling turns a stale reference into a compile error; swapping the DLL without recompiling throws MissingMethodException when the call is reached.
  • +
+

+
+ +
2.1.0

A correctness release. Almost everything below is a wrong answer becoming a right one, and most of it was found by harnesses rather than reported — boundary points where a rule's assumption fails, From 4556aa24c983abe23d3968861b58a7ad92a4e66b Mon Sep 17 00:00:00 2001 From: Rafael Vuijk Date: Wed, 16 Sep 2026 11:07:32 +0000 Subject: [PATCH 2/3] The landing page no longer says the library is deprecated The line dated from 2024. The README dropped it, six releases have shipped since, and the maintainer said on asc-community/AngouriMath#1019 to follow that decision through here. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_012sonx8iAspMiwRwokT1Ura --- src/content/index.html | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/content/index.html b/src/content/index.html index ab810744f..f9cad5b45 100644 --- a/src/content/index.html +++ b/src/content/index.html @@ -1,8 +1,4 @@  -

- NOTE: AngouriMath is deprecated; read more -

-

What is AngouriMath?


From dd47e36a1d42114eaa6f0c7490e19371082872d6 Mon Sep 17 00:00:00 2001 From: Rafael Vuijk Date: Fri, 2 Oct 2026 19:19:06 +0000 Subject: [PATCH 3/3] The footer's years run to 2026 Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_012sonx8iAspMiwRwokT1Ura --- src/content/_templates/bottom.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/_templates/bottom.html b/src/content/_templates/bottom.html index 9551cd5a5..2f44f9448 100644 --- a/src/content/_templates/bottom.html +++ b/src/content/_templates/bottom.html @@ -6,7 +6,7 @@











-Angouri © 2019-2023 · +Angouri © 2019-2026 · Project's repo · Site's repo · Octicons ·