Recursively collect raw factors without merging
( expr: Expression, variable: string, result: FactorInfo[] )
| 802 | |
| 803 | if (isFunction(expr, 'Negate')) return factor(expr.op1).neg(); |
| 804 | |
| 805 | if (isFunction(expr, 'Add')) { |
| 806 | const ce = expr.engine; |
| 807 | let common: NumericValue | undefined = undefined; |
| 808 | |
| 809 | // Calculate the GCD of all coefficients |
| 810 | const terms: { coeff: NumericValue; term: Expression }[] = []; |
| 811 | for (const op of expr.ops) { |
| 812 | const [coeff, term] = op.toNumericValue(); |
| 813 | // GCD-based content extraction is only defined for real (rational) |
| 814 | // coefficients. A complex coefficient — e.g. the `i` in `1 + i` — has no |
| 815 | // meaningful gcd: `gcd` returns NaN, which would poison `common` and make |
| 816 | // factor() return NaN (destroying a Gaussian integer at boxing time). |
| 817 | // Leave such sums unfactored. |
| 818 | if (coeff.im !== 0) return expr; |
| 819 | common = common ? common.gcd(coeff) : coeff; |
| 820 | if (!coeff.isZero) terms.push({ coeff, term }); |
| 821 | } |
| 822 | |
| 823 | // Every coefficient was zero (possible with non-canonical input, |
| 824 | // e.g. synthetic `0·u + 0·v` sums): the sum is zero, and add() below |
| 825 | // cannot be called with no terms. |
| 826 | if (terms.length === 0) return ce.Zero; |
| 827 | |
| 828 | if (!common || common.isOne) return expr; |
| 829 | |
| 830 | const newTerms = terms.map(({ coeff, term }) => |
| 831 | mul(term, ce.expr(coeff.div(common))) |
| 832 | ); |
| 833 | |
| 834 | // Build the factored product WITHOUT the expanding `mul()` helper: |
| 835 | // `mul(k, sum)` distributes `k` back over the sum (expandProduct), |
| 836 | // re-expanding `2(x+2)` into `2x+4` and undoing the factoring. A |
| 837 | // canonical Multiply node preserves the factored form. |
| 838 | return ce.function('Multiply', [ce.number(common), add(...newTerms)]); |
| 839 | } |
| 840 | |
| 841 | return Product.from(together(expr)).asExpression(); |
| 842 | } |
no test coverage detected