Skip to content

The branches a simplification went down and came back from (#273) - #1139

Merged
Rafael-SOWNet merged 2 commits into
masterfrom
the-branches-the-search-came-back-from
Sep 1, 2026
Merged

Rafael-SOWNet merged 2 commits into
masterfrom
the-branches-the-search-came-back-from

Conversation

@Rafael-SOWNet

Copy link
Copy Markdown
Member

Closes #273.

The issue asks for two things:

  1. record steps while solving something — already here, as RewriteRecording and DerivationPath
  2. reverse to the branch's root whenever we fail to solve something within a method — this

No new recording was needed

PathFrom searches the recorded edges for a chain from the input to the result and throws the rest away. The rest is exactly the branches, and each already carries the expression it left from — the branch's root, in the issue's words. DerivationPath.Abandoned hands them over beside the Steps it kept.

What it shows

Simplifying (x + 1)^2 keeps one step and abandons seven:

kept       CanonicalOrder     (x + 1) ^ 2        ->  (1 + x) ^ 2
abandoned  AsPolynomial       (x + 1) ^ 2        ->  x ^ 2 + 2 * x + 1
abandoned  Expand             (1 + x) ^ 2        ->  x ^ 2 + 2 * x + 1
abandoned  CanonicalOrder     x ^ 2 + 2 * x + 1  ->  1 + x ^ 2 + 2 * x
abandoned  Common             (1 + x) ^ 2        ->  (x + 1) ^ 2

The search expands the square and comes back, because the unexpanded form rates better. A Steps list on its own reads as though the library had walked straight to the answer.

Deduplicated, and that is not tidying

The simplifier runs the same passes over the same expressions at every level of its candidate search, so the raw edges are mostly one rewrite recorded over and over:

raw distinct
x^(-1)/(y/z) 425 13
(x + 1)^2 177 7
sin(x)^2 + cos(x)^2 2 0

That last row is the one that mattered. Both raw entries were duplicates of the kept steps, so the branch list read as though the search had rejected the very steps it went on to keep. A list of 425 is a record of how often the search was asked, not of where it went — so entries are deduplicated against each other and against the kept chain, and a test asserts both.

Not an error list

A step here is a road not taken, usually to a perfectly correct expression that simply rated worse than the one kept. The documentation says so rather than leaving a reader to infer that Abandoned means "went wrong".

Tests

Seven, and the interesting ones are the negative shapes: no kept step also appears as abandoned, no branch is reported twice, every branch leaves from an expression the search had actually reached, and expressions that were their own answer abandon nothing rather than "unknown".

One member added to the public surface, PublicApi.txt regenerated. Nothing removed:

+AngouriMath.Core.Transformations.DerivationPath.Abandoned { } : IReadOnlyList<DerivationStep>

Failed: 0, Passed: 9228 on net10.0.

🤖 Generated with Claude Code

https://claude.ai/code/session_012sonx8iAspMiwRwokT1Ura

#273 asks for two things: recording the steps taken while solving, and being able to see the return
to a branch's root where a method fails. The first was already here -- `RewriteRecording` and
`DerivationPath`. This is the second, and it turned out to need no new recording at all.

`PathFrom` searches the recorded edges for a chain from the input to the result and throws the rest
away. The rest is exactly the branches: each carries the expression it left from, which is the root
the search returned to. `DerivationPath.Abandoned` hands them over beside the `Steps` it kept.

What that shows, on the smallest case that has any: simplifying `(x + 1)^2` keeps one step and
abandons seven, among them `AsPolynomial` and `Expand` both reaching `x^2 + 2x + 1` -- the search
expanding the square and coming back, because the unexpanded form rates better. A `Steps` list on
its own reads as though the library had walked straight to the answer.

**Deduplicated, and that is not tidying.** The simplifier runs the same passes over the same
expressions at every level of its candidate search, so the raw edges are mostly one rewrite recorded
over and over: `x^(-1)/(y/z)` produces 425 of them across 13 distinct steps. Worse, the raw list
included edges the kept chain had also taken, so the branches read as though the search had rejected
the very step it went on to keep -- `sin(x)^2 + cos(x)^2` reported two abandoned branches, both
duplicates of its two kept steps, and now reports none. A list of 425 is a record of how often the
search was asked rather than of where it went.

Neither list is an error list. A step here is a road not taken, usually to a perfectly correct
expression that rated worse than the one kept, and the documentation says so rather than leaving a
reader to assume otherwise.

One member added to the public surface, `PublicApi.txt` regenerated: nothing removed.

Part of #273.
…arch-came-back-from

# Conflicts:
#	BREAKING-CHANGES.md
@Rafael-SOWNet
Rafael-SOWNet merged commit e0f4d7a into master Sep 1, 2026
33 of 34 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Step recorder with reversible trees

1 participant