Skip to content

Simplify a product of numbers that cancels to one - #89

Merged
dqnykamp merged 1 commit into
Doenet:2.xfrom
dqnykamp:fix-empty-product-in-simplify
Aug 20, 2026
Merged

Simplify a product of numbers that cancels to one#89
dqnykamp merged 1 commit into
Doenet:2.xfrom
dqnykamp:fix-empty-product-in-simplify

Conversation

@dqnykamp

Copy link
Copy Markdown
Member

Simplifying a numeric matrix subtraction such as

me.fromAst(["+", A, B, ["-", C]]).simplify();

either produced a wrong entry or threw TypeError: Cannot read properties of undefined (reading '0'), depending on the numbers involved.

Cause

simplify_integers_in_roots merges the factors of a product, collecting numeric factors into numberFactor and everything else into otherFactors. It then omits numberFactor from the result when it equals one:

if (numberFactor !== 1) {
  otherFactors.unshift(numberFactor);
}

return ["*", ...otherFactors];

When the product consisted entirely of numbers, otherFactors is empty, so a product whose numbers cancel to one became the empty multiplication ["*"], which evaluate_numbers_sub reduces to undefined.

Ordinary numeric products never reach that state, because simplify evaluates numbers before this pass runs. The products created by distributing a scalar over a vector, tuple, or matrix do, since perform_vector_matrix_additions_scalar_multiplications builds them afterwards. An entry whose product with the scalar is one — most commonly an entry of -1 in a matrix being subtracted — therefore vanished from the entry's sum. What the reader saw depended on how default_order sorted the broken node among the remaining addends:

  • rest of the sum negative: undefined sorted last, and the right === undefined early return in the "+" branch dropped it silently, giving a wrong entry
  • rest of the sum positive: undefined sorted first, and left[0] threw the TypeError

Both symptoms are reachable from user input in DoenetML, where <math simplify>$A + $B - $C</math> over numeric matrices is common.

Fix

Return the accumulated number when there are no other factors, so the product collapses to 1 rather than to nothing.

Also in this PR

Full suite passes: 6194 tests across 29 files.

🤖 Generated with Claude Code

When `simplify_integers_in_roots` merges the factors of a product, it
accumulates the numeric factors into `numberFactor` and omits that
factor from the result when it equals one. If the product consisted
entirely of numbers, that left an empty multiplication `["*"]`, which
later evaluates to `undefined`.

That happens whenever a scalar is distributed over a vector, tuple, or
matrix, since those products are formed after numbers are evaluated.
An entry whose product with the scalar is one, such as the -1 entry of
a matrix being subtracted, therefore disappeared from the sum. If the
rest of that entry's sum was negative, the entry silently came out
wrong; if it was positive, the missing operand sorted to the front of
the sum and simplifying threw a TypeError.

Return the number itself when there are no other factors, and bump the
version so the fix can be released.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01563D3v3KXwuRLmni12AuvU
@dqnykamp
dqnykamp merged commit a7d5ebc into Doenet:2.x Aug 20, 2026
2 checks passed
@dqnykamp
dqnykamp deleted the fix-empty-product-in-simplify branch August 20, 2026 20:01
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.

1 participant