Repository navigation
2.3.0
Correctness release, and the first one whose claim to that is measured on an outside corpus rather
than only on our own tests. Against Rubi's integration suite — 1774 problems that each carry an
antiderivative known to exist — this version answers 604 where 2.2.0-era master answered 536, and
gets 0 wrong where that answered 7. Six of those seven were 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,
with the old value, the new one and why, each measured on a build of both sides. Read that first if
you have code depending on an answer.
AssemblyVersion stays 2.0.0.0. This release removes and renames nothing — 103 additions and 0
removals against the 2.2.0 public API baseline — 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
NaNfor ordinary matrices. Gaussian elimination left the pivots as
literal divisions, so the expression was undefined wherever a pivot vanishes. Two of four ordinary
3×3 matrices came backNaN, one of them the singular example every linear-algebra course opens
with. It is Laplace expansion now, which never divides — and is faster, dramatically so on numeric
matrices. (#992) - A matrix was a member of every special set at once —
BB,ZZ,QQ,RR,CCand their
intersections — because membership was answered with a guard that is deliberately permissive about
what it has not ruled out. Asking "might this be a member" and reporting it as "is a member" are
different questions. (#995) - Differentiating over
piorebehaved as though they varied.sin(pi)differentiated by
MathS.piwas-1, which iscos(pi): the chain rule run over a symbol that cannot change. It is
0. (#993) Differentiate(x, n)returned raw chain-rule output forn >= 1, and because each pass
differentiated the unsimplified result of the last, the expression compounded —x^4three times was
a screenful where differentiating three times by hand is2 * x * 3 * 4. Same value, and only one of
them is an answer. (#1002)- A bound
piorestill carried the constant's value, so a binder could not bind them and
derivative(e^2, e)was0. A name a binder declares is a variable, whatever it is spelled. (#984) - Differentiating or integrating over something that cannot vary — a number in the variable
position — renamed it and answered the derivative of a question nobody asked. (#964)
Interoperability
ToSympyCodeemitted Python that does not run, for every set, every lambda, everypiecewise
and every non-vector matrix: unqualifiedFiniteSet,Interval,UnionandSagainst a preamble
of onlyimport sympy; a lambda with no body; a set builder that threw out of the exporter; and
Interval,PiecewiseandMatrixwriting their children as this library spells them rather than
as SymPy does. Measured by executing the generated program rather than reading it: 24 of 45 ran
before, 45 of 45 run now. (#985)
Names and reporting
- A set builder leaked its internal placeholder.
"{ k : k > 0 }".FreeVariableswas{ %1 }— a
name in no expression, not typeable, and different for a different predicate. It also brokeVars'
own promise in both directions at once: the name that occurs was missing and the one that does not
was there. (#989) Stringizeof aRationalread back as aDivf, so the round trip was not an identity. Fixed
by the parser change below rather than by anything aimed at it. (#873)- A quotient of two integer literals now parses as the
Rationalit denotes rather than as a
division.
Under the hood
The rule registry grew to cover every addressable rule set, with confluence and termination checked by
tooling rather than asserted — #746 tier 2
asks for exactly that. Core.Binding makes binder resolution happen at construction, which is what let
i, pi and e become bindable names.
Performance
The 1769th column of
version_performance_control.md,
taken on the same runner class as the 1620th and 1671st so the three are comparable. Every row faster
or flat. SolveEasy is 21.3 ms to 8.5 ms — a 2.5× speedup with a 2.3× allocation drop beside it,
which is how you tell work from machine noise.
What this release is not
It does not complete a #746 tier. It
advances tier 1 and tier 2 and finishes neither, which is why it is a minor version. The rewrite graph
that v2.0 is reserved for is still ahead.