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

Function collectPolyFactors

src/compute-engine/rubi/driver.ts:774–825  ·  view source on GitHub ↗

Rewrite uncollected polynomial Add factors of a (normal-form) integrand * as Σ Coeff·x^k with x-free coefficients; null when nothing changes.

(
  ce: ComputeEngine,
  integrand: Expression,
  variable: string
)

Source from the content-addressed store, hash-verified

772 ce,
773 free.length === 1 ? free[0] : ce._fn('Multiply', free)
774 );
775 const u = recanonicalize(
776 ce,
777 rest.length === 1 ? rest[0] : ce._fn('Multiply', rest)
778 );
779 this.stats.preludeFirings++;
780 // Record the constant pull BEFORE recursing (preorder); roll it back if
781 // the residual integral fails so an aborted attempt leaves no records.
782 const mark = this.mark();
783 this.record(
784 entryNode,
785 () => ce.function('Multiply', [c, inert(u)]),
786 'integrate.constant-factor'
787 );
788 const F = this.intRec(u, variable, depth + 1);
789 if (F === null) {
790 this.truncate(mark);
791 return null;
792 }
793 return c.mul(F);
794 }
795 }
796
797 // ---- rule dispatch (priority order) -------------------------------
798 const hooks: Hooks = { int: recurse };
799 const trace = (id: string, stage: string): void => {
800 if (this.options.trace) this.stats.trace.push({ id, stage, depth });
801 };
802 // Second-level dispatch screen: the candidate list for this integrand's
803 // root operator (root-operator prescreen, cached once per operator over
804 // the bundle) narrowed by the integrand-skeleton feature set. Both
805 // filters are NECESSARY conditions on a match (see compile.ts
806 // `requiredHeads`), so no rule that could fire is dropped; rule order
807 // within the candidate list is the original priority order (stable
808 // filtering — the buckets are built by a single ordered pass).
809 const integrandHeads = new Set<string>();
810 collectHeads(integrand, integrandHeads);
811 const noSkeleton = this.options.noSkeleton ?? NO_SKELETON;
812 const candidates = noSkeleton
813 ? this.rules
814 : this.candidatesFor(integrand.operator);
815 const dispatch = (envCap: number): Expression | null => {
816 for (const rule of candidates) {
817 if (Date.now() > this.deadline) return null;
818 if (noSkeleton) {
819 // legacy path: root-operator prescreen only (A/B baseline)
820 if (rule.rootOp !== null && rule.rootOp !== integrand.operator)
821 continue;
822 } else {
823 // integrand-skeleton screen: skip when a head the pattern provably
824 // requires is absent from the integrand (conservative — fail-open
825 // on inclusion). The candidate bucket already enforced the
826 // root-operator match.
827 const req = rule.requiredHeads;
828 let skip = false;

Callers 1

intRecMethod · 0.85

Calls 4

collectFunction · 0.70
symbolMethod · 0.65
mapMethod · 0.65
_fnMethod · 0.65

Tested by

no test coverage detected