( rule: CompiledFungrimRule )
| 94 | if (Array.isArray(x)) return x.map((y) => substituteSymbol(y, from, to)); |
| 95 | return x; |
| 96 | } |
| 97 | |
| 98 | // --------------------------------------------------------------------------- |
| 99 | // Derivation |
| 100 | // --------------------------------------------------------------------------- |
| 101 | |
| 102 | export type SolveTemplate = { |
| 103 | /** Raw `['Add', ['Multiply', '__a', A(_x)], '__b']`. */ |
| 104 | match: MathJSON; |
| 105 | /** Raw `f(Negate(Divide(__b, __a)))`. */ |
| 106 | replace: MathJSON; |
| 107 | /** The inner `A(_x)` (in the solve `_x` convention) — used by the self-test. */ |
| 108 | innerA: MathJSON; |
| 109 | }; |
| 110 | |
| 111 | /** Derive a root template from a compiled inverse-composition simplify rule |
| 112 | * (`f(A(_w)) → _w`). Returns `{error}` when the rule is not of that shape. */ |
| 113 | export function deriveSolveTemplate( |
| 114 | rule: CompiledFungrimRule |
| 115 | ): SolveTemplate | { error: string } { |
| 116 | const m = rule.match; |
| 117 | const rep = rule.replace; |
| 118 | if (typeof rep !== 'string' || !rep.startsWith('_')) |
| 119 | return { error: 'replace is not a bare wildcard' }; |
| 120 | if (!Array.isArray(m) || m.length < 2) |
| 121 | return { error: 'match is not a function expression' }; |
| 122 | const unknown = rep; |
| 123 | // The topmost node `[head, arg1, …]` must contain the unknown in exactly |
| 124 | // one argument slot (the inner expression `A`). |
| 125 | const slots: number[] = []; |
| 126 | for (let i = 1; i < m.length; i++) |
| 127 | if (collectWildcards(m[i]).has(unknown)) slots.push(i); |
| 128 | if (slots.length !== 1) |
| 129 | return { error: `unknown appears in ${slots.length} argument slots` }; |
| 130 | const slot = slots[0]; |
| 131 | const A = m[slot]; |
| 132 | if (A === unknown) |
| 133 | return { error: 'inner argument is the bare unknown (degenerate f(x)=x)' }; |
| 134 | // `A` must reference no wildcard other than the unknown (no free parameter). |
no test coverage detected