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

Function collectSameExponent

src/compute-engine/rubi/normal-form.ts:80–127  ·  view source on GitHub ↗

Fuse factors sharing a NON-NUMERIC exponent: aˣ·bˣ → (a·b)ˣ. Sound for the * Rubi verification regime (positive-real parameters), and needed so a product * of distinct-base exponentials (`aˣ·bˣ`, `aˣ/bˣ`) presents a single base to * FunctionOfExponential. Restricted to symbolic exponents so numer

(
  ce: ComputeEngine,
  flat: Expression[]
)

Source from the content-addressed store, hash-verified

78 * factors (`√2·√3`, `x²·y²`) are left to CE's own canonicalization, keeping the
79 * blast radius to exponential integrands. */
80function collectSameExponent(
81 ce: ComputeEngine,
82 flat: Expression[]
83): Expression[] {
84 // Group powers by their SIGN-CANONICALIZED exponent (|exp|) so aˣ·bˣ → (ab)ˣ
85 // and aˣ/bˣ (= aˣ·b⁻ˣ) → (a/b)ˣ both fuse: positive-sign bases go to the
86 // numerator, negative-sign to the denominator.
87 const groups = new Map<
88 string,
89 {
90 exp: Expression;
91 items: { f: Expression; base: Expression; sign: 1 | -1 }[];
92 }
93 >();
94 const order: string[] = [];
95 const passthrough: Expression[] = [];
96 for (const f of flat) {
97 const isPow = f.operator === 'Power' && f.ops;
98 const exp = isPow ? f.ops![1] : ce.One;
99 // only fuse genuine (symbolic-exponent) powers; everything else is kept
100 if (!isPow || isNumber(exp)) {
101 passthrough.push(f);
102 continue;
103 }
104 const [canon, sign] = splitSign(ce, exp);
105 const key = canon.toString();
106 if (!groups.has(key)) {
107 groups.set(key, { exp: canon, items: [] });
108 order.push(key);
109 }
110 groups.get(key)!.items.push({ f, base: f.ops![0], sign });
111 }
112 if ([...groups.values()].every((g) => g.items.length === 1)) return flat;
113 const out: Expression[] = [...passthrough];
114 for (const key of order) {
115 const { exp, items } = groups.get(key)!;
116 if (items.length === 1) {
117 out.push(items[0].f); // singleton: keep the original factor verbatim
118 continue;
119 }
120 const num = items.filter((i) => i.sign === 1).map((i) => i.base);
121 const den = items.filter((i) => i.sign === -1).map((i) => i.base);
122 let base: Expression = num.length ? mul(ce, num) : ce.One;
123 if (den.length) base = ce._fn('Divide', [base, mul(ce, den)]);
124 out.push(pow(ce, base, exp)); // exp is the canonical (positive) exponent
125 }
126 return out;
127}
128
129/** Split an exponent into (|exponent|, sign), canonicalizing through `mul` so
130 * `−1·x` keys identically to `x` (the raw `negate` leaves a `1·x` artifact). */

Callers 1

mulFunction · 0.85

Calls 11

isNumberFunction · 0.90
splitSignFunction · 0.85
mulFunction · 0.70
powFunction · 0.70
toStringMethod · 0.65
hasMethod · 0.65
setMethod · 0.65
getMethod · 0.65
valuesMethod · 0.65
mapMethod · 0.65
_fnMethod · 0.65

Tested by

no test coverage detected