1 /* nicked from mailing list; here is the email message + headers:
3 From: toy.raymond at gmail.com (Raymond Toy)
4 Date: Mon, 03 May 2010 09:41:08 -0400
5 Subject: [Maxima] Rothstein-Trager algorithm.
7 Here is a very rudimentary implementation of the Rothstein-Trager
8 algorithm. Seems to work for the few tests that I've run.
10 f:(x^4-3*x^2+6)/(x^6-5*x^4+5*x^2+4)$
11 int_rational_function(f,x);
12 -> lsum(t*log(x^3+t*x^2-3*x-2*t)/2,t,rootsof(t^2+1,t))
14 One refinement that needs to be done is to try to solve for the roots
15 and substitute them in if possible, instead of leaving the result as a
18 We could also implement the Lazard-Rioboo-Trager algorithm, but maxima
19 doesn't seem to provide the subresultant prs sequence. That would have
27 * Simple implementation of Rothstein-Trager algorithm for integrating
30 * $Id: hermite_reduce.mac,v 1.4 2010/05/03 13:28:46 toy Exp $
33 /* Extended Euclidean algorithm, diophantine version
35 * Find s and t such that s*a + t*b = c and either s = 0 or deg(s) < deg(b)
37 * var is the variable of the polynomials.
39 extended_euclidean(a, b, c, var) :=
40 block([s, t, g, q, r],
41 [s, t, g] : gcdex(a, b, var),
42 [q, r] : divide(c, g),
45 if is(s # 0) and is(hipow(s, var) > hipow(b, var)) then
46 ([q, r] : divide(s, b), s : r, t : t + q*a),
49 /* Hermite Reduction, Mack's linear version
51 * Find g and h such that A/D = diff(g,x) + h and return g and h.
52 * h has a square-free denominator.
54 hermite_reduce(a, d, var) :=
55 block([g : 0, d_minus: gcd(d, diff(d, var)), d_star, deg],
56 d_star : quotient(d, d_minus),
58 print("d- = ", d_minus),
59 print("d* = ", d_star),
61 for i : 1 while hipow(d_minus, var) > 0 do
62 block([d_minus2 : gcd(d_minus, diff(d_minus, var)), d_minus_s, b, c],
63 d_minus_s : quotient(d_minus, d_minus2),
65 print("d-2 = ", d_minus2),
66 print("d-* = ", d_minus_s),
68 [b,c] : extended_euclidean(quotient(-d_star * diff(d_minus,var),
69 d_minus), d_minus_s, a, var),
70 /*print("[b, c] = ", [b, c]),*/
71 a : c - quotient(diff(b, var) * d_star, d_minus_s),
78 /* Make p a monic polynomial.
80 * Let p(x) = a[0]*x^n + a[1]*x^(n-1) ...
82 * Use the substitution x = y/a[0]^(1/n) to get
84 * p(y) = y^n + a[1]/a[0]^((n-1)/n)*y^(n-1) ...
86 * Return the new polynomial and a[0]^(1/n)
89 block([e : hipow(p, var), c, temp],
91 [subst([var = var/(c^(1/e))], p), c^(1/e)]);
95 block([algebraic:true, gcd : subres],
98 /* Rothstein-Trager algorithm
100 * The numerator is a, the denominator is d, and the variable of
101 * integration is var.
103 int_rational_log_part(a, d, var) :=
104 block([resultant : subres, c, t, r, rr, s : 0],
105 r : resultant(d, a - t*diff(d,var), var),
107 /* Can this be done better? Say we have -c*R1(x)*R2(x).... We
108 * really just want the term product terms, without the leading
109 * coefficient. Just look for a unary minus and negate if it is.
111 if op(r) = "-" and length(args(r)) = 1 then
113 for i : 1 thru length(r) do
114 block([f : part(r, i)],
115 /* Skip any expressions that don't involve t */
116 if not freeof(t, f) then
118 /* Look for a expression like (t^2-16)^3. Handle (t^2-16)
124 [rr, c] : monic(p, t),
126 g : algebraic_gcd(d, a - t*expand(diff(d, var)/c)),
129 s : s + apply('lsum, [t*g/c, t, rootsof(rr, t)]))),
133 /* Integrate a rational function f */
134 int_rational_function(f, var) :=
136 [g, h] : hermite_reduce(num(f), denom(f), var),
137 [q, r] : divide(num(h), denom(h)),
139 g + integrate(q, var)
141 g + integrate(q, var) + int_rational_log_part(r, denom(h), var));