* Explanation of `solve()` for a univariate equation: the same * `findUnivariateRoots` + assumptions-filter pipeline the plain `solve()` * runs, with the trace accumulator attached. Step values are *equations* — * the state of the equation after each phase — ending with the candidate * roots, re
(expr: Expression, options?: ExplainOptions)
| 82 | |
| 83 | return explanationFromRuleSteps('simplify', raw, verbosity ?? 'default'); |
| 84 | } |
| 85 | |
| 86 | /** |
| 87 | * Explanation of `solve()`. Dispatches — mirroring the plain `solve()` |
| 88 | * (boxed-function.ts) — on the receiver: |
| 89 | * |
| 90 | * - a `List`/`And` of `Equal` equations → a traced system solve, |
| 91 | * - an `Or` of univariate alternatives → per-case sub-chains merged, |
| 92 | * - otherwise a univariate equation. |
| 93 | * |
| 94 | * Every path threads the trace accumulator through the same helpers the |
| 95 | * plain `solve()` runs (pure observation), so the result is identical to |
| 96 | * what `solve()` returns. |
| 97 | */ |
| 98 | function explainSolve(expr: Expression, options?: ExplainOptions): Explanation { |
| 99 | const ce = expr.engine; |
| 100 | const canonical = expr.canonical; |
| 101 | const operator = canonical.operator; |
| 102 | const verbosity = options?.verbosity ?? 'default'; |
| 103 | |
| 104 | const varNames = normalizedUnknownsForSolve( |
| 105 | options?.variable ?? canonical.unknowns |
| 106 | ); |
| 107 | if (varNames.length < 1) |
| 108 | throw new Error( |
| 109 | 'explain("solve") requires at least one unknown: specify it with options.variable' |
| 110 | ); |
| 111 | |
| 112 | // Systems of equations. Mirror the plain `solve()` dispatch: try the system |
| 113 | // path, then fall through to univariate when it declines (`solveSystem` |
| 114 | // returns null) and there is exactly one unknown. |
| 115 | if (operator === 'List' || operator === 'And') { |
| 116 | const systemEx = explainSolveSystem(ce, canonical, varNames, verbosity); |
| 117 | if (systemEx !== null) return systemEx; |
| 118 | } |
| 119 | |
| 120 | // Alternatives: solve each operand's univariate pipeline, merge the roots. |
| 121 | if (operator === 'Or') |
| 122 | return explainSolveOr(ce, canonical, varNames, verbosity); |
| 123 | |
| 124 | if (varNames.length !== 1) |
| 125 | throw new Error( |
| 126 | 'explain("solve") requires exactly one unknown: specify it with options.variable' |
| 127 | ); |
| 128 | |
| 129 | return explainSolveUnivariate(ce, canonical, varNames[0], verbosity); |
| 130 | } |
| 131 | |
| 132 | /** |
| 133 | * Univariate solve: the same `findUnivariateRoots` + assumptions-filter |
| 134 | * pipeline the plain `solve()` runs, with the trace accumulator attached. |
| 135 | * Step values are *equations* — the state of the equation after each phase — |
| 136 | * ending with the candidate roots, rejected candidates (if any), and the |
| 137 | * solution set. |
| 138 | */ |
| 139 | function explainSolveUnivariate( |
| 140 | ce: ComputeEngine, |
| 141 | canonical: Expression, |
no test coverage detected