(u: Expression)
| 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 |
no test coverage detected