Skip to content

Releases: asc-community/AngouriMath

2.4.0

Choose a tag to compare

@Rafael-SOWNet Rafael-SOWNet released this 28 Aug 12:31
de7189b

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. 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
, 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. Twenty-seven entries, and
more than half are marked Silent — the call still succeeds and quietly returns something else.

AssemblyVersion stays 2.0.0.0. The recorded public surface shows 68 additions and 130
removals, and none of the removals is one a caller can hit: Stringize() and Latexize()
stopped being abstract on Entity and each node's override became a private helper, so the
member is still public on Entity and inherited by every node. Source- and binary-compatible.

Wrong answers fixed

  • A factorisation that was not equal to what it factored. Factor("4x² − 4y²", "x") returned
    (x + y)(x − y) — the 4 simply gone, the difference from the input −3x² + 3y². Every
    candidate in the polynomial layer is checked by exact division, but that check is on the
    individual factors; nothing compared the assembled product against the input, so a constant
    lost during assembly was lost silently. (#1092)
  • (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. Only reachable with both
    operands symbolic: with a number on one side, 2 < x is rewritten to x > 2 earlier in the same
    pass and one of the four correct rules matches. A test written with a numeric operand would
    have passed on the defect. (#1077)
  • x! = 0 was answered False everywhere, including at the negative integers where the
    factorial has a pole and the statement is NaN. The rule read a property pattern on the
    factorial's argument rather than on the factorial. It took x! / x!1 with it, and three
    recorded test verdicts had been recording that. (#1081)
  • ln(1/b) = −ln(b) was applied unconditionally, which is false on the negative reals — at
    b = −0.63 the two differ by the full turn of the argument the principal branch discards.
    Three rules gained the guard their neighbours ten lines below already had. (#1062)

Factorisation

Factorize was built entirely out of rewrite rules, so it factored what someone had written a
rule for and handed everything else back whole — while square-free decomposition, Zassenhaus over
ℚ and the multivariate GCD sat in the tree unused by it.

"x3 - 1".Factorize()          x ^ 3 - 1              →  (x - 1) * (x ^ 2 + x + 1)
"x4 - 5x2 + 4".Factorize()    unchanged              →  (x + 1) * (x + 2) * (x - 2) * (x - 1)
"x2 + 2x + 1".Factorize()     unchanged              →  (x + 1) ^ 2

The layer speaks only where the rules said nothing, so every answer they already gave is
unchanged — the order two factors come out in is arbitrary and theirs is the one on record. (#1018)

And the layer itself reaches further. Hensel lifting along an evaluation homomorphism (#1088,
#1089) factors bivariate polynomials that Kronecker's substitution refuses — not because its image
is too large but because it over-factors: x⁷ − y⁷ maps to t⁷(1 − t⁴⁹), whose factors are
cyclotomic. An evaluation image inflates nothing.

Factor("x12 - y12", "x")      null                   →  six factors, the full cyclotomic split
Factor("x7 - y7",   "x")      null                   →  (x - y)(x⁶ + x⁵y + ⋯ + y⁶)

Where the substitution gives up entirely, an evaluation image can still prove a polynomial
irreducible — which since #1059 is an answer rather than a refusal, so
Factor("x2 + y2 + z2 + w2 + 1", "x") returns the polynomial instead of null. (#1087)

The rule sets are data

Thirty of thirty rule sets now have a form in which each rule is a value — a pattern, a
replacement, a soundness tier and a direction — proven to agree with the switch it replaces over
thousands of generated expressions. Twenty-seven run it. The three that do not are the canonical
orders, and that is a measurement rather than an omission.

It buys: every rule individually addressable (407 entries), per-rule soundness where only the set
had a tier before (181 Sound, 141 SoundUnderAssumptions), and 26 rules that can be read
backwards.

Performance, honestly

SimplifyEasy is about 13% slower than before the exchange — 82,676 ns to 93,732 ns on one
desktop, both arms, standard deviation under half a per cent. Every conversion was measured
against the commit in front of it and every one came back free or better; nothing was measured
against the start, and the sum of a run of free steps is +13%.

It would have been worse. Indexing each set's rules by node type recovered most of it, and a
bounded pattern is now walked by index rather than enumerated — 165.05 MB to 163.40 MB of
SolveMediumHard on its own.

The work shape is unchanged: 4,914 rule-set invocations on that input at both ends, so this is
per-operation overhead rather than extra work. version_performance_control.md records where it
goes, what three attempts to remove it measured, and the roughly 40% still unattributed.

That file also gained a measurement worth more than the column: the Kernel Benchmark run twice
on one commit is 30–57% apart on every benchmark
, while allocation over the same pair agrees to
0.03%. Timing comparisons between its columns are evidence only above about 50%.

2.3.0

Choose a tag to compare

@Rafael-SOWNet Rafael-SOWNet released this 23 Aug 02:04
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 onceBB, 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.

2.2.0

Choose a tag to compare

@Rafael-SOWNet Rafael-SOWNet released this 14 Aug 18:02
19c8c7f

Infrastructure release. 2.1.0 was mostly wrong answers becoming right ones; this one is mostly the
layer underneath them — a real polynomial layer, and a written specification of what canonical
form means here
with both halves implemented. The corrected answers in it are largely consequences
of those two rather than separate fixes.

Every changed answer is in BREAKING-CHANGES.md under 2.2.0 — since 2.1.0,
with the old value, the new one, and why, measured on a build of each version. Read that first if you
have code depending on an answer.

AssemblyVersion stays 2.0.0.0. See the rename note at the bottom before dropping the DLL in
without recompiling.

A polynomial layer

The single item that #746 names as
unblocking a large fraction of the tracker. Multivariate GCD, resultants, square-free decomposition,
and factorisation over ℚ and finite fields. (#918, #920/#923, #921/#927)

It is not shipped for its own sake — three things in this release are consequences of having it:

  • A polynomial equation that factors is solved through its factors. x^5 + 2x^3 - 2x^2 - 4
    returned three of its five roots, one of them a float; it returns all five, exact. x^4 + x^2 + 1
    loses a nested radical. (#918)
  • A rational function is decomposed over the factors of its denominator, not only its roots, so
    1/(x^4 + 3x^2 + 2) and 1/(x^4 + 4) now integrate instead of coming back unevaluated. (#926)
  • A resultant is bounded by measured work rather than by a reasoned size limit, which raised the
    ceiling from a Sylvester matrix of 24 to one of 40 without risking the blow-up the old bound was
    guessing at. (#921/#927)

Canonical form: specified, measured, and offered

Docs/Contributing/CanonicalForm.md states the position rather than leaving it to be inferred:
canonical is about identity, simplest is about presentation, and there is no canonical form for
the whole language — zero-equivalence is undecidable once pi, exp, the trigonometric functions and
abs are in play (Richardson 1968). So the specification is a canonical form on a decidable
sublanguage, a normalisation elsewhere that must not be mistaken for one, and a search that is not
required to be canonical at all. (#928)

Both halves are now reachable from Entity, beside Simplify and Factorize:

Entity Canonicalize()                     // the commutative structure: 0 idempotence and
                                          // 0 order-independence failures over 834 expressions
Entity? CanonicalizeAsRationalFunction()  // rational functions over Q -- or null, which is the
                                          // library saying it has no answer rather than guessing

x/x canonicalises to 1 provided not x = 0 and is deliberately not equal to the canonical form of
1: the quotient is undefined where the polynomial is not. (#933, #935, #940)

Nothing applies either by default. Simplify and InnerSimplified return exactly what they
returned before. Turning canonical ordering on by default would change every commutative operand order
in every printed answer, and that is a decision for a release that says so.

Wrong answers fixed

  • sin(-x) + sin(x) was left as written and is 0 — the parity identities were not being applied.
    cos(-x) and abs(-x) fold too. (#929/#931)
  • InnerSimplified is idempotent again. An exact trigonometric value reached through a half turn
    came back as -(-1) where it should have been 1. The value was never wrong, but applying
    InnerSimplified twice gave a different tree from applying it once, and much of the library treats
    what it returns as settled. (#930/#932)
  • A negative pair keeps its sign. (#936/#937)
  • The logarithm's domain follows the reading, as every other node's already did, so log(-3, -3)
    is no longer declared undefined while evaluating to 1. (#721/#890, #916)
  • log(x, x) was 1 provided x > 0NaN at every negative x, and 1 at x = 1 where the
    logarithm is NaN. (#916)
  • d/dx x^n carried provided x > 0, a condition it never needed, making the derivative undefined
    at every negative x. (#916)
  • A sum of logarithms is no longer gathered unless that is exactln(a) + ln(b) -> ln(a*b) is
    wrong by 2*pi*i off the positive reals. Two limits lost to that guard in 2.1.0 are back, via an
    ambient scope rather than a new pass. (#922, #925)

Under the hood

  • A rewrite rule's left-hand side can be data. MatchPattern matches by enumerating solutions, so
    commutative operands backtrack properly, and three rule sets are expressed as data and proved
    equivalent to the switch they mirror. Internal for now — it is a prerequisite for
    #746's rewrite graph, and for a rule being
    able to carry its own justification. (#248, #938)
  • A measured performance pair is published in Docs/WhatsNew/version_performance_control.md, both
    columns re-measured on one machine. It caught four solver benchmarks 7–21% slower with allocation up
    10–20%, isolated to the polynomial layer by bisecting on allocation. That is the price of the
    factoring solver, recorded rather than quietly absorbed
    — and the same document notes that none of
    the ten solver benchmarks factors, so the suite measures that change's cost and none of its benefit.

One rename

Five members were spelled -ise on a surface that is otherwise Factorize, Latexize,
Normalization. Three had not shipped; two had:

Was (2.1.0) Is
Transformation.Rationalisation Transformation.Rationalization
RewriteRules.RationaliseDenominator RewriteRules.RationalizeDenominator

Recompiling turns a stale reference into a compile error. Swapping the DLL without recompiling does
not
AssemblyVersion is pinned at 2.0.0.0 so the assembly still binds, and the call throws
MissingMethodException when it is reached. Documentation prose keeps British spelling; the convention
is about identifiers. (#940)

2.1.0

Choose a tag to compare

@Rafael-SOWNet Rafael-SOWNet released this 12 Aug 19:51
b8cf4dc

AngouriMath 2.1.0

Correctness release. Almost everything here 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, one child
process per case so a stack overflow is a result rather than the end of the run, every documented code
sample compiled and run, and the generated SymPy code executed rather than read.

Every changed answer is in BREAKING-CHANGES.md under 2.1.0 — since 2.0.0,
with the old value, the new one, and why, measured on a build of each version. Read that first if you
have code depending on an answer.

AssemblyVersion stays 2.0.0.0, so this is a drop-in replacement for 2.0.0 on a strong-named reference.

Wrong answers fixed

  • arcsin(sin(x)) and three siblings no longer cancel off the principal branch. arcsin(sin(3)) was
    3; it is pi - 3. Four rules had been wrong since 2020. (#884)
  • arctan(x) + arccotan(x) is no longer always pi/2 — this library's arccotan has range
    (-pi/2, pi/2], so the sum is -pi/2 for negative x. (#887)
  • ln(e^x) no longer simplifies to x, which is wrong wherever Im x leaves (-pi, pi]: at
    x = 3*pi*i the expression is pi*i. (#902)
  • log(1, 1) was 0 and is NaN — it is 0/0. log(1, 2) was +oo. (#890)
  • abs(sgn(x)) and sgn(abs(x)) were 1, and both are 0 at x = 0. (#892)
  • A logical connective is no longer strict in NaN. False and u is False for an operand with no
    truth value, which is what Simplify already answered while evaluation said NaN. (#880)
  • A connective over a number now declines rather than reporting the same type error three
    different ways. A number is not a truth value. (#897)
  • A conditional set's bound variable was named from a hash of the predicate, which could spell true
    and throw — an intermittent CI failure that would not reproduce. (#891)

Better answers

  • abs folds where the sign of its argument is known. abs(-sqrt(6)) is sqrt(6); a concrete
    quadratic inequality no longer answers with abs(-sqrt(6)) / 2 as an endpoint. (#881)
  • -(a - b) is turned round wherever it sits — inside a power, a function's argument or a matrix, not
    only at the root — and Expand now descends into a matrix. A solved system's entries are shorter for
    it. (#882)
  • NaN is a literal. It printed as NaN and parsed back as a variable of that name, so
    NaN - NaN was 0. (#906)
  • MathS.ToSympyCode emits Python that runs and stays exact. Any non-integer rational produced a
    SyntaxError, NaN and the infinities were unbound names, and 1/2 arrived in SymPy as the float
    0.5. (#909, #911)

Two answers withdrawn on purpose

Both are recorded in the changelog rather than quietly dropped.

  • lim x->+oo (x^2)^x / e^(2*x*ln(x)) and lim x->+oo x^x / e^(x*ln(x) - ln(x)) are unevaluated
    where they used to be answered. They need ln(a^c) = c*ln(a), which is false in general; on the way to
    +oo the base really is positive, and there is currently no way to tell the simplifier so. Unevaluated
    rather than NaN, so the caller is told nothing was settled rather than told the limit does not exist.
  • false and 0 and true or 0 were False and True by short-circuit. Whether an operand is admissible
    cannot depend on whether the operator happened to need it.

One word reserved

NaN is now a keyword, so it can no longer be a variable name — the same trade mod took in 2.0. Only
the exact spelling: NaNx and NaN_1 are still variables.

Performance

Measured, not hoped for: v2.0.0 and this release benchmarked minutes apart on one machine, published as
a pair in
Docs/WhatsNew/version_performance_control.md.
No regression — the largest real move is SolveMedium at +4.6%, the rest sits inside ±3%, and
allocation is flat with three rows byte-identical.

Known, and not fixed here

ln(x) + ln(x+1) -> ln(x*(1+x)) is still unsound off the positive reals, and log(x, x) -> 1 provided x > 0 declares itself undefined at x = -3 where it evaluates to 1. Both wait on
#721 — whether a domain is a property a node
carries or a query with the reading passed in — because guarding either one costs coverage that an
assumption travelling with the expression would not.

v2.0.0

Choose a tag to compare

@Rafael-SOWNet Rafael-SOWNet released this 11 Aug 12:45
f259425

v2.0.0-preview.2

v2.0.0-preview.2 Pre-release
Pre-release

Choose a tag to compare

@Rafael-SOWNet Rafael-SOWNet released this 09 Aug 18:19
50fc43f

The second preview of 2.0. Replaces 2.0.0-preview.1, which has a defect in Expand — see below. If you are testing against the preview, move to this one.

Please read BREAKING-CHANGES.md before upgrading. It lists every place the same input now gives a different result, with the value before and the value now, both measured on a build rather than taken from the diff.

What changed since preview.1

Expand no longer loses a term that takes no power

Expand turned RR + 1 into NaN, and with it ZZ + 1, CC + 1, QQ + 1, BB + 1 and true + 1. Simplify then returned NaN too, because it offers the expanded form as a candidate and NaN rates as the simplest thing on offer.

1.4.0 2.0.0-preview.1 2.0.0-preview.2
"RR + 1".Simplify() RR + 1 NaN RR + 1
"ZZ + 1".Simplify() ZZ + 1 NaN ZZ + 1

Collecting like terms reduces every factor to a base and an exponent and puts the term back together, and a factor that appeared once came back as base^1. Raising to the first power is an identity only where the power is defined at all — RR^1 and true^1 are NaN — so the reassembly turned an expression that had a value into one that did not. Sets that can be shifted were never affected and still are not: { 1, 2 } + 1 is { 2, 3 }.

Found by running CSharpMath's test suite against preview.1: 955 green on 1.4.0, two red on the preview. This closes one of the two; the other is the documented radical change.

#851, PR #852.

Documentation and measurement

  • integral takes bounds, not a repetition count: integral(f, x, from, to) is now written down in the syntax reference, along with why derivative takes an order and integral does not. The change itself was made in 1.4.0 and had never been recorded — BREAKING-CHANGES.md now has a section for it, since 1.4.0 is what dotnet add package still installs.
  • The samples are built and run in CI. Two of them had been broken against the current release since January, hidden by a pin to 1.3.0; a third was broken in plain sight because nothing ran it.
  • Trigonometry against precision is now benchmarked, and allocation is recorded alongside the timings.

The rest of 2.0 is unchanged from preview.1

Most of 2.0 is a wrong answer becoming a right one. That is still a breaking change if you built on the wrong one, and a large share of these changes are silent: the call still succeeds and quietly returns something else.

The loud breaks — the compiler finds these for you:

was is
target frameworks net7.0;netstandard2.0 netstandard2.0;net8.0;net10.0
28 members deprecated since 1.x obsolete but present removed
Latexise, ILatexiseable, entity_latexise the British spelling Latexize, ILatexizeable, entity_latexize
MathS.Quantum.Factorise one letter from the unrelated Entity.Factorize MathS.Quantum.TensorFactorize
MathS.Quantum.IsNormalised the British spelling IsNormalized
Minusf.Minuend / .Subtrahend named for the wrong operand named for the right one

The silent ones are what to test against — sqrt(x^2) left as written, -7 mod 3 now 2, sqrt(12) now 2*sqrt(3), numbers below 1e-16 kept, an identity equation solving to CC, many limits returning a value where they returned NaN, Stringize output parsing back. The full list with worked examples is in BREAKING-CHANGES.md.

Reporting

If something you relied on changed and it is not in BREAKING-CHANGES.md, that is a bug in the notes as much as in the code — please open an issue either way. The Expand defect above was found by running a downstream project's tests against preview.1, which is exactly what a preview is for.

Packages: AngouriMath, AngouriMath.FSharp, AngouriMath.Interactive, AngouriMath.Terminal.

v2.0.0-preview.1

v2.0.0-preview.1 Pre-release
Pre-release

Choose a tag to compare

@Rafael-SOWNet Rafael-SOWNet released this 09 Aug 14:23
59947e3

The first preview of 2.0, the release where AngouriMath changes answers it was getting wrong.

Please read BREAKING-CHANGES.md before upgrading. It lists every place the same input now gives a different result, with the value before and the value now, both measured on a build rather than taken from the diff.

Why a preview rather than 2.0.0

Most of 2.0 is a wrong answer becoming a right one. That is still a breaking change if you built on the wrong one — and a large share of these changes are silent: the call still succeeds and quietly returns something else. No compiler error, no exception, just a different value.

Those are the ones a preview exists to surface. If you depend on AngouriMath, this is the build to try before 2.0.0 is final.

The loud breaks — the compiler will find these for you

was is
target frameworks net7.0;netstandard2.0 netstandard2.0;net8.0;net10.0
28 members deprecated since 1.x obsolete but present removed
Latexise, ILatexiseable, entity_latexise the British spelling Latexize, ILatexizeable, entity_latexize
MathS.Quantum.Factorise one letter from the unrelated Entity.Factorize MathS.Quantum.TensorFactorize
MathS.Quantum.IsNormalised the British spelling IsNormalized
Minusf.Minuend / .Subtrahend named for the wrong operand named for the right one

AssemblyVersion is pinned at 2.0.0.0 for the whole of 2.x, so later 2.x releases are drop-in replacements for this one.

The silent ones — these are what to test against

A sample; the full list with worked examples is in BREAKING-CHANGES.md.

  • sqrt(x^2) and sqrt(-x) are left as written instead of being simplified to x and i*sqrt(x), which were wrong for negative x.
  • Real % follows the sign of the divisor: -7 % 3 is 2, was -1.
  • Radicals are reduced everywhere: sqrt(12) is now 2 * sqrt(3).
  • Numbers below 1e-16 are kept rather than rounded to 0.
  • An identity equation solves to all of CC, not { } or { 0 }.
  • Many limits that returned NaN or stayed unevaluated now return a value.
  • Stringize output parses back for powers, lambdas, applications, piecewises and complex numbers with a fractional imaginary part. If you parse printed output, read that section.
  • Boolean expressions are minimised where that is shorter, rather than factored.
  • Some integrals return closed forms that were not antiderivatives before — and two that were answered correctly are now unevaluated, a deliberate loss.

Reporting

If something you relied on changed and it is not in BREAKING-CHANGES.md, that is a bug in the notes as much as in the code — please open an issue either way. A silent change found now is one that does not arrive against 2.0.0 final.

Packages: AngouriMath, AngouriMath.FSharp, AngouriMath.Interactive, AngouriMath.Terminal.

v1.4.0

Choose a tag to compare

@Happypig375 Happypig375 released this 22 Jan 16:20
fbfb4db

What's Changed

New Contributors

Read more

v1.4.0-preview.7

v1.4.0-preview.7 Pre-release
Pre-release

Choose a tag to compare

@Happypig375 Happypig375 released this 16 Jan 19:22
b44972d

What's Changed

  • Parenthesize LaTeX limit target for one-sided limits, parenthesize Provided by Priority by @Happypig375 in #651
  • Do not simplify x in {1} to false, InnerEval merge with InnerSimplify, simplify 0/0 to NaN in InnerSimplify by @Happypig375 in #652
  • Display not equals in Latexise, simplify Notf(Andf) and Notf(Orf) by @Happypig375 in #653
  • Fix stack overflow for nonexistent two-sided limits by @Happypig375 in #654
  • Change AngouriMath.Experimental to AngouriMath.Terminal MyGet on README by @Happypig375 in #655
  • Place calculus operator priority between addition/subtraction and mutiplication/division in Latexise by @Happypig375 in #656

Full Changelog: v1.4.0-preview.6...v1.4.0-preview.7

v1.4.0-preview.6

v1.4.0-preview.6 Pre-release
Pre-release

Choose a tag to compare

@Happypig375 Happypig375 released this 08 Jan 19:42
2d2060a

What's Changed

  • Keep domains on simplify ("x/x" becomes "1 provided not x = 0"), fix 0/0 = 0 (now becomes undefined), fixed arcotanh and gamma definitions by @Happypig375 in #650

Full Changelog: v1.4.0-preview.5...v1.4.0-preview.6