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

Function combineTriSum

src/compute-engine/rubi/rubi-utils.ts:1859–1913  ·  view source on GitHub ↗
(
  u: { kind: 'bin'; p: BinParts } | { kind: 'tri'; p: TriParts },
  v: { kind: 'bin'; p: BinParts } | { kind: 'tri'; p: TriParts }
)

Source from the content-addressed store, hash-verified

1857 const out = terms.map((t) => t.div(xk));
1858 return out.length === 1 ? out[0] : ce.function('Add', out);
1859 };
1860 return divTerms(num).div(divTerms(den));
1861}
1862
1863/** R26B: rewrite a (possibly deeply nested) rational function of `x` into a
1864 * single FLAT `N/D` whose numerator and denominator are fully-expanded
1865 * polynomials in `x` sharing no common `x^k` monomial factor. Used by the
1866 * hyperbolic function-of-exponential fallback: the `t = e^x` substitution
1867 * lands `∫1/(a+b·sinh x)` at the nested shape `1/(x·(a + b/2·(x − 1/x)))`,
1868 * which no bundled rule matches, whereas the flat equivalent `2/(b·x²+2a·x−b)`
1869 * closes via the 1.2.1.1 quadratic-denominator rules.
1870 *
1871 * `asNumDen` cross-multiplies the nested Divide/Subtract/Power structure into a
1872 * single fraction; `expand` turns each side into a polynomial in x; the common
1873 * `x^k` factor (introduced by the outer `1/x` of the substitution) is cancelled
1874 * the way `Cancel` would. Returns null when the result is NOT a rational
1875 * function of x (some expanded side is not a polynomial in x, or the
1876 * denominator vanishes), so the caller can fall back to the un-normalized form.
1877 */
1878export function rationalNormalFormX(
1879 e: Expression,
1880 x: string,
1881 clearNegatives = false
1882): Expression | null {
1883 const ce = e.engine;
1884 const divByXk = (u: Expression, kk: number): Expression => {
1885 if (kk <= 0) return u;
1886 const xk = ce.function('Power', [ce.symbol(x), ce.number(kk)]);
1887 const terms = u.operator === 'Add' && u.ops ? u.ops : [u];
1888 const out = terms.map((t) => t.div(xk));
1889 return expand(out.length === 1 ? out[0] : ce.function('Add', out));
1890 };
1891 const { num, den } = asNumDen(e);
1892 let n = expand(num);
1893 let d = expand(den);
1894 if (d.isSame(0)) return null;
1895 // R30: a hyperbolic power ≥ 2 substitutes to `(½(x∓1/x))^k` folds whose
1896 // expansion carries genuine NEGATIVE x-powers (`x^-1`, `x^-2`, …); the outer
1897 // `1/x` of the substitution clears only ONE of them, so the residual is a
1898 // Laurent (not ordinary) polynomial and `polyCoeffsX` below rejects it,
1899 // leaving these rows unsolved. Multiply num & den through by `x^(-negShift)`
1900 // (the shared factor preserves the fraction's value) so both become genuine
1901 // polynomials in x; the biquadratic/trinomial denominator that results is
1902 // exactly what the bundled 1.2.x rules close. Gated (default off) so R26B and
1903 // ch2 stay byte-identical unless the caller opts in.
1904 if (clearNegatives) {
1905 const negShift = Math.min(0, minXPowerSigned(n, x), minXPowerSigned(d, x));
1906 if (negShift < 0) {
1907 const xs = ce.function('Power', [ce.symbol(x), ce.number(-negShift)]);
1908 n = expand(n.mul(xs));
1909 d = expand(d.mul(xs));
1910 }
1911 }
1912 // Cancel the common `x^k` monomial factor shared by numerator and denominator
1913 // (introduced by the substitution's outer `1/x`).
1914 const k = Math.min(minXPower(n, x), minXPower(d, x));
1915 n = divByXk(n, k);
1916 d = divByXk(d, k);

Callers 1

trinomialPartsXFunction · 0.85

Calls 5

zeroQFunction · 0.85
subMethod · 0.65
mulMethod · 0.65
evaluateMethod · 0.65
addMethod · 0.65

Tested by

no test coverage detected