FunctionOfExponentialTestAux: register the first exponential, or * commensurate-check a later base^expon against the running state.
( base: Expression, expon: Expression, x: string, st: FoeState )
| 3215 | let base = f; |
| 3216 | if (f.operator === 'Power' && f.ops) { |
| 3217 | if (f.ops[1].has(x)) return null; // exponent must be x-free |
| 3218 | exp = f.ops[1]; |
| 3219 | base = f.ops[0]; |
| 3220 | } |
| 3221 | const m = trigMonoParts(base, x); |
| 3222 | if (m) return { kind: 'mono', head: m.head, coef: m.coef, arg: m.arg, exp }; |
| 3223 | const bi = trigBinomParts(ce, base, x); |
| 3224 | if (bi) |
| 3225 | return { kind: 'binom', head: bi.head, a: bi.a, b: bi.b, arg: bi.arg, exp }; |
| 3226 | return null; |
| 3227 | } |
| 3228 | |
| 3229 | /** Build `(coef·head[arg])^exp` (dropping a unit coefficient / exponent). */ |
| 3230 | function buildMono( |
| 3231 | ce: ComputeEngine, |
| 3232 | coef: Expression, |
| 3233 | head: string, |
| 3234 | arg: Expression, |
| 3235 | exp: Expression |
| 3236 | ): Expression { |
| 3237 | const node = ce.function(head, [arg]); |
| 3238 | const base = coef.isSame(1) ? node : coef.mul(node); |
| 3239 | return exp.isSame(1) ? base : ce.function('Power', [base, exp]); |
| 3240 | } |
| 3241 | |
| 3242 | /** Build `(a + b·head[arg])^exp` (dropping a zero constant / unit exponent). */ |
| 3243 | function buildBinom( |
| 3244 | ce: ComputeEngine, |
| 3245 | a: Expression, |
| 3246 | b: Expression, |
| 3247 | head: string, |
| 3248 | arg: Expression, |
| 3249 | exp: Expression |
| 3250 | ): Expression { |
| 3251 | const node = ce.function(head, [arg]); |
| 3252 | const term = b.isSame(1) ? node : b.mul(node); |
| 3253 | const base = a.isSame(0) ? term : a.add(term); |
| 3254 | return exp.isSame(1) ? base : ce.function('Power', [base, exp]); |
| 3255 | } |
| 3256 | |
| 3257 | // Two-factor cofunction-shift clauses (IntegrationUtilityFunctions.m §1.0, |
| 3258 | // 1.1.2, 1.1.3). Rubi has no Cosine chapter, so a cos *binomial* `(a+b·cos)` — |
| 3259 | // or a cos/cofunction *monomial* product (cos·csc, cos·sec) with no sine — |
| 3260 | // must be rewritten so the sine rules apply. The two factors share a single |
| 3261 | // linear argument θ; the shift θ→θ±π/2 turns cos into sin (or sin into cos) |
| 3262 | // while carrying the paired monomial along so both keep a common argument. |
| 3263 | function unifyProductClauses( |
| 3264 | ce: ComputeEngine, |
| 3265 | f1: Expression, |
| 3266 | f2: Expression, |
| 3267 | x: string |
| 3268 | ): Expression | null { |
| 3269 | const c1 = classifyFactor(ce, f1, x); |
| 3270 | const c2 = classifyFactor(ce, f2, x); |
| 3271 | if (c1 === null || c2 === null) return null; |
| 3272 | if (!c1.arg.isSame(c2.arg)) return null; |
| 3273 | const argP = c1.arg.add(ce.Pi.div(2)); // θ + π/2 |
| 3274 | const argM = c1.arg.sub(ce.Pi.div(2)); // θ − π/2 |