@danielsimonjr/mathts-functions 0.59.0 → 0.61.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cas/rational-integrate.d.ts +197 -0
- package/dist/cas/rational-integrate.d.ts.map +1 -0
- package/dist/cas-integration.d.ts +7 -2
- package/dist/cas-integration.d.ts.map +1 -1
- package/dist/index.js +559 -3
- package/dist/typed/factorization/integer-poly.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Layer 1 rational-function symbolic integration — Task 1: parse a
|
|
3
|
+
* single-variable rational-function expression into exact integer
|
|
4
|
+
* numerator/denominator polynomials, split off the polynomial part via
|
|
5
|
+
* exact-ℚ long division, and integrate a polynomial termwise (power rule).
|
|
6
|
+
*
|
|
7
|
+
* Reuses the univariate expression parser (`polyFromExpression`, from the
|
|
8
|
+
* Gröbner-basis module) for parsing and the bigint dense-polynomial
|
|
9
|
+
* convention (`IntPoly`, index = degree) from the #7 factorization engine
|
|
10
|
+
* for the integer representation.
|
|
11
|
+
*
|
|
12
|
+
* See docs/superpowers/plans/2026-07-20-risch-layer1-rational-integration.md
|
|
13
|
+
* (Task 1). Later tasks build denominator factorization, exact-ℚ partial
|
|
14
|
+
* fractions, and per-factor closed-form integration on top of this module.
|
|
15
|
+
*/
|
|
16
|
+
import { type IntPoly } from '../typed/factorization/integer-poly.js';
|
|
17
|
+
/** Exact rational number, always normalized to lowest terms with a positive denominator. */
|
|
18
|
+
export interface Rat {
|
|
19
|
+
num: bigint;
|
|
20
|
+
den: bigint;
|
|
21
|
+
}
|
|
22
|
+
/** A rational function `numer(x)/denom(x)` with integer dense (`IntPoly`) coefficients. */
|
|
23
|
+
export interface RatFunc {
|
|
24
|
+
numer: IntPoly;
|
|
25
|
+
denom: IntPoly;
|
|
26
|
+
}
|
|
27
|
+
export declare function ratAdd(a: Rat, b: Rat): Rat;
|
|
28
|
+
export declare function ratSub(a: Rat, b: Rat): Rat;
|
|
29
|
+
export declare function ratMul(a: Rat, b: Rat): Rat;
|
|
30
|
+
export declare function ratDiv(a: Rat, b: Rat): Rat;
|
|
31
|
+
export declare function ratFromBigint(n: bigint): Rat;
|
|
32
|
+
/**
|
|
33
|
+
* A quadratic surd `a + b·√Δ` for a fixed positive non-square radicand `Δ`
|
|
34
|
+
* (Δ > 0, non-square — a perfect-square Δ never occurs here since it would
|
|
35
|
+
* already have split into rational linear factors). `Δ` is NOT stored on the
|
|
36
|
+
* `Surd` itself: surds produced within one computation share a single `Δ`,
|
|
37
|
+
* and every op that needs it (`surdMul`, `surdDiv`, `surdRender`) takes it as
|
|
38
|
+
* an explicit parameter. `surdAdd`/`surdSub`/`surdNeg`/`surdFromRat` are
|
|
39
|
+
* Δ-independent (componentwise on `a`/`b`), so they don't take it.
|
|
40
|
+
*
|
|
41
|
+
* See docs/superpowers/specs/2026-07-21-risch-layer2-quadratic-surd-design.md
|
|
42
|
+
* (Architecture §1).
|
|
43
|
+
*/
|
|
44
|
+
export interface Surd {
|
|
45
|
+
a: Rat;
|
|
46
|
+
b: Rat;
|
|
47
|
+
}
|
|
48
|
+
/** Lifts a rational number to a surd with zero `√Δ` component. */
|
|
49
|
+
export declare function surdFromRat(r: Rat): Surd;
|
|
50
|
+
/** Negates a surd componentwise. */
|
|
51
|
+
export declare function surdNeg(s: Surd): Surd;
|
|
52
|
+
/** Componentwise surd addition (Δ-independent). */
|
|
53
|
+
export declare function surdAdd(x: Surd, y: Surd): Surd;
|
|
54
|
+
/** Componentwise surd subtraction (Δ-independent). */
|
|
55
|
+
export declare function surdSub(x: Surd, y: Surd): Surd;
|
|
56
|
+
/**
|
|
57
|
+
* Surd multiplication: `(a+b√Δ)(c+d√Δ) = (ac+bdΔ) + (ad+bc)√Δ`, using exact
|
|
58
|
+
* `Rat` arithmetic throughout (`Δ` lifted to a `Rat` via `ratFromBigint`).
|
|
59
|
+
*/
|
|
60
|
+
export declare function surdMul(x: Surd, y: Surd, delta: bigint): Surd;
|
|
61
|
+
/**
|
|
62
|
+
* Surd division, rationalized by the conjugate: `(a+b√Δ)/(c+d√Δ) =
|
|
63
|
+
* (a+b√Δ)(c−d√Δ) / (c²−d²Δ)`, where `c²−d²Δ` is a plain rational scalar.
|
|
64
|
+
* Throws when `y` is zero (both components zero).
|
|
65
|
+
*/
|
|
66
|
+
export declare function surdDiv(x: Surd, y: Surd, delta: bigint): Surd;
|
|
67
|
+
/**
|
|
68
|
+
* Renders a surd as a readable, evaluable string `a + b*sqrt(Δ)`: a zero `a`
|
|
69
|
+
* or zero `b` component is omitted, `b = 1`/`b = -1` render as bare
|
|
70
|
+
* `sqrt(Δ)`/`- sqrt(Δ)`, and integer `Rat`s print without a `/1`. Exact
|
|
71
|
+
* format is non-contractual (correctness is verified by differentiation
|
|
72
|
+
* elsewhere); this only needs to stay evaluable and readable.
|
|
73
|
+
*/
|
|
74
|
+
export declare function surdRender(s: Surd, delta: bigint): string;
|
|
75
|
+
/**
|
|
76
|
+
* Parses a single-variable expression `numerExpr/denomExpr` (or a bare
|
|
77
|
+
* polynomial, denominator `[1n]`) into integer numerator/denominator dense
|
|
78
|
+
* polynomials. Rational coefficients are cleared by the LCM of their
|
|
79
|
+
* denominators (numerator and denominator are each cleared independently,
|
|
80
|
+
* then cross-scaled by the other's factor so the represented ratio
|
|
81
|
+
* `numer(x)/denom(x)` is unchanged).
|
|
82
|
+
*
|
|
83
|
+
* Returns `null` when `expr` is not a rational function of `v`: it contains
|
|
84
|
+
* a transcendental call (`sin`/`exp`/... — any identifier other than `v`),
|
|
85
|
+
* more than one variable, a zero denominator, or coefficients that cannot be
|
|
86
|
+
* cleared to integers.
|
|
87
|
+
*/
|
|
88
|
+
export declare function parseRationalFunction(expr: string, v: string): RatFunc | null;
|
|
89
|
+
/**
|
|
90
|
+
* Exact-ℚ polynomial long division of `rf.numer` by `rf.denom`:
|
|
91
|
+
* `numer = quotient·denom + remainder`, `deg(remainder) < deg(denom)`.
|
|
92
|
+
* Division is performed over ℚ (so a non-monic denominator is handled
|
|
93
|
+
* correctly); the result is converted back to `bigint` coefficients, which
|
|
94
|
+
* requires every intermediate `Rat` to reduce to an integer denominator —
|
|
95
|
+
* true whenever the division is itself exact-integer, as it is for a
|
|
96
|
+
* genuine rational-function reduction. Throws if it is not (a caller that
|
|
97
|
+
* expects a non-integer quotient/remainder is out of this module's scope).
|
|
98
|
+
*/
|
|
99
|
+
export declare function polynomialPart(rf: RatFunc): {
|
|
100
|
+
quotient: IntPoly;
|
|
101
|
+
remainder: IntPoly;
|
|
102
|
+
};
|
|
103
|
+
/**
|
|
104
|
+
* Termwise power rule: the coefficient `c` at degree `n` in `p` integrates
|
|
105
|
+
* to `c/(n+1) · v^(n+1)`. Renders a readable (not contractual beyond
|
|
106
|
+
* containing the expected power) string, e.g. `x^2/2`, `2*x`.
|
|
107
|
+
*/
|
|
108
|
+
export declare function integratePolynomial(p: IntPoly, v: string): string;
|
|
109
|
+
/**
|
|
110
|
+
* An irreducible factor of a rational function's denominator, classified for
|
|
111
|
+
* closed-form integration:
|
|
112
|
+
* - `'linear'` (degree 1) → a `log`;
|
|
113
|
+
* - `'quadratic-neg'` (degree 2, discriminant `b²−4ac < 0`, complex roots) →
|
|
114
|
+
* a `log` + `atan` pair (Layer 1);
|
|
115
|
+
* - `'quadratic-pos'` (degree 2, discriminant `> 0`, real irrational roots,
|
|
116
|
+
* multiplicity 1) → a pair of real `log`s with quadratic-surd coefficients
|
|
117
|
+
* (Layer 2, see the quadratic-surd design doc).
|
|
118
|
+
* Degree-≥3 irreducible factors, and repeated positive-discriminant quadratics,
|
|
119
|
+
* are out of scope (see `factorDenominator`, which returns `null` for them).
|
|
120
|
+
*/
|
|
121
|
+
export interface DenFactor {
|
|
122
|
+
poly: IntPoly;
|
|
123
|
+
mult: number;
|
|
124
|
+
kind: 'linear' | 'quadratic-neg' | 'quadratic-pos';
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Factors `denom` completely over ℤ/ℚ via the #7 factorization engine
|
|
128
|
+
* (`factorUnivariateZ`) and classifies each irreducible factor by degree.
|
|
129
|
+
*
|
|
130
|
+
* A degree-1 factor is `'linear'`. A degree-2 factor, having survived complete
|
|
131
|
+
* factorization over ℚ, is irreducible over ℚ — but that does NOT fix its
|
|
132
|
+
* discriminant sign: `disc = b²−4ac < 0` (complex roots, e.g. x²+1) is
|
|
133
|
+
* `'quadratic-neg'` (Layer 1 arctan path); `disc > 0` (real irrational roots,
|
|
134
|
+
* a non-square disc, e.g. x²−2) with **multiplicity 1** is `'quadratic-pos'`
|
|
135
|
+
* (Layer 2 quadratic-surd path).
|
|
136
|
+
*
|
|
137
|
+
* Returns `null` when a factor is out of scope: any irreducible factor of
|
|
138
|
+
* degree ≥ 3, or a **repeated** positive-discriminant quadratic (`disc > 0`,
|
|
139
|
+
* `mult > 1`) — the reduction formula for repeated real-root quadratics is
|
|
140
|
+
* Layer 3. The caller then falls back to the `integral(...)` marker.
|
|
141
|
+
*/
|
|
142
|
+
export declare function factorDenominator(denom: IntPoly): DenFactor[] | null;
|
|
143
|
+
/**
|
|
144
|
+
* A single partial-fraction term `numer(x) / factor(x)^power`. `numer` is a
|
|
145
|
+
* `Rat[]` of fixed length `deg(factor)` (index = degree, ascending — the same
|
|
146
|
+
* convention as `IntPoly`): length 1 (a constant) over a linear factor,
|
|
147
|
+
* length 2 (`[E, D]` meaning `D*x + E`) over a quadratic factor.
|
|
148
|
+
*/
|
|
149
|
+
export interface PFTerm {
|
|
150
|
+
factor: IntPoly;
|
|
151
|
+
power: number;
|
|
152
|
+
numer: Rat[];
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Exact-ℚ partial-fraction decomposition of `remainder(x) / ∏ factorᵢ(x)^multᵢ`
|
|
156
|
+
* (`deg(remainder) < deg(∏ factorᵢ^multᵢ)`, as produced by `polynomialPart`)
|
|
157
|
+
* into the standard form: for each irreducible factor `qᵢ` with multiplicity
|
|
158
|
+
* `mᵢ`, terms `A_{i,k}(x) / qᵢ(x)^k` for `k = 1..mᵢ`, `deg A_{i,k} < deg qᵢ`.
|
|
159
|
+
*
|
|
160
|
+
* Solved by clearing denominators: multiplying the ansatz by the full
|
|
161
|
+
* denominator `D = ∏ factorⱼ^multⱼ` turns each unknown numerator coefficient
|
|
162
|
+
* into a linear unknown whose column is the polynomial
|
|
163
|
+
* `x^j · qᵢ(x)^{mᵢ−k} · ∏_{j≠i} factorⱼ(x)^multⱼ` (a plain integer polynomial
|
|
164
|
+
* product — no division is ever needed, since `mᵢ−k ≥ 0`). Equating
|
|
165
|
+
* coefficients of `remainder(x)` on both sides gives a square (`deg D` ×
|
|
166
|
+
* `deg D`) rational linear system, solved exactly via `solveLinearSystemRat`.
|
|
167
|
+
*/
|
|
168
|
+
export declare function partialFractions(remainder: IntPoly, factors: DenFactor[]): PFTerm[];
|
|
169
|
+
/**
|
|
170
|
+
* Integrates a single partial-fraction term in closed form. Dispatches on the
|
|
171
|
+
* degree of `term.factor` and, for a quadratic, on its discriminant sign:
|
|
172
|
+
* - degree 1 → `log` (+ rational part for a repeated factor);
|
|
173
|
+
* - degree 2, `disc < 0` (complex roots) → `log`/rational part + `atan`;
|
|
174
|
+
* - degree 2, `disc > 0` (real irrational roots, power 1) → a pair of real
|
|
175
|
+
* `log`s with quadratic-surd coefficients (Layer 2).
|
|
176
|
+
* The produced string is evaluable by the expression engine (`log`, `atan`,
|
|
177
|
+
* `sqrt`, `abs`, `^`, `*`); its exact form is not contractual — correctness is
|
|
178
|
+
* verified by differentiation. Throws on any other factor degree, or on a
|
|
179
|
+
* positive-discriminant quadratic with power > 1 (both unreachable for a
|
|
180
|
+
* `factorDenominator`-classified factor).
|
|
181
|
+
*/
|
|
182
|
+
export declare function integratePFTerm(term: PFTerm, v: string): string;
|
|
183
|
+
/**
|
|
184
|
+
* Full Layer-1 rational-function integration pipeline. Parses `expr` into an
|
|
185
|
+
* exact integer rational function, splits off and integrates the polynomial
|
|
186
|
+
* part, factors the denominator into linear + irreducible-quadratic factors,
|
|
187
|
+
* decomposes into exact-ℚ partial fractions, and integrates each term in
|
|
188
|
+
* closed form (rational part + `log` + `atan`).
|
|
189
|
+
*
|
|
190
|
+
* Returns `null` when `expr` is not a rational function of `v`
|
|
191
|
+
* (`parseRationalFunction` declines), when the denominator has a degree-≥3
|
|
192
|
+
* irreducible factor (`factorDenominator` declines — Layer 2 territory), or
|
|
193
|
+
* when any internal step throws (e.g. a non-integer polynomial-part division),
|
|
194
|
+
* so callers get a clean decline rather than an exception.
|
|
195
|
+
*/
|
|
196
|
+
export declare function integrateRationalFunction(expr: string, v: string): string | null;
|
|
197
|
+
//# sourceMappingURL=rational-integrate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rational-integrate.d.ts","sourceRoot":"","sources":["../../src/cas/rational-integrate.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,12 +4,17 @@
|
|
|
4
4
|
* integrand is outside the supported subset, returns `integral(expr, variable)`.
|
|
5
5
|
*
|
|
6
6
|
* The direct recursion is tried first; on failure, partial-fraction integration
|
|
7
|
-
* (for rational integrands)
|
|
8
|
-
* polynomial·{exp,sin,cos})
|
|
7
|
+
* (for distinct-rational-root integrands), tabular integration by parts (for
|
|
8
|
+
* polynomial·{exp,sin,cos}), and full rational-function integration (Risch
|
|
9
|
+
* Layer 1) are attempted before giving up with the marker. Rational functions
|
|
10
|
+
* with irreducible-quadratic and repeated factors are now integrated (rational
|
|
11
|
+
* part + `log` + `arctan`); degree-≥3 irreducible denominators and transcendental
|
|
12
|
+
* Risch remain out of scope (marker).
|
|
9
13
|
*
|
|
10
14
|
* @example symbolicIntegral('x^3') // 'x^4 / 4'
|
|
11
15
|
* @example symbolicIntegral('cos(3*x + 1)') // 'sin(3 * x + 1) / 3'
|
|
12
16
|
* @example symbolicIntegral('1/(x^2 - 1)') // partial fractions → sum of logs
|
|
17
|
+
* @example symbolicIntegral('1/(x^2 + 1)') // Risch Layer 1 → 'atan(...)'
|
|
13
18
|
* @example symbolicIntegral('x * sin(x)') // by parts → 'sin(x) - x*cos(x)'
|
|
14
19
|
*/
|
|
15
20
|
export declare function symbolicIntegral(expr: string, variable?: string): string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cas-integration.d.ts","sourceRoot":"","sources":["../src/cas-integration.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"cas-integration.d.ts","sourceRoot":"","sources":["../src/cas-integration.ts"],"names":[],"mappings":"AA2WA;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,SAAM,GAAG,MAAM,CAYrE"}
|
package/dist/index.js
CHANGED
|
@@ -10019,11 +10019,15 @@ function landauMignotte(p) {
|
|
|
10019
10019
|
return 1n;
|
|
10020
10020
|
}
|
|
10021
10021
|
const n = BigInt(d + 1);
|
|
10022
|
-
const lcAbs = t[d] < 0n ? -t[d] : t[d];
|
|
10023
10022
|
const powerOfTwo = 1n << BigInt(d);
|
|
10023
|
+
let normSq = 0n;
|
|
10024
|
+
for (const c of t) {
|
|
10025
|
+
normSq += c * c;
|
|
10026
|
+
}
|
|
10027
|
+
const norm2Ceil = isqrt(normSq) + 1n;
|
|
10024
10028
|
const sq = isqrt(n);
|
|
10025
10029
|
const sqrtCeil = sq * sq === n ? sq : sq + 1n;
|
|
10026
|
-
const bound = sqrtCeil * powerOfTwo *
|
|
10030
|
+
const bound = sqrtCeil * powerOfTwo * norm2Ceil;
|
|
10027
10031
|
return bound > 0n ? bound : 1n;
|
|
10028
10032
|
}
|
|
10029
10033
|
function modSymmetric(p, m) {
|
|
@@ -50609,6 +50613,558 @@ function lsqBounded(A, b, lower, upper, opts = {}) {
|
|
|
50609
50613
|
return { x, residual: residualNorm(A, x, b) };
|
|
50610
50614
|
}
|
|
50611
50615
|
|
|
50616
|
+
// src/cas/rational-integrate.ts
|
|
50617
|
+
function ratNormalize(num2, den) {
|
|
50618
|
+
if (den === 0n) {
|
|
50619
|
+
throw new Error("Rat: zero denominator");
|
|
50620
|
+
}
|
|
50621
|
+
let n = num2;
|
|
50622
|
+
let d = den;
|
|
50623
|
+
if (d < 0n) {
|
|
50624
|
+
n = -n;
|
|
50625
|
+
d = -d;
|
|
50626
|
+
}
|
|
50627
|
+
if (n === 0n) {
|
|
50628
|
+
return { num: 0n, den: 1n };
|
|
50629
|
+
}
|
|
50630
|
+
const g = bigintGcd(n, d);
|
|
50631
|
+
return { num: n / g, den: d / g };
|
|
50632
|
+
}
|
|
50633
|
+
function ratAdd(a, b) {
|
|
50634
|
+
return ratNormalize(a.num * b.den + b.num * a.den, a.den * b.den);
|
|
50635
|
+
}
|
|
50636
|
+
function ratSub(a, b) {
|
|
50637
|
+
return ratNormalize(a.num * b.den - b.num * a.den, a.den * b.den);
|
|
50638
|
+
}
|
|
50639
|
+
function ratMul(a, b) {
|
|
50640
|
+
return ratNormalize(a.num * b.num, a.den * b.den);
|
|
50641
|
+
}
|
|
50642
|
+
function ratDiv(a, b) {
|
|
50643
|
+
if (b.num === 0n) {
|
|
50644
|
+
throw new Error("Rat: division by zero");
|
|
50645
|
+
}
|
|
50646
|
+
return ratNormalize(a.num * b.den, a.den * b.num);
|
|
50647
|
+
}
|
|
50648
|
+
function ratFromBigint(n) {
|
|
50649
|
+
return { num: n, den: 1n };
|
|
50650
|
+
}
|
|
50651
|
+
var RAT_ZERO = { num: 0n, den: 1n };
|
|
50652
|
+
function surdFromRat(r) {
|
|
50653
|
+
return { a: r, b: RAT_ZERO };
|
|
50654
|
+
}
|
|
50655
|
+
function surdNeg(s) {
|
|
50656
|
+
return { a: ratNeg(s.a), b: ratNeg(s.b) };
|
|
50657
|
+
}
|
|
50658
|
+
function surdAdd(x, y) {
|
|
50659
|
+
return { a: ratAdd(x.a, y.a), b: ratAdd(x.b, y.b) };
|
|
50660
|
+
}
|
|
50661
|
+
function surdMul(x, y, delta) {
|
|
50662
|
+
const d = ratFromBigint(delta);
|
|
50663
|
+
return {
|
|
50664
|
+
a: ratAdd(ratMul(x.a, y.a), ratMul(ratMul(x.b, y.b), d)),
|
|
50665
|
+
b: ratAdd(ratMul(x.a, y.b), ratMul(x.b, y.a))
|
|
50666
|
+
};
|
|
50667
|
+
}
|
|
50668
|
+
function surdDiv(x, y, delta) {
|
|
50669
|
+
if (y.a.num === 0n && y.b.num === 0n) {
|
|
50670
|
+
throw new Error("surdDiv: division by zero surd");
|
|
50671
|
+
}
|
|
50672
|
+
const d = ratFromBigint(delta);
|
|
50673
|
+
const scale4 = ratSub(ratMul(y.a, y.a), ratMul(ratMul(y.b, y.b), d));
|
|
50674
|
+
const conj3 = { a: y.a, b: ratNeg(y.b) };
|
|
50675
|
+
const numer = surdMul(x, conj3, delta);
|
|
50676
|
+
return { a: ratDiv(numer.a, scale4), b: ratDiv(numer.b, scale4) };
|
|
50677
|
+
}
|
|
50678
|
+
function surdRender(s, delta) {
|
|
50679
|
+
const parts = [];
|
|
50680
|
+
if (s.a.num !== 0n) {
|
|
50681
|
+
parts.push(ratToStr(s.a));
|
|
50682
|
+
}
|
|
50683
|
+
if (s.b.num !== 0n) {
|
|
50684
|
+
const neg2 = s.b.num < 0n;
|
|
50685
|
+
const absB = neg2 ? ratNeg(s.b) : s.b;
|
|
50686
|
+
const sqrtPart = `sqrt(${delta})`;
|
|
50687
|
+
const term = absB.num === absB.den ? sqrtPart : `${ratToStr(absB)}*${sqrtPart}`;
|
|
50688
|
+
if (parts.length === 0) {
|
|
50689
|
+
parts.push(neg2 ? `- ${term}` : term);
|
|
50690
|
+
} else {
|
|
50691
|
+
parts.push(neg2 ? `- ${term}` : `+ ${term}`);
|
|
50692
|
+
}
|
|
50693
|
+
}
|
|
50694
|
+
if (parts.length === 0) {
|
|
50695
|
+
return "0";
|
|
50696
|
+
}
|
|
50697
|
+
return parts.join(" ");
|
|
50698
|
+
}
|
|
50699
|
+
function splitTopLevelDivision(expr) {
|
|
50700
|
+
let depth = 0;
|
|
50701
|
+
for (let i = 0; i < expr.length; i += 1) {
|
|
50702
|
+
const c = expr[i];
|
|
50703
|
+
if (c === "(") {
|
|
50704
|
+
depth += 1;
|
|
50705
|
+
} else if (c === ")") {
|
|
50706
|
+
depth -= 1;
|
|
50707
|
+
} else if (c === "/" && depth === 0) {
|
|
50708
|
+
return { numerStr: expr.slice(0, i), denomStr: expr.slice(i + 1) };
|
|
50709
|
+
}
|
|
50710
|
+
}
|
|
50711
|
+
return { numerStr: expr, denomStr: "1" };
|
|
50712
|
+
}
|
|
50713
|
+
function denseFromPoly(p) {
|
|
50714
|
+
let maxPow = 0;
|
|
50715
|
+
for (const t of p) {
|
|
50716
|
+
maxPow = Math.max(maxPow, t.powers[0] ?? 0);
|
|
50717
|
+
}
|
|
50718
|
+
const dense = new Array(maxPow + 1).fill(0);
|
|
50719
|
+
for (const t of p) {
|
|
50720
|
+
dense[t.powers[0]] += t.coeff;
|
|
50721
|
+
}
|
|
50722
|
+
return dense;
|
|
50723
|
+
}
|
|
50724
|
+
var INT_EPS = 1e-7;
|
|
50725
|
+
function isCloseToInteger(x) {
|
|
50726
|
+
return Math.abs(x - Math.round(x)) < INT_EPS;
|
|
50727
|
+
}
|
|
50728
|
+
function commonDenominator(coeffs) {
|
|
50729
|
+
const LIMIT = 1e5;
|
|
50730
|
+
for (let k = 1; k <= LIMIT; k += 1) {
|
|
50731
|
+
if (coeffs.every((c) => isCloseToInteger(c * k))) {
|
|
50732
|
+
return k;
|
|
50733
|
+
}
|
|
50734
|
+
}
|
|
50735
|
+
return null;
|
|
50736
|
+
}
|
|
50737
|
+
function parseRationalFunction(expr, v) {
|
|
50738
|
+
const { numerStr, denomStr } = splitTopLevelDivision(expr);
|
|
50739
|
+
let numerPoly;
|
|
50740
|
+
let denomPoly;
|
|
50741
|
+
try {
|
|
50742
|
+
numerPoly = polyFromExpression(numerStr, [v]);
|
|
50743
|
+
denomPoly = polyFromExpression(denomStr, [v]);
|
|
50744
|
+
} catch {
|
|
50745
|
+
return null;
|
|
50746
|
+
}
|
|
50747
|
+
const numerDense = denseFromPoly(numerPoly);
|
|
50748
|
+
const denomDense = denseFromPoly(denomPoly);
|
|
50749
|
+
if (denomDense.every((c) => c === 0)) {
|
|
50750
|
+
return null;
|
|
50751
|
+
}
|
|
50752
|
+
const kNumer = commonDenominator(numerDense);
|
|
50753
|
+
const kDenom = commonDenominator(denomDense);
|
|
50754
|
+
if (kNumer === null || kDenom === null) {
|
|
50755
|
+
return null;
|
|
50756
|
+
}
|
|
50757
|
+
const scale4 = kNumer * kDenom;
|
|
50758
|
+
const toIntPoly = (dense) => {
|
|
50759
|
+
const out = new Array(dense.length);
|
|
50760
|
+
for (let i = 0; i < dense.length; i += 1) {
|
|
50761
|
+
const scaled = dense[i] * scale4;
|
|
50762
|
+
if (!isCloseToInteger(scaled)) {
|
|
50763
|
+
return null;
|
|
50764
|
+
}
|
|
50765
|
+
out[i] = BigInt(Math.round(scaled));
|
|
50766
|
+
}
|
|
50767
|
+
return trim(out);
|
|
50768
|
+
};
|
|
50769
|
+
const numer = toIntPoly(numerDense);
|
|
50770
|
+
const denom = toIntPoly(denomDense);
|
|
50771
|
+
if (numer === null || denom === null || denom.length === 0) {
|
|
50772
|
+
return null;
|
|
50773
|
+
}
|
|
50774
|
+
return { numer, denom };
|
|
50775
|
+
}
|
|
50776
|
+
function trimRat(p) {
|
|
50777
|
+
let n = p.length;
|
|
50778
|
+
while (n > 0 && p[n - 1].num === 0n) {
|
|
50779
|
+
n -= 1;
|
|
50780
|
+
}
|
|
50781
|
+
return p.slice(0, n);
|
|
50782
|
+
}
|
|
50783
|
+
function polynomialPart(rf) {
|
|
50784
|
+
const denom = trim(rf.denom);
|
|
50785
|
+
if (denom.length === 0) {
|
|
50786
|
+
throw new Error("polynomialPart: zero denominator");
|
|
50787
|
+
}
|
|
50788
|
+
const db = denom.length - 1;
|
|
50789
|
+
const lb = ratFromBigint(denom[db]);
|
|
50790
|
+
const denomRat = denom.map(ratFromBigint);
|
|
50791
|
+
let rem = trimRat(trim(rf.numer).map(ratFromBigint));
|
|
50792
|
+
const dq = rem.length - 1 - db;
|
|
50793
|
+
const quotient = new Array(Math.max(dq + 1, 0)).fill(RAT_ZERO);
|
|
50794
|
+
while (rem.length > 0 && rem.length - 1 >= db) {
|
|
50795
|
+
const dr = rem.length - 1;
|
|
50796
|
+
const shift = dr - db;
|
|
50797
|
+
const coeff = ratDiv(rem[dr], lb);
|
|
50798
|
+
quotient[shift] = coeff;
|
|
50799
|
+
const next = rem.slice();
|
|
50800
|
+
for (let i = 0; i <= db; i += 1) {
|
|
50801
|
+
next[shift + i] = ratSub(next[shift + i], ratMul(coeff, denomRat[i]));
|
|
50802
|
+
}
|
|
50803
|
+
rem = trimRat(next);
|
|
50804
|
+
}
|
|
50805
|
+
const toExactIntPoly = (rs) => trim(
|
|
50806
|
+
rs.map((r) => {
|
|
50807
|
+
if (r.den !== 1n) {
|
|
50808
|
+
throw new Error("polynomialPart: division introduced a non-integer coefficient");
|
|
50809
|
+
}
|
|
50810
|
+
return r.num;
|
|
50811
|
+
})
|
|
50812
|
+
);
|
|
50813
|
+
return { quotient: toExactIntPoly(quotient), remainder: toExactIntPoly(rem) };
|
|
50814
|
+
}
|
|
50815
|
+
function formatRatTerm(r, varPart) {
|
|
50816
|
+
const sign3 = r.num < 0n ? "-" : "";
|
|
50817
|
+
const absNum = r.num < 0n ? -r.num : r.num;
|
|
50818
|
+
const coeffPart = absNum === 1n ? "" : `${absNum}*`;
|
|
50819
|
+
const denPart = r.den === 1n ? "" : `/${r.den}`;
|
|
50820
|
+
return `${sign3}${coeffPart}${varPart}${denPart}`;
|
|
50821
|
+
}
|
|
50822
|
+
function integratePolynomial(p, v) {
|
|
50823
|
+
const trimmed = trim(p);
|
|
50824
|
+
const terms = [];
|
|
50825
|
+
for (let i = 0; i < trimmed.length; i += 1) {
|
|
50826
|
+
const c = trimmed[i];
|
|
50827
|
+
if (c === 0n) {
|
|
50828
|
+
continue;
|
|
50829
|
+
}
|
|
50830
|
+
const n = i + 1;
|
|
50831
|
+
const coeff = ratNormalize(c, BigInt(n));
|
|
50832
|
+
const varPart = n === 1 ? v : `${v}^${n}`;
|
|
50833
|
+
terms.push(formatRatTerm(coeff, varPart));
|
|
50834
|
+
}
|
|
50835
|
+
if (terms.length === 0) {
|
|
50836
|
+
return "0";
|
|
50837
|
+
}
|
|
50838
|
+
return terms.join(" + ").replace(/\+ -/g, "- ");
|
|
50839
|
+
}
|
|
50840
|
+
function factorDenominator(denom) {
|
|
50841
|
+
const { factors } = factorUnivariateZ(trim(denom));
|
|
50842
|
+
const out = [];
|
|
50843
|
+
for (const { poly, mult } of factors) {
|
|
50844
|
+
const deg = trim(poly).length - 1;
|
|
50845
|
+
if (deg === 1) {
|
|
50846
|
+
out.push({ poly, mult, kind: "linear" });
|
|
50847
|
+
} else if (deg === 2) {
|
|
50848
|
+
const q = trim(poly);
|
|
50849
|
+
const disc = q[1] * q[1] - 4n * q[2] * q[0];
|
|
50850
|
+
if (disc < 0n) {
|
|
50851
|
+
out.push({ poly, mult, kind: "quadratic-neg" });
|
|
50852
|
+
} else if (mult === 1) {
|
|
50853
|
+
out.push({ poly, mult, kind: "quadratic-pos" });
|
|
50854
|
+
} else {
|
|
50855
|
+
return null;
|
|
50856
|
+
}
|
|
50857
|
+
} else {
|
|
50858
|
+
return null;
|
|
50859
|
+
}
|
|
50860
|
+
}
|
|
50861
|
+
return out;
|
|
50862
|
+
}
|
|
50863
|
+
function shiftedColumn(poly, shift, size2) {
|
|
50864
|
+
const col = new Array(size2).fill(RAT_ZERO);
|
|
50865
|
+
for (let i = 0; i < poly.length; i += 1) {
|
|
50866
|
+
const row2 = i + shift;
|
|
50867
|
+
if (row2 < size2) {
|
|
50868
|
+
col[row2] = ratFromBigint(poly[i]);
|
|
50869
|
+
}
|
|
50870
|
+
}
|
|
50871
|
+
return col;
|
|
50872
|
+
}
|
|
50873
|
+
function solveLinearSystemRat(matrix2, rhs) {
|
|
50874
|
+
const n = rhs.length;
|
|
50875
|
+
const rows = matrix2.map((row2, r) => [...row2, rhs[r]]);
|
|
50876
|
+
for (let col = 0; col < n; col += 1) {
|
|
50877
|
+
let pivotRow = -1;
|
|
50878
|
+
for (let r = col; r < n; r += 1) {
|
|
50879
|
+
if (rows[r][col].num !== 0n) {
|
|
50880
|
+
pivotRow = r;
|
|
50881
|
+
break;
|
|
50882
|
+
}
|
|
50883
|
+
}
|
|
50884
|
+
if (pivotRow === -1) {
|
|
50885
|
+
throw new Error("partialFractions: singular partial-fraction linear system");
|
|
50886
|
+
}
|
|
50887
|
+
if (pivotRow !== col) {
|
|
50888
|
+
const tmp = rows[col];
|
|
50889
|
+
rows[col] = rows[pivotRow];
|
|
50890
|
+
rows[pivotRow] = tmp;
|
|
50891
|
+
}
|
|
50892
|
+
const pivotVal = rows[col][col];
|
|
50893
|
+
rows[col] = rows[col].map((v) => ratDiv(v, pivotVal));
|
|
50894
|
+
for (let r = 0; r < n; r += 1) {
|
|
50895
|
+
if (r === col) {
|
|
50896
|
+
continue;
|
|
50897
|
+
}
|
|
50898
|
+
const factor2 = rows[r][col];
|
|
50899
|
+
if (factor2.num === 0n) {
|
|
50900
|
+
continue;
|
|
50901
|
+
}
|
|
50902
|
+
const pivotRowVals = rows[col];
|
|
50903
|
+
rows[r] = rows[r].map((v, c) => ratSub(v, ratMul(factor2, pivotRowVals[c])));
|
|
50904
|
+
}
|
|
50905
|
+
}
|
|
50906
|
+
return rows.map((row2) => row2[n]);
|
|
50907
|
+
}
|
|
50908
|
+
function partialFractions(remainder, factors) {
|
|
50909
|
+
const trimmedRemainder = trim(remainder);
|
|
50910
|
+
const factorPowers = factors.map((f) => {
|
|
50911
|
+
const powers = [[1n]];
|
|
50912
|
+
let acc = [1n];
|
|
50913
|
+
for (let p = 1; p <= f.mult; p += 1) {
|
|
50914
|
+
acc = mul(acc, f.poly);
|
|
50915
|
+
powers.push(acc);
|
|
50916
|
+
}
|
|
50917
|
+
return powers;
|
|
50918
|
+
});
|
|
50919
|
+
const othersProduct = factors.map((_f, fi) => {
|
|
50920
|
+
let acc = [1n];
|
|
50921
|
+
for (let fj = 0; fj < factors.length; fj += 1) {
|
|
50922
|
+
if (fj === fi) {
|
|
50923
|
+
continue;
|
|
50924
|
+
}
|
|
50925
|
+
acc = mul(acc, factorPowers[fj][factors[fj].mult]);
|
|
50926
|
+
}
|
|
50927
|
+
return acc;
|
|
50928
|
+
});
|
|
50929
|
+
const degOf = (fi) => trim(factors[fi].poly).length - 1;
|
|
50930
|
+
const unknowns = [];
|
|
50931
|
+
for (let fi = 0; fi < factors.length; fi += 1) {
|
|
50932
|
+
const di = degOf(fi);
|
|
50933
|
+
for (let k = 1; k <= factors[fi].mult; k += 1) {
|
|
50934
|
+
for (let j = 0; j < di; j += 1) {
|
|
50935
|
+
unknowns.push({ fi, k, j });
|
|
50936
|
+
}
|
|
50937
|
+
}
|
|
50938
|
+
}
|
|
50939
|
+
const n = unknowns.length;
|
|
50940
|
+
const columns = unknowns.map(({ fi, k, j }) => {
|
|
50941
|
+
const remainingPower = factors[fi].mult - k;
|
|
50942
|
+
const coPoly = mul(othersProduct[fi], factorPowers[fi][remainingPower]);
|
|
50943
|
+
return shiftedColumn(coPoly, j, n);
|
|
50944
|
+
});
|
|
50945
|
+
const rows = [];
|
|
50946
|
+
for (let r = 0; r < n; r += 1) {
|
|
50947
|
+
rows.push(columns.map((col) => col[r]));
|
|
50948
|
+
}
|
|
50949
|
+
const rhs = new Array(n).fill(RAT_ZERO).map((_, idx2) => ratFromBigint(idx2 < trimmedRemainder.length ? trimmedRemainder[idx2] : 0n));
|
|
50950
|
+
const solution = n === 0 ? [] : solveLinearSystemRat(rows, rhs);
|
|
50951
|
+
const terms = [];
|
|
50952
|
+
let idx = 0;
|
|
50953
|
+
for (let fi = 0; fi < factors.length; fi += 1) {
|
|
50954
|
+
const di = degOf(fi);
|
|
50955
|
+
for (let k = 1; k <= factors[fi].mult; k += 1) {
|
|
50956
|
+
const numer = [];
|
|
50957
|
+
for (let j = 0; j < di; j += 1) {
|
|
50958
|
+
numer.push(solution[idx]);
|
|
50959
|
+
idx += 1;
|
|
50960
|
+
}
|
|
50961
|
+
terms.push({ factor: factors[fi].poly, power: k, numer });
|
|
50962
|
+
}
|
|
50963
|
+
}
|
|
50964
|
+
return terms;
|
|
50965
|
+
}
|
|
50966
|
+
function ratNeg(r) {
|
|
50967
|
+
return { num: -r.num, den: r.den };
|
|
50968
|
+
}
|
|
50969
|
+
function ratToStr(r) {
|
|
50970
|
+
return r.den === 1n ? `${r.num}` : `${r.num}/${r.den}`;
|
|
50971
|
+
}
|
|
50972
|
+
function renderCoeffTimes(r, rest) {
|
|
50973
|
+
const neg2 = r.num < 0n;
|
|
50974
|
+
const absNum = neg2 ? -r.num : r.num;
|
|
50975
|
+
const sign3 = neg2 ? "-" : "";
|
|
50976
|
+
if (absNum === r.den) {
|
|
50977
|
+
return `${sign3}${rest}`;
|
|
50978
|
+
}
|
|
50979
|
+
const denPart = r.den === 1n ? "" : `/${r.den}`;
|
|
50980
|
+
return `${sign3}${absNum}${denPart}*${rest}`;
|
|
50981
|
+
}
|
|
50982
|
+
function renderXMinus(a, v) {
|
|
50983
|
+
if (a.num === 0n) {
|
|
50984
|
+
return v;
|
|
50985
|
+
}
|
|
50986
|
+
if (a.num > 0n) {
|
|
50987
|
+
return `${v} - ${ratToStr(a)}`;
|
|
50988
|
+
}
|
|
50989
|
+
return `${v} + ${ratToStr(ratNeg(a))}`;
|
|
50990
|
+
}
|
|
50991
|
+
function renderQuadraticCore(b, c, v) {
|
|
50992
|
+
let s = `${v}^2`;
|
|
50993
|
+
if (b.num !== 0n) {
|
|
50994
|
+
s += ` + (${ratToStr(b)})*${v}`;
|
|
50995
|
+
}
|
|
50996
|
+
s += ` + (${ratToStr(c)})`;
|
|
50997
|
+
return s;
|
|
50998
|
+
}
|
|
50999
|
+
function renderTwoXPlusB(b, v) {
|
|
51000
|
+
let s = `2*${v}`;
|
|
51001
|
+
if (b.num !== 0n) {
|
|
51002
|
+
s += ` + (${ratToStr(b)})`;
|
|
51003
|
+
}
|
|
51004
|
+
return s;
|
|
51005
|
+
}
|
|
51006
|
+
function joinTerms(parts) {
|
|
51007
|
+
if (parts.length === 0) {
|
|
51008
|
+
return "0";
|
|
51009
|
+
}
|
|
51010
|
+
return parts.join(" + ").replace(/\+ -/g, "- ");
|
|
51011
|
+
}
|
|
51012
|
+
function integrateLinearTerm(factor2, k, numer, v) {
|
|
51013
|
+
const p0 = factor2[0];
|
|
51014
|
+
const p1 = factor2[1];
|
|
51015
|
+
const a = ratNeg(ratDiv(ratFromBigint(p0), ratFromBigint(p1)));
|
|
51016
|
+
const A = ratDiv(numer[0], ratFromBigint(p1 ** BigInt(k)));
|
|
51017
|
+
if (A.num === 0n) {
|
|
51018
|
+
return "0";
|
|
51019
|
+
}
|
|
51020
|
+
const xMinus = renderXMinus(a, v);
|
|
51021
|
+
if (k === 1) {
|
|
51022
|
+
return renderCoeffTimes(A, `log(abs(${xMinus}))`);
|
|
51023
|
+
}
|
|
51024
|
+
const coeff = ratNeg(ratDiv(A, ratFromBigint(BigInt(k - 1))));
|
|
51025
|
+
return renderCoeffTimes(coeff, `(${xMinus})^(${-(k - 1)})`);
|
|
51026
|
+
}
|
|
51027
|
+
function integrateInverseQuadraticPower(k, b, c) {
|
|
51028
|
+
if (k === 1) {
|
|
51029
|
+
return { terms: [], atanCoeff: ratFromBigint(1n) };
|
|
51030
|
+
}
|
|
51031
|
+
const prev = integrateInverseQuadraticPower(k - 1, b, c);
|
|
51032
|
+
const d2 = ratSub(ratMul(ratFromBigint(4n), c), ratMul(b, b));
|
|
51033
|
+
const denomFactor = ratMul(ratFromBigint(BigInt(k - 1)), d2);
|
|
51034
|
+
const newTermCoeff = ratDiv(ratFromBigint(1n), denomFactor);
|
|
51035
|
+
const propagate = ratDiv(ratFromBigint(BigInt(2 * (2 * k - 3))), denomFactor);
|
|
51036
|
+
const terms = prev.terms.map((t) => ({ coeff: ratMul(t.coeff, propagate), power: t.power }));
|
|
51037
|
+
terms.push({ coeff: newTermCoeff, power: k - 1 });
|
|
51038
|
+
return { terms, atanCoeff: ratMul(prev.atanCoeff, propagate) };
|
|
51039
|
+
}
|
|
51040
|
+
function integrateQuadraticTerm(factor2, k, numer, v) {
|
|
51041
|
+
const q0 = factor2[0];
|
|
51042
|
+
const q1 = factor2[1];
|
|
51043
|
+
const q2 = factor2[2];
|
|
51044
|
+
const b = ratDiv(ratFromBigint(q1), ratFromBigint(q2));
|
|
51045
|
+
const c = ratDiv(ratFromBigint(q0), ratFromBigint(q2));
|
|
51046
|
+
const leadPow = ratFromBigint(q2 ** BigInt(k));
|
|
51047
|
+
const D = ratDiv(numer[1], leadPow);
|
|
51048
|
+
const E = ratDiv(numer[0], leadPow);
|
|
51049
|
+
const d2 = ratSub(ratMul(ratFromBigint(4n), c), ratMul(b, b));
|
|
51050
|
+
const K = ratSub(E, ratMul(D, ratDiv(b, ratFromBigint(2n))));
|
|
51051
|
+
const qCore = renderQuadraticCore(b, c, v);
|
|
51052
|
+
const twoXb = renderTwoXPlusB(b, v);
|
|
51053
|
+
const parts = [];
|
|
51054
|
+
if (D.num !== 0n) {
|
|
51055
|
+
const half = ratDiv(D, ratFromBigint(2n));
|
|
51056
|
+
if (k === 1) {
|
|
51057
|
+
parts.push(renderCoeffTimes(half, `log(${qCore})`));
|
|
51058
|
+
} else {
|
|
51059
|
+
const coeff = ratNeg(ratDiv(half, ratFromBigint(BigInt(k - 1))));
|
|
51060
|
+
parts.push(renderCoeffTimes(coeff, `(${qCore})^(${-(k - 1)})`));
|
|
51061
|
+
}
|
|
51062
|
+
}
|
|
51063
|
+
if (K.num !== 0n) {
|
|
51064
|
+
const ik = integrateInverseQuadraticPower(k, b, c);
|
|
51065
|
+
for (const t of ik.terms) {
|
|
51066
|
+
const coeff = ratMul(K, t.coeff);
|
|
51067
|
+
if (coeff.num === 0n) {
|
|
51068
|
+
continue;
|
|
51069
|
+
}
|
|
51070
|
+
parts.push(renderCoeffTimes(coeff, `(${twoXb})/(${qCore})^(${t.power})`));
|
|
51071
|
+
}
|
|
51072
|
+
const atanCoeff = ratMul(ratMul(K, ik.atanCoeff), ratFromBigint(2n));
|
|
51073
|
+
if (atanCoeff.num !== 0n) {
|
|
51074
|
+
const d2s = ratToStr(d2);
|
|
51075
|
+
parts.push(renderCoeffTimes(atanCoeff, `atan((${twoXb})/sqrt(${d2s}))/sqrt(${d2s})`));
|
|
51076
|
+
}
|
|
51077
|
+
}
|
|
51078
|
+
return joinTerms(parts);
|
|
51079
|
+
}
|
|
51080
|
+
function integrateQuadraticPosTerm(factor2, numer, v) {
|
|
51081
|
+
const c = factor2[0];
|
|
51082
|
+
const b = factor2[1];
|
|
51083
|
+
const a = factor2[2];
|
|
51084
|
+
const R = b * b - 4n * a * c;
|
|
51085
|
+
const D = numer[1] ?? RAT_ZERO;
|
|
51086
|
+
const E = numer[0] ?? RAT_ZERO;
|
|
51087
|
+
const twoA = ratFromBigint(2n * a);
|
|
51088
|
+
const negBOver2A = ratDiv(ratFromBigint(-b), twoA);
|
|
51089
|
+
const inv2A = ratDiv(ratFromBigint(1n), twoA);
|
|
51090
|
+
const r1 = { a: negBOver2A, b: inv2A };
|
|
51091
|
+
const r2 = { a: negBOver2A, b: ratNeg(inv2A) };
|
|
51092
|
+
const sqrtR = { a: RAT_ZERO, b: ratFromBigint(1n) };
|
|
51093
|
+
const Dsurd = surdFromRat(D);
|
|
51094
|
+
const Esurd = surdFromRat(E);
|
|
51095
|
+
const numA = surdAdd(surdMul(Dsurd, r1, R), Esurd);
|
|
51096
|
+
const numB = surdAdd(surdMul(Dsurd, r2, R), Esurd);
|
|
51097
|
+
const A = surdDiv(numA, sqrtR, R);
|
|
51098
|
+
const B = surdDiv(numB, surdNeg(sqrtR), R);
|
|
51099
|
+
const parts = [];
|
|
51100
|
+
const emit = (coeff, root2) => {
|
|
51101
|
+
if (coeff.a.num === 0n && coeff.b.num === 0n) {
|
|
51102
|
+
return;
|
|
51103
|
+
}
|
|
51104
|
+
parts.push(`(${surdRender(coeff, R)})*log(abs(${v} - (${surdRender(root2, R)})))`);
|
|
51105
|
+
};
|
|
51106
|
+
emit(A, r1);
|
|
51107
|
+
emit(B, r2);
|
|
51108
|
+
return joinTerms(parts);
|
|
51109
|
+
}
|
|
51110
|
+
function integratePFTerm(term, v) {
|
|
51111
|
+
const factor2 = trim(term.factor);
|
|
51112
|
+
const deg = factor2.length - 1;
|
|
51113
|
+
if (deg === 1) {
|
|
51114
|
+
return integrateLinearTerm(factor2, term.power, term.numer, v);
|
|
51115
|
+
}
|
|
51116
|
+
if (deg === 2) {
|
|
51117
|
+
const disc = factor2[1] * factor2[1] - 4n * factor2[2] * factor2[0];
|
|
51118
|
+
if (disc < 0n) {
|
|
51119
|
+
return integrateQuadraticTerm(factor2, term.power, term.numer, v);
|
|
51120
|
+
}
|
|
51121
|
+
if (term.power !== 1) {
|
|
51122
|
+
throw new Error("integratePFTerm: repeated positive-discriminant quadratic is out of scope");
|
|
51123
|
+
}
|
|
51124
|
+
return integrateQuadraticPosTerm(factor2, term.numer, v);
|
|
51125
|
+
}
|
|
51126
|
+
throw new Error(`integratePFTerm: unsupported factor degree ${deg}`);
|
|
51127
|
+
}
|
|
51128
|
+
function integrateRationalFunction(expr, v) {
|
|
51129
|
+
try {
|
|
51130
|
+
const rf = parseRationalFunction(expr, v);
|
|
51131
|
+
if (rf === null) {
|
|
51132
|
+
return null;
|
|
51133
|
+
}
|
|
51134
|
+
const factors = factorDenominator(rf.denom);
|
|
51135
|
+
if (factors === null) {
|
|
51136
|
+
return null;
|
|
51137
|
+
}
|
|
51138
|
+
const { quotient, remainder } = polynomialPart(rf);
|
|
51139
|
+
const terms = partialFractions(remainder, factors);
|
|
51140
|
+
let prod2 = [1n];
|
|
51141
|
+
for (const { poly, mult } of factors) {
|
|
51142
|
+
for (let k = 0; k < mult; k += 1) prod2 = mul(prod2, poly);
|
|
51143
|
+
}
|
|
51144
|
+
const scalePoly = exactDivide(rf.denom, prod2);
|
|
51145
|
+
if (scalePoly !== null && scalePoly.length === 1 && scalePoly[0] !== 1n) {
|
|
51146
|
+
const scale4 = ratFromBigint(scalePoly[0]);
|
|
51147
|
+
for (const term of terms) {
|
|
51148
|
+
term.numer = term.numer.map((c) => ratDiv(c, scale4));
|
|
51149
|
+
}
|
|
51150
|
+
}
|
|
51151
|
+
const parts = [];
|
|
51152
|
+
const polyPart = integratePolynomial(quotient, v);
|
|
51153
|
+
if (polyPart !== "0") {
|
|
51154
|
+
parts.push(polyPart);
|
|
51155
|
+
}
|
|
51156
|
+
for (const term of terms) {
|
|
51157
|
+
const s = integratePFTerm(term, v);
|
|
51158
|
+
if (s !== "0") {
|
|
51159
|
+
parts.push(s);
|
|
51160
|
+
}
|
|
51161
|
+
}
|
|
51162
|
+
return joinTerms(parts);
|
|
51163
|
+
} catch {
|
|
51164
|
+
return null;
|
|
51165
|
+
}
|
|
51166
|
+
}
|
|
51167
|
+
|
|
50612
51168
|
// src/cas-integration.ts
|
|
50613
51169
|
var parse2 = parse;
|
|
50614
51170
|
var evaluate2 = evaluate;
|
|
@@ -50846,7 +51402,7 @@ function symbolicIntegral(expr, variable = "x") {
|
|
|
50846
51402
|
return integrateNode(parse2(expr), variable);
|
|
50847
51403
|
} catch (e) {
|
|
50848
51404
|
if (!(e instanceof NotIntegrable)) throw e;
|
|
50849
|
-
return tryPartialFractions(expr, variable) ?? tryByParts(expr, variable) ?? `integral(${expr}, ${variable})`;
|
|
51405
|
+
return tryPartialFractions(expr, variable) ?? tryByParts(expr, variable) ?? integrateRationalFunction(expr, variable) ?? `integral(${expr}, ${variable})`;
|
|
50850
51406
|
}
|
|
50851
51407
|
}
|
|
50852
51408
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"integer-poly.d.ts","sourceRoot":"","sources":["../../../src/typed/factorization/integer-poly.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,qEAAqE;AACrE,MAAM,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC;AAE/B;;;GAGG;AACH,wBAAgB,IAAI,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAMxC;AAED,sEAAsE;AACtE,wBAAgB,MAAM,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,CAGzC;AAED,+DAA+D;AAC/D,wBAAgB,EAAE,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,CAGrC;AAED,4EAA4E;AAC5E,wBAAgB,MAAM,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAE1C;AAED,wBAAwB;AACxB,wBAAgB,GAAG,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,GAAG,OAAO,CASnD;AAED,wBAAwB;AACxB,wBAAgB,GAAG,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,GAAG,OAAO,CASnD;AAED,qBAAqB;AACrB,wBAAgB,GAAG,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAEvC;AAED,uDAAuD;AACvD,wBAAgB,GAAG,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,GAAG,OAAO,CAenD;AAED,iDAAiD;AACjD,wBAAgB,SAAS,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAExD;AAED,gFAAgF;AAChF,wBAAgB,MAAM,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,GAAG,OAAO,CAQtD;AAED,4DAA4D;AAC5D,wBAAgB,QAAQ,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAOtD;AAED,sDAAsD;AACtD,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAStD;AAED,0EAA0E;AAC1E,wBAAgB,OAAO,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,CAO1C;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAYjD;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,GAAG,OAAO,GAAG,IAAI,CAmClE;AAED,sEAAsE;AACtE,wBAAgB,UAAU,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAU9C;AAyBD;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,GAAG,OAAO,CAkBxD;AAmBD;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"integer-poly.d.ts","sourceRoot":"","sources":["../../../src/typed/factorization/integer-poly.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,qEAAqE;AACrE,MAAM,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC;AAE/B;;;GAGG;AACH,wBAAgB,IAAI,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAMxC;AAED,sEAAsE;AACtE,wBAAgB,MAAM,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,CAGzC;AAED,+DAA+D;AAC/D,wBAAgB,EAAE,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,CAGrC;AAED,4EAA4E;AAC5E,wBAAgB,MAAM,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAE1C;AAED,wBAAwB;AACxB,wBAAgB,GAAG,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,GAAG,OAAO,CASnD;AAED,wBAAwB;AACxB,wBAAgB,GAAG,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,GAAG,OAAO,CASnD;AAED,qBAAqB;AACrB,wBAAgB,GAAG,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAEvC;AAED,uDAAuD;AACvD,wBAAgB,GAAG,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,GAAG,OAAO,CAenD;AAED,iDAAiD;AACjD,wBAAgB,SAAS,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAExD;AAED,gFAAgF;AAChF,wBAAgB,MAAM,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,GAAG,OAAO,CAQtD;AAED,4DAA4D;AAC5D,wBAAgB,QAAQ,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAOtD;AAED,sDAAsD;AACtD,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAStD;AAED,0EAA0E;AAC1E,wBAAgB,OAAO,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,CAO1C;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAYjD;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,GAAG,OAAO,GAAG,IAAI,CAmClE;AAED,sEAAsE;AACtE,wBAAgB,UAAU,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAU9C;AAyBD;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,GAAG,OAAO,CAkBxD;AAmBD;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,CAyBjD;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAa3D"}
|
package/package.json
CHANGED