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

Function costFunction

src/compute-engine/cost-function.ts:74–257  ·  view source on GitHub ↗
(expr: Expression)

Source from the content-addressed store, hash-verified

72 // beat the single `⁴√12` (8).
73 //
74 // The premium is calibrated so a radical LITERAL costs about what the
75 // equivalent expression costs: `Sqrt(y)` prices at 6, and `√3` now prices
76 // at 6 too.
77 const radical = (n as { radical?: number }).radical;
78 if (radical !== undefined && radical > 1)
79 return numericCostFunction(n.re) + 3 + numericCostFunction(radical);
80
81 return numericCostFunction(n.re);
82}
83
84/**
85 * The default cost function, used to determine if a new expression is simpler
86 * than the old one.
87 *
88 * To change the cost function used by the engine, set the
89 * `ce.costFunction` property of the engine or pass a custom cost function
90 * to the `simplify` function.
91 *
92 */
93/**
94 * Price a `Power(base, exp)`. Extracted so the alias heads that canonicalize
95 * to a Power (`Square`, `Exp`) price identically to the canonical form — the
96 * cost function must not depend on which representation it is handed.
97 *
98 * The base is mostly ignored so that `2q^2` beats `2qq`, except when the base
99 * is a `Negate` (so `(-x)^n` is not cheaper than `-x^n`) or a `Multiply` (so
100 * `(ab)^n` is not artificially cheaper than the distributed `a^n b^n`).
101 */
102function powerCost(base: Expression, exp: Expression): number {
103 const expCost = costFunction(exp);
104 // Count a negated base too. This used to be a flat `expCost + 4`, which
105 // discarded everything under the sign — the same defect as the removed
106 // `Negate(Power(...))` shortcut, just on the other side. Once `Power` began
107 // counting its base it became load-bearing: `(-sin x)^2` scored 5 against
108 // `sin(x)^2` at 12, so the gate REJECTED the rewrite and left the negation
109 // in place. A symbol base hid it (`(-x)^2 -> x^2` still worked).
110 if (base.operator === 'Negate') return expCost + costFunction(base);
111 if (isFunction(base, 'Multiply')) {
112 // A negative coefficient under a fractional exponent must factor its sign
113 // out for a correct real result, so make the unfactored form expensive.
114 const hasNegativeCoef = base.ops.some(
115 (f) => isNumber(f) && f.isNegative === true
116 );
117 if (hasNegativeCoef && exp.isRational === true && !exp.isInteger)
118 return expCost + costFunction(base) + 15;
119 return expCost + costFunction(base);
120 }
121 // Count the base. It used to be discarded for every base that was not a
122 // `Negate` or `Multiply`, which priced `(a+b+c+d)^20` at 2 — the same as
123 // `x^20`, and barely above `x^2` — even though it expands to 1,771 terms.
124 // The stated goal ("`2q^2` should beat `2qq`") survives: a power still costs
125 // far less than the repeated multiplication it replaces.
126 return expCost + costFunction(base);
127}
128
129export function costFunction(expr: Expression): number {
130 // Special-case: Encourage the "exp/log separation" rewrite used by
131 // `simplifyLog()` for base-10 logs:

Callers 1

isCheaperFunction · 0.85

Calls 8

isFunctionFunction · 0.90
isSymbolFunction · 0.90
isNumberFunction · 0.90
numericValueFunction · 0.90
numericCostFunctionFunction · 0.85
matchFunction · 0.70
absMethod · 0.65
isIntegerMethod · 0.45

Tested by

no test coverage detected