Stop Expand losing a term that takes no power - #852
Merged
Conversation
Expand turned RR + 1 into NaN, and with it ZZ + 1, CC + 1, QQ + 1, BB + 1
and true + 1. A 2.0 regression: 1.4.0 leaves all of them alone.
CollectLikeTerms, which is what makes expansion finish, reduces every factor
to a base and an exponent and then puts the term back together. A factor that
appeared once came back as base^1 -- and raising to the first power is an
identity only where the power is defined at all. RR^1, ZZ^1 and true^1 are
NaN, so the reassembly turned an expression that had a value into one that
did not. A factor that appeared once now goes back as itself.
Sets that can be shifted are unaffected and still are: { 1, 2 } + 1 is
{ 2, 3 } and [0; 1] + 1 is [1; 2]. They survived before because a finite set
and an interval both do take a power.
A second guard covers the same fault at any exponent above the first, where
the identity does not apply and the factor cannot be written back at all:
collecting is an improvement rather than a requirement, so a collection that
introduced NaN is discarded and the expanded form kept.
Found by running CSharpMath's suite against 2.0.0-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 and is theirs to absorb.
Closes #851.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This was referenced Aug 9, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #851.
The bug
ExpandturnedRR + 1intoNaN— and with itZZ + 1,CC + 1,QQ + 1,BB + 1andtrue + 1. BecauseSimplifyoffersres.Expand()as a candidate andNaNrates as the simplest thing on offer,SimplifyreturnedNaNtoo.A 2.0 regression, measured against the published packages:
"RR + 1".Simplify()RR + 1NaN"ZZ + 1".Simplify()ZZ + 1NaNExpandis public, so this is not only aSimplifyartefact —"RR + 1".Expand()returnedNaNdirectly.The cause
CollectLikeTermsis what makes expansion finish: it reduces every factor to a base and an exponent, adds up the terms whose monomials agree, and puts them back together. The reassembly wrote a factor that appeared once asbase^1.Raising to the first power is an identity only where the power is defined at all. It is not, for these:
So the decomposition was lossless for everything that takes a power and destroyed everything that does not. That also explains why the sets that can be shifted were never affected: a finite set and an interval both take a power, so they round-tripped.
The fix
A factor that appeared once goes back as itself rather than as
base^1.A second guard covers the same fault above the first power, where the identity does not apply and the factor cannot be written back at all (
RR * RR): collecting is an improvement rather than a requirement, so a collection that introducedNaNis discarded and the expanded form kept. That one is deliberately written against the symptom rather than a list of node types, so a node added later cannot reintroduce it.Measured
Fixed, and the shiftable sets still shift:
Suite: 6061 passed, 0 failed, 14 skipped (11 new cases).
Verified downstream, which is where it came from
Found by running CSharpMath's suite against
2.0.0-preview.1— the consumer #822 is about. It is 955 green on 1.4.0 and two red on the preview. Rebuilt against this branch:The one that remains is
1+\sqrt{2x}expanding to1+\sqrt{2}\sqrt{x}— the documented 2.0 radical change, sound and theirs to absorb, not a defect here.Noted, not fixed here
(x+1)^2 * (x+1)^2expands to... + 2*x^2 + 4*x^2 + ...with those two left uncollected, which is whatCollectLikeTermsexists to prevent. Pre-existing — reproduced on master without this change, so it is not a regression from it and wants its own issue rather than being folded in.🤖 Generated with Claude Code