(u: Expression, n: number)
| 1386 | } |
| 1387 | |
| 1388 | const productOf = (ce: ComputeEngine, fs: Expression[]): Expression => |
| 1389 | fs.length === 0 |
| 1390 | ? ce.One |
| 1391 | : fs.length === 1 |
| 1392 | ? fs[0] |
| 1393 | : fs.reduce((p, f) => p.mul(f)); |
| 1394 | |
| 1395 | // Rubi NegQ[u] over a term (negative form per the PosAux heuristics) |
| 1396 | function negFormQ(u: Expression): boolean { |
| 1397 | return !posQ(u) && !zeroQ(u); |
| 1398 | } |
| 1399 | |
| 1400 | /** sum terms of a base (Add/Subtract), through odd literal powers |
| 1401 | * (Rubi SumBaseQ companions); null when not a sum base */ |
| 1402 | function sumBaseTerms(u: Expression): Expression[] | null { |
| 1403 | if (u.operator === 'Add' || u.operator === 'Subtract') return sumTermsX(u); |
| 1404 | if (u.operator === 'Power' && u.ops) { |
| 1405 | const k = realNum(u.ops[1]); |
| 1406 | if (k !== null && Number.isInteger(k) && Math.abs(k % 2) === 1) |
| 1407 | return sumBaseTerms(u.ops[0]); |
| 1408 | } |
| 1409 | return null; |
| 1410 | } |
| 1411 | const sumBaseQ = (u: Expression): boolean => sumBaseTerms(u) !== null; |
| 1412 | const negSumBaseQ = (u: Expression): boolean => { |
| 1413 | const ts = sumBaseTerms(u); |
| 1414 | return ts !== null && negFormQ(mmaFirstTerm(ts)); |
| 1415 | }; |
| 1416 | const allNegTermQ = (u: Expression): boolean => { |
| 1417 | const ts = sumBaseTerms(u); |
| 1418 | if (ts !== null) return ts.every(negFormQ); |
| 1419 | return negFormQ(u); |
| 1420 | }; |
| 1421 | const someNegTermQ = (u: Expression): boolean => { |
| 1422 | const ts = sumBaseTerms(u); |
| 1423 | if (ts !== null) return ts.some(negFormQ); |
| 1424 | return negFormQ(u); |
| 1425 | }; |
| 1426 | const atomBaseQ = (u: Expression): boolean => { |
| 1427 | if (!u.ops) return true; |
| 1428 | if (u.operator === 'Power' && u.ops) { |
| 1429 | const k = realNum(u.ops[1]); |
| 1430 | if (k !== null && Number.isInteger(k) && Math.abs(k % 2) === 1) |
| 1431 | return atomBaseQ(u.ops[0]); |
| 1432 | } |
| 1433 | return false; |
| 1434 | }; |
| 1435 | |
| 1436 | /** Rubi RtAux[u, n] (TrigSquare and the complex-integer basis case |
| 1437 | * omitted — not exercised by Chapter 1) */ |
| 1438 | let rtAuxDepth = 0; |
| 1439 | function rtAux(u: Expression, n: number): Expression { |
| 1440 | // recursion backstop: the WL definition recurses through rewritten |
| 1441 | // forms whose CE canonicalizations can re-create each other — fall |
| 1442 | // back to the literal principal root rather than overflow |
| 1443 | if (rtAuxDepth > 40) { |
| 1444 | if (process.env.RUBI_DEBUG_RT) |
| 1445 | console.error(`rtAux depth cap: ${u.toString().slice(0, 120)}`); |
no test coverage detected