MCPcopy Create free account
hub / github.com/cortex-js/compute-engine / expandPower

Function expandPower

src/compute-engine/boxed-expression/expand.ts:68–117  ·  view source on GitHub ↗

Use the multinomial theorem (https://en.wikipedia.org/wiki/Multinomial_theorem) to expand the expression. * The expression must be a power of a sum of terms. * The power must be a positive integer. * - expr = '(a + b)^2' * -> 'a^2 + 2ab + b^2' * - expr = '(a + b)^3' * -> 'a^3 + 3a^2b +

(base: Expression, exp: number)

Source from the content-addressed store, hash-verified

66 * -> 'a^3 + 3a^2b + 3ab^2 + b^3'
67 */
68
69function expandPower(base: Expression, exp: number): Expression | null {
70 const ce = base.engine;
71 if (exp < 0) {
72 const expr = expandPower(base, -exp);
73 return expr ? expr.inv() : null;
74 }
75 if (exp === 0) return ce.One;
76 if (exp === 1) return expand(base);
77 if (isFunction(base, 'Negate')) {
78 if (Number.isInteger(exp)) {
79 const sign = exp % 2 === 0 ? 1 : -1;
80 const result = expandPower(base.op1, exp);
81 if (result === null) return null;
82 return sign > 0 ? result : result.neg();
83 }
84 }
85
86 // Subtract is non-canonical, so we don't expect to see it here.
87 console.assert(base.operator !== 'Subtract');
88
89 // We can expand only if the expression is a power of a sum.
90 if (!isFunction(base, 'Add')) return null;
91
92 // Apply the multinomial theorem
93 // https://en.wikipedia.org/wiki/Multinomial_theorem
94 // (a + b + c)^n = sum_{k1 + k2 + ... + km = n} (n choose k1, k2, ..., km) a^k1 b^k2 ... c^km
95 // where the sum is over all non-negative integers k1, k2, ..., km such that k1 + k2 + ... + km = n
96 // and (n choose k1, k2, ..., km) = n! / (k1! k2! ... km!)
97 // For example, (a + b)^3 = (a + b)^2 (a + b) = (a^2 + 2ab + b^2) (a + b) = a^3 + 3a^2b + 3ab^2 + b^3
98 // The multinomial theorem is a generalization of the binomial theorem.
99 // For example, (a + b)^2 = a^2 + 2ab + b^2
100 // (a + b + c)^2 = (a + b + c) (a + b + c) = a^2 + b^2 + c^2 + 2ab + 2ac + 2bc
101 // (a + b + c)^3 = (a + b + c) (a + b + c) (a + b + c) = a^3 + b^3 + c^3 + 3a^2b + 3a^2c + 3b^2a + 3b^2c + 3c^2a + 3c^2b + 6abc
102
103 const terms = base.ops;
104 const it = powers(terms.length, exp);
105
106 const result: Expression[] = [];
107 const deadline = ce._deadline;
108 let count = 0;
109 for (const val of it) {
110 // A high power of a sum enumerates a multinomial with `C(exp+m-1, m-1)`
111 // terms — e.g. `(a+b+c)^350` is ~6·10⁴ — so this loop can run for many
112 // seconds. Checkpoint the engine deadline (stride-amortized) so a runaway
113 // expansion honors `ce.timeLimit` instead of stalling (e.g. the compiler's
114 // symbolic-antiderivative attempt on `(trinomial)^p`).
115 if ((++count & 0xff) === 0) checkDeadline(deadline);
116 const product = [ce.number(multinomialCoefficient(val))];
117 for (let i = 0; i < val.length; i += 1) {
118 if (val[i] !== 0) {
119 if (val[i] === 1) product.push(terms[i]);
120 else product.push(terms[i].pow(val[i]));

Callers 1

expandFunctionFunction · 0.85

Calls 12

isFunctionFunction · 0.90
mulFunction · 0.90
addFunction · 0.90
powersFunction · 0.85
multinomialCoefficientFunction · 0.85
assertMethod · 0.80
expandFunction · 0.70
invMethod · 0.65
negMethod · 0.65
numberMethod · 0.65
powMethod · 0.65
isIntegerMethod · 0.45

Tested by

no test coverage detected