( ce: ComputeEngine, options?: IntegrationRulesLoadOptions )
| 51 | /** |
| 52 | * Compile the bundled Rubi rules and register them as the engine's symbolic |
| 53 | * integration provider. Idempotent per engine (re-registers the provider, |
| 54 | * reusing the cached compiled rules). |
| 55 | */ |
| 56 | export function loadIntegrationRules( |
| 57 | ce: ComputeEngine, |
| 58 | options?: IntegrationRulesLoadOptions |
| 59 | ): IntegrationRulesLoadReport { |
| 60 | let result = compiledCache.get(ce); |
| 61 | if (!result) { |
| 62 | result = compileRuleDocs(ce, RUBI_RULES_DATA as unknown as RubiRuleDoc[]); |
| 63 | compiledCache.set(ce, result); |
| 64 | } |
| 65 | const compiled = result.rules; |
| 66 | const skipped = result.skipped; |
| 67 | |
| 68 | const driver = new RubiDriver(ce, compiled, { |
| 69 | timeLimitMs: options?.timeLimitMs ?? 10_000, |
| 70 | }); |
| 71 | |
| 72 | ce._integrationProvider = ( |
| 73 | integrand: Expression, |
| 74 | variable: string, |
| 75 | trace?: RuleSteps |
| 76 | ) => { |
| 77 | // The `Integrate` evaluator passes the integrand wrapped in |
| 78 | // `Function`/`Block`/`Delimiter` scaffolding; the rule driver wants the |
| 79 | // bare integrand (the built-in antiderivative unwraps these too). |
| 80 | let f = integrand; |
| 81 | while ( |
| 82 | f.operator === 'Function' || |
| 83 | f.operator === 'Block' || |
| 84 | f.operator === 'Delimiter' |
| 85 | ) |
| 86 | f = f.op1!; // Function/Block/Delimiter always have a first operand |
| 87 | // Only accumulate a step trace when `explain('Integrate')` asked for one. |
| 88 | const records: IntStepRecord[] | undefined = trace ? [] : undefined; |
| 89 | const result = driver.int(f, variable, records); |
| 90 | // Only a fully-closed antiderivative is usable; a residual inert |
| 91 | // `Integrate` means the rules couldn't finish — defer to the built-in |
| 92 | // antiderivative instead of returning a partial result. |
| 93 | if (result === null || containsIntegrate(result)) return null; |
| 94 | if (trace && records) { |
| 95 | // Replay the recorded steps into whole-state steps. No closing step is |
| 96 | // pushed here: the caller (`explainIntegrate`) appends a final |
no test coverage detected