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

Function canonicalLimitsSequence

src/compute-engine/library/utils.ts:253–306  ·  view source on GitHub ↗
(
  ops: ReadonlyArray<Expression>,
  options: { engine: ComputeEngine }
)

Source from the content-addressed store, hash-verified

251 // symbol `n`, or `n − 1` — cannot be enumerated: the domain is
252 // symbolic. Without this check `normalizeIndexingSet` silently
253 // substitutes its default iteration window for the unusable bound, so
254 // `Sum(k, [k, 1, n])` evaluated as if `n` were 10001 (→ 50015001).
255 const symbolicBound = (b: Expression) =>
256 !(isSymbol(b) && b.symbol === 'Nothing') &&
257 Number.isNaN(bigopBoundValue(b));
258 if (symbolicBound(idx.op2) || symbolicBound(idx.op3)) return 'symbolic';
259 if (!normalizeIndexingSet(idx).isFinite) infinite = true;
260 }
261 }
262
263 if (!infinite) return 'finite';
264
265 // The body is numeric iff its only free variables are the index variables.
266 // (`unknowns` already excludes constants like `Pi` and any name bound to a
267 // value, and function heads are not counted as free variables.)
268 const numericBody = (body?.unknowns ?? []).every((s) => indexNames.has(s));
269 return numericBody ? 'numeric' : 'symbolic';
270}
271
272/**
273 * Shift a body's index `k → k + 1`, returning the substituted expression.
274 */
275function shiftIndex(
276 expr: Expression,
277 index: string,
278 ce: ComputeEngine
279): Expression {
280 return expr.subs({ [index]: ce.box(['Add', index, 1]) });
281}
282
283/**
284 * Decompose a telescoping body `Add(a, b)` (exactly two terms, exactly one a
285 * `Negate`) into its positive and negative parts and the orientation:
286 * - forward: body = t(k+1) − t(k) (with `t = neg`), sums to t(b+1) − t(a)
287 * - mirror: body = t(k) − t(k+1) (with `t = pos`), sums to t(a) − t(b+1)
288 * Both parts must depend on the index. Returns undefined if the body is not a
289 * `k → k+1` shift pair.
290 */
291function telescopingParts(
292 body: Expression,
293 index: string,
294 ce: ComputeEngine
295): { pos: Expression; neg: Expression; forward: boolean } | undefined {
296 if (!isFunction(body, 'Add') || body.ops.length !== 2) return undefined;
297
298 let pos: Expression | undefined;
299 let neg: Expression | undefined;
300 for (const t of body.ops) {
301 if (isFunction(t, 'Negate')) {
302 if (neg) return undefined; // two negated terms → not a telescoping pair
303 neg = t.op1;
304 } else {
305 if (pos) return undefined;
306 pos = t;
307 }
308 }
309 if (!pos || !neg) return undefined;

Callers 1

calculus.tsFile · 0.90

Calls 4

isSymbolFunction · 0.90
isNumberFunction · 0.90
canonicalLimitsFunction · 0.85
errorMethod · 0.65

Tested by

no test coverage detected