Skip to content

2.3.0

Choose a tag to compare

@Rafael-SOWNet Rafael-SOWNet released this 23 Aug 02:04
· 893 commits to master since this release
6b93b40

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 NaN for 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 back NaN, 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, CC and 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 pi or e behaved as though they varied. sin(pi) differentiated by
    MathS.pi was -1, which is cos(pi): the chain rule run over a symbol that cannot change. It is
    0. (#993)
  • Differentiate(x, n) returned raw chain-rule output for n >= 1, and because each pass
    differentiated the unsimplified result of the last, the expression compounded — x^4 three times was
    a screenful where differentiating three times by hand is 2 * x * 3 * 4. Same value, and only one of
    them is an answer. (#1002)
  • A bound pi or e still carried the constant's value, so a binder could not bind them and
    derivative(e^2, e) was 0. 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

  • ToSympyCode emitted Python that does not run, for every set, every lambda, every piecewise
    and every non-vector matrix: unqualified FiniteSet, Interval, Union and S against a preamble
    of only import sympy; a lambda with no body; a set builder that threw out of the exporter; and
    Interval, Piecewise and Matrix writing 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 }".FreeVariables was { %1 } — a
    name in no expression, not typeable, and different for a different predicate. It also broke Vars'
    own promise in both directions at once: the name that occurs was missing and the one that does not
    was there. (#989)
  • Stringize of a Rational read back as a Divf, 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 Rational it 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.