You are on page 1of 16

ISSN 0361-7688, Programming and Computer Software, 2009, Vol. 35, No. 2, pp. 63–78. © Pleiades Publishing, Ltd.

, 2009.

On Mathematica Program for “Poor Man’s Integrator”


Implementing Risch–Norman Algorithm1
R. Kragler
University of Applied Sciences D-88241 Weingarten, Germany
e-mail: kragler@hs-weingarten.de

Abstract—In this paper by means of computer experiment we study advantages and disadvantages of the heu-
ristical method of “parallel integrator”. For this purpose we describe and use implementation of the method in
Mathematica. In some cases we compare this implementation with the original one in Maple.
DOI: 10.1134/S0361768809020029

1 1. METHOD OF PARALLEL INTEGRATION m


Du i
In his last paper (see [1, 2]) Manuel Bronstein from
f = Dv + ∑ c --------
i
u
-.
i
(1)
INRIA (France) presented implementation in Maple of i=1

the heuristical integration method known in the litera-


Since v is a ration of polynomials in t1, …, tn and ui are
ture as “new Risch algorithm” [3], “Risch-Norman
algorithm” [4–6] (most often) and “parallel Risch algo- polynomials in the same variables, the method of paral-
rithm” [7–9]. The presented Maple programm pmint lel integration consists in making educated guesses for
called by his author “Poor Man’s Integrator” is avail- the ui , for the denominator of v as well as for the degree
able in the Internet [10]. of its numerator. This reduces the problem of solving
equation (1) to finding the ci and the constant coeffi-
In his monograph [11] M. Bronstein devoted a sep- cients of the numerator in v which can be achieved with
arate chapter (chapter 10) to this integration method. elementary linear algebra.
The method attempts to handle all the generators of the
differential field containing the integrand “in parallel”, If the system of linear equations in the unknown
i.e. without sequential (recursive) construction of the constants ci has a solution, then an integral of f is found.
corresponding field extensions. In fact, parallel integra- However, the nonexistence of a solution does not
tion is rather heuristical than algorithmic since it may always imply that f does not have an elementary inte-
fail both in theory and in practice at integration of ele- gral over K; it could just mean that the guess was
mentary functions. wrong. All parallel approaches published so far share
the property that there are functions which have ele-
The basic idea of parallel integration [11] is to avoid mentary antiderivatives that cannot be found by the par-
recursive nature in algorithmic construction of an inte- allel method. As a consequence, parallel integration is
gral by extension of the differential field K containing a convenient heuristic method which is significantly
both integrand f and its “antiderivative”. In so doing the easier to implement than the complete Risch integration
field containing f is considered as a field of multivariate algorithm. As will be shown below it is very success-
rational functions over its constants. Thereby, it is fully implemented for computer algebra systems (CAS)
assumed that f ∈ K where K = C(t1, …, tn), C = such as Maple and Mathematica. Below we demon-
Const(K) (field of constants for K) and every ti is tran-
strate this fact by a number of examples.
scendental over C(t1, …, ti – 1).
As a consequence of the strong version of Liou-
ville’s Theorem [11] (Ch. 5, p. 145), if the integral of f, 2. MATHEMATICA CODE FOR PMINT
which belongs to the field of elementary functions over
K, is an elementary function from the same field (more The Maple implementation of the heuristic parallel
preciously, belongs to its elementary extension), then integration as the program pmint made available by
there exists v ∈ K and constants c1, …, cm from the M. Bronstein in the Internet in May 2005 [10]. This
algebraic closure of C and u1, …, um ∈ K such that program contains 95 lines of code only. The program is
intended to integrate trancendental functions both ele-
1 The article is published in the original. mentary and special.

63
64 KRAGLER

Luis A. Medina and Alexander Pavlyk [12] devel- Below we present the code of pmint in Mathematica
oped the concept of pmint for Mathematica. Because in the form of separate procedures. In doing so, where
powerful Maple functions (e.g. convert) used do not it is possible we compare the Mathematica code with
the code of corresponding procedures of pmint in
have a direct correspondence in Mathematica the task Maple.
rewriting pmint into Mathematica code is not straight- (1) Procedures: pmint, pmIntegrate, tryIntegral,
forward. The author of the present paper updated pmint getSpecial, myFactors, enumerateMonoms, splitFactor,
and made their intensive testing by different examples deflation
running for the version 6.0.2 of Mathematica. The main procedure pmint in Mathematica:

Clear[pmint];
pmint[ f–, x–, opt: OptionsPattern[{Extension 0}]] :=
Module[{ff, si, li, lin, lout, q, d, l, lv, ld, ls, fint, lc, t, terms, list},
ff = Together[TrigToTan[f]];
list = ToIndetsAndDerivation[ff, x, t];
If [list == $Failed, Return[INT[f]]];
{ff, terms, lv, ld} = list;
q = denD[ld];
ld = q ∗ ld;
ls = DeleteCases[Map[getSpecial[#,Thread[terms Rest[lv]]]&, terms], Null];
ToTerms[pmIntegrate[ff, lv, ld, q, ls, OptionValue[Extension]],
terms, Rest[lv]] /. {tan Tan}]
For comparison we give the procedure pmint in Maple:
pmint := proc( f, x)
local ff, si, li, lin, lout, ld, q, d, l, vars, dx, ls, fint, lc;
ff := eval(convert( f, tan));] # convert trigs to tan
si := select(proc(d) diff(d, x) <> 0 end, indets( ff ));
si := select(proc(d) diff(d, x) <> 0 end, indets(map(diff, si, x)))
union si;
li := [op(si)]; # list of terms in integrand and its derivative
lin := [seq(d = ‘tools/genglobal‘(x), d = lin)]; # substitution terms –> indets
lout := [seq(rhs(d) = lhs(d), d = lin)]; # substitution indets –> terms
ld := subs(lin, map(dif f, li, x)); # derivatives of all the terms
q := lcm(seq(denom(d), d = ld)); # denominator of the total derivation
l := [seq(normal(q ∗ d),d = ld)]; # q ∗ derivatives of all the terms
vars := map(lhs, lout);
dx := totalDerivation(vars, l); # vector field dx = q ∗ d/dx
ls := [seq(getSpecial(d, lin), d = li)]; # list of known Darboux for dx
fint := subs(lout, pmIntegrate(subs(lin, ff ), dx, q, vars, ls));
lc := select(proc(d) convert(d, string)[1] =" –"; end, indets(fint, name));
subs({seq(d = 0, d = lc minus si)}, fint);
end;
pmIntegrate in Mathematica:
Clear[pmIntegrate];
pmIntegrate[ f–, lv–List, ld–List, q–, ls–: {}, ext–: 0] :=
Module[{splq, s, df, spl, cden, dg, x, monomials, cand, lunk, sol, i, AA},
DRPrint[“Visit pmIntegrate.”];
splq = splitFactor[q, lv, ld];
s = First[splq];
Scan[If [Last[#], s = s ∗ First[#]]&, ls];

PROGRAMMING AND COMPUTER SOFTWARE Vol. 35 No. 2 2009


ON MATHEMATICA PROGRAM FOR “POOR MAN’S INTEGRATOR” 65

x = First[lv];
df = Denominator[f];
spl = splitFactor[df, lv, ld];
cden = s ∗ First[spl] ∗ deflation[Last[spl], lv, ld];
dg = 1 + totalDeg[s, lv] +
Max[totalDeg[Numerator[f], lv], totalDeg[Denominator[f], lv]];
monomials = enumerateMonoms[lv, dg];
DRPrint[“There are”, Length[lv],
“new variables in the integrand and the guess bound for deg is”, dg,
“therefore the number of monomials is”, Length[monomials], “.”];

If [Length[monomials] > 800,


DRPrint[“\n Since the number of monomials is bigger than 800, then
'pmint' failed. It is possible that the integral is doable,”];
DRPrint[“but it will require too much time. The bound 800 can be
changed to a smaller one''];
Return[INT[f]]];
cand = Total[Table[AA[i] ∗ monomials[[i]],
{i, Length[monomials]}]]/cden;
lunk = Table[AA[i], {i, Length[monomials]}];
sol = tryIntegral[f, lv, ld, q, cand, lunk,
First[spl], (∗ normal part of df ∗)
Last[spl], (∗ special part of df ∗)
Last[splq], (∗ special part of q ∗)
ls, ext];
If [First[sol], INT[f], Last[sol]] ]
pmIntegrate in Maple:
pmIntegrate := proc(f, d, q, vars)
local ls, splq, s, ff, df, spl, cden, dg, monomials, cand, lunk, sol, i;
if nargs = 5 then ls := args[5]; else ls := []; fi;
splq := splitFactor(q, d);
s := splq[1];
for i to nops(ls) do if ls[i][2] then s := s * ls[i][1]; fi; od;
ff := normal(f); df := denom(ff); spl := splitFactor(df, d);
cden := s ∗ spl[1] ∗ deflation(spl[2], d);
dg := 1 + degree(s) + max(degree(numer(ff)), degree(denom(ff)));
monomials := [op(enumerateMonoms(vars, dg))];
cand := add('–A'[i] ∗ monomials[i], i = 1..nops(monomials))/cden;
lunk := {seq('–A'[i],i = 1..nops(monomials))};
sol := tryIntegral(f, d, q, vars, cand, lunk,
spl[1], spl[2], splq[1], ls, 0);
if sol[1] then sol := tryIntegral(f, d, q, vars, cand, lunk,
spl[1], spl[2], splq[1], ls, I); fi;
if sol[1] then Int(f); else sol[2]; fi;
end;
tryIntegral in Mathematica:
Clear[tryIntegral];
tryIntegral[f–, lv–List, ld–List, q–, cand–, lunk–, l1–, l2–, l3–, ls–, k–] :=
(∗ In this application the “k” is a variable or variables to adjoint ∗)

PROGRAMMING AND COMPUTER SOFTWARE Vol. 35 No. 2 2009


66 KRAGLER

Module[{candlog, p, candidate, i, sol, DD, BB, lu, dens},


DRPrint[“Visit tryIntegral.”];
DD = totalDerivation[lv, ld];
candlog = Union[myFactors[l1, k], myFactors[l2, k],
myFactors[l3, k], First /@ ls];
candidate = cand + Total[Table[BB[i]Log[candlog[[i]]],
{i, Length[candlog]}]];
lu = Union[lunk, Table[BB[i], {i, Length[candlog]}]];
DRPrint[“Applying 'funky way' of Together…”];
sol = totalDerivation[lv, Together[ld/q]];
{sol, dens} = Reap[Collect[f – sol[candidate], Alternatives @@ lu,
With[{tmp = Together[#]}, Sow[Denominator[tmp]]; tmp]&] ];
dens = PolynomialLCM @@ Flatten[dens];
DRPrint[“Applying Collect…”];

sol = Collect[sol, Alternatives @@ lu, Together [dens ∗ #]&];


sol = DeleteCases[PolyCoeffs[sol, lv], 0];
DRPrint[“Applying Outer…”];
dens = Outer[D, sol, lu];
DRPrint[“Solving linear equation with a”,
First[Dimensions[dens]], “x”,
Last[Dimensions[dens]], “matrix.”];

sol = Quiet[LinearSolve[dens, –sol /. Thread[lu 0] ] ];


If [Head[sol] === LinearSolve, sol = {}];
If [sol =! = {}, sol = Thread[lu sol]];
{sol === {}, (candidate /. sol) /. Thread[lu 0]} ]
tryIntegral in Maple:
tryIntegral := proc( f, d, q, vars, cand, lunk, l1, l2, l3, ls, K)
local candlog, p, candidate, i, sol;
candlog := [op({myfactors(l1, K), myfactors(l2, K), myfactors(l3, K)}
union {seq(p[1], p = ls)})];
candidate := cand + add('B'[i] ∗ log(candlog[i]),
i = 1..nops(candlog));
sol := solve({coeffs(numer(normal(f – d(candidate)/q)), {op(vars)})},
lunk union {seq('B'[i], i = 1..nops(candlog)) });
[evalb(sol = NULL), subs(sol, candidate)];
end;
getSpecial in Mathematica (constructs the known Darboux polynomials):
getSpecial[f–an, ru–] := {1 + (f /. ruˆ2, False};
getSpecial[f Tanh, ru–] := With[{ff = f /. ru}, Sequence @@ {{1 + ff, False},
{1 – ff, False}} ];
getSpecial[f–ProductLog, ru–] := {f /. ru, True};
getSpecial[–] := Null;
getSpecial in Maple (returns known Darboux polynomials):
getSpecial := proc(f, l) local p;
p := op(0, f);
if p = 'tan'then [1 + subs(l, f)ˆ2, false];
elif p = 'tanh' then [1 + subs(l, f), false], [1 – subs(l, f), false];

PROGRAMMING AND COMPUTER SOFTWARE Vol. 35 No. 2 2009


ON MATHEMATICA PROGRAM FOR “POOR MAN’S INTEGRATOR” 67

elif p = 'LambertW' then [subs(l, f), true];


else NULL; fi;
end;
myFactors in Mathematica:
myFactors[p–, Algebraic] :=
Module[{f, var},
(var = Variables [#];
If[Length[var] == 1,
Apply[Sequence, (First[var] – (First[var] /.
{ToRules[Roots[# = 0, First[var]] ] })
)], #])& /@ myFactors[p, I] ];
myFactors[p–/; !NumericQ[p], 0] := Drop[First /@ FactorList[p], 1];
myFactors[p–?NumericQ, –] := {p};
myFactors[p–/; !NumericQ[p], extension–] :=
Drop[First /@ FactorList[p, Extension extension], 1];
myFactors in Maple:
myFactors := proc(p, K) local l, fact;
if K = 0 then l := factors(p); else l := factors(p, K); fi;
seq(fact[1], fact = l[2]);
end;
enumerateMonoms in Mathematica (Calculates all monomials in variables “lv” such that TOTAL deg is ≤
“deg”):
enumerateMonoms[{}, de–] := {1};
enumerateMonoms[lv–List, deg–] :=
Module[{i, v = Most[lv]},
Union[enumerateMonoms[v, deg],
Sequence @@ Table[Last[lv]ˆi ∗ enumerateMonoms[v, deg – i], {i, deg} ] ] ]
enumerateMonoms in Maple:
enumerateMonoms := proc(vars, d) local n, x, i, v, s, w;
n := nops(vars);
if n = 0 then {1}; else
x := vars[n];
v := [seq(vars[i], i = 1..n – 1)];
s := enumerateMonoms(v, d);
for i to d do s := s union {seq(xˆi ∗ w, w =
enumerateMonoms(v, d – i))};
od; s;
fi;
splitFactor in Mathematica:
splitFactor[p–, lv–List, ldList] :=
Module[{theT, c, hn, hs, S, q, qn, qs, DD},
theT = mainVar[p, lv];
If [theT === $Failed, Return[{p, 1} ] ];
DD = totalDerivation[lv, ld];
{c, q} = PolyContentPP[p, theT];
{hn, hs} = splitFactor[c, lv, ld];
S = PolynomialQuotient[PolynomialGCD[q, DD[q]],
PolynomialGCD [q, D[q, theT]], theT];
If[Exponent[S, theT] == 0, Return[{hnp, hs} ] ];

PROGRAMMING AND COMPUTER SOFTWARE Vol. 35 No. 2 2009


68 KRAGLER

{qn, qs} = splitFactor[PolynomialQuotient[q, S, theT], lv, ld];


{hn qn, S hs qs} ]
splitFactor in Maple:
splitFactor := proc(p, d) local si, x, c, q, spl, s, splh;
si := select(proc(z) d(z) <> 0 end, indets(p, name));
if si = {} then RETURN([1, p])fi;
x := si[1];
c := content(p, x, 'q');
spl := splitFactor(c, d);
s := normal(gcd(q, d(q))/gcd(q, diff(q, x)));
if degree(s) = 0 then RETURN([spl[1], q ∗ spl[2]]); fi;
splh := splitFactor(normal(q/s), d);
[spl[1] ∗ splh[1] ∗ s, spl[2] ∗ splh[2]];
end;
deflation in Mathematica (Calculate the deflation of p with respect to the “new derivation”):
deflation[p, lv–List, ld–List] :=
Module[{theT, c, q, DD},
theT = mainVar[p, lv];
If [theT === $ Failed, Return [p]];
DD = totalDerivation[lv, ld];
{c, q} = PolyContentPP[p, theT];
deflation[c, lv, ld] ∗ PolynomialGCD[q, DD[q, theT]] ]
deflation in Maple:
deflation := proc(p, d) local s i, x, c, q;
si := select(proc(z) d(z) <> 0 end, indets(p, name));
if si = {} then RETURN(p) fi;
x := si[1];
c := content(p, x,' q');
deflation(c, d) ∗ gcd(q, diff(q, x));
end;
(2) Conversion of trigonometric function to rational functions of tangent: TrigToTan, Derivative
TrigToTan in Mathematica:
Clear[TrigToTan, tan, exp];
TrigToTan[ee–] :=
Module[{ToTan, e = ee/. Sec[x–]ˆ2 1 + Tan[x]ˆ2},
ToTan[Sin[x–]] = With[{y = Together[x/2]}, 2 tan[y]/(1 + tan[y]ˆ2)];
ToTan[Cos[x–]] = With[{y = Together[x/2]}, (1 – tan[y]ˆ2)/(1 + tan[y]ˆ2)];
ToTan[Sec[x–]] = With[{y = Together[x/2]}, (1 + tan[y]ˆ2)/(1 – tan[y]ˆ2)];
ToTan[Sec[x–]ˆ2] := 1 + tan[x]ˆ2;
ToTan[Csc[x–]] = With[{y = Together[x/2]}, (1 + tan[y]ˆ2)/(2 tan[y])];
(∗ ToTan[Tan[x–]] = With[{y = Together[x/2]}, 2 tan[y]/(1 – tan[y]ˆ2)]; ∗)
ToTan[Tan[x–]] := tan[x];
ToTan[Cot[x–]] = With[{y = Together[x/2]}, (1 – tan[y]ˆ2)/(2 tan[y])];
e //. {x : (–Sin|–Cos|–Tan|–Cot|–Sec|–Csc) :> ToTan[x]} ]
In Maple there is a powerful built-in procedure convert(expr, form) which transforms expr into another form.
The function convert is used to convert an expression from one form to another. Some of the conversions are data-
type conversions, others are form or function conversions. For the latter one a set of optional arguments are given
to perform the conversion in different manners, e.g. convert(f,tan) which converts trigonometric functions into
expressions which involve only the function tan.

PROGRAMMING AND COMPUTER SOFTWARE Vol. 35 No. 2 2009


ON MATHEMATICA PROGRAM FOR “POOR MAN’S INTEGRATOR” 69

Derivative in Mathematica:
Derivative[1][tan] = Function[1 + tan[#]ˆ2];
Derivative[1][exp] = exp;
exp[a– + b–] := exp[a] exp[b];
exp[Log[x–]] := x;
This function provides an extension of the first derivatives of tan and exp with additional rules for the expo-
nential function.
(3) Other auxillary functions are: totalDerivation, PolyContentPP, PolyCoeffs, mainVar, myVariables, Ratio-
nalFunctionQ, td, totalDeg, SubSet.
totalDerivation in Mathematica:
totalDerivation[lvList, ldList] :=
Function[u, ld . Table[D[u, k], {k, lv}], Listable]
totalDerivation in Maple:
totalDerivation := proc(lv, ld)
proc( f ) local fp, i;
fp := 0; for i to nops(ld) do fp := fp + ld[i] ∗ diff (f, lv[i]); od;
fp;
end;
end;
PolyContentPP in Mathematica:
PolyContentPP[A–, t–] :=
With[{q = FactorTermsList[A, t]},
{Times @@ Most[q], Last[q]} ]
PolyCoeffs in Mathematica:
PolyCoeffs[p–,vars–] :=
Block[{t},
Union @ Flatten[Coef ficientArrays[p, vars]/.
t–SparseArray :> ArrayRules[t][[All, 2]]] ]
mainVar in Mathematica:
mainVar[p–, lv–List] :=
Catch[Scan[If[Exponent[p, #1] > 0, Throw[#1]]&, Reverse[lv]];
$Failed ]
myVariables in Mathematica:
myVariables[e : (–Plus|–Times)] :=
Union[Flatten[myV ariables /@ Apply [List, e]]];
myVariables[HoldPattern[Power][e–, a–Integer]] := myVariables[e];
myVariables[e– /; NumericQ[e]] := {};
myVariables[HoldPattern [Power][x–, pPlus]] :=
Union[Flatten[myV ariables [xˆApply [List, p]]]];
myVariables[e–] := {e};
SetAttributes[myVariables, {Listable}];
RationalFunctionQ in Mathematica:
RationalFunctionQ[expr : (Plus|–Times), x–] :=
Fold[Function[{pr, el}, pr && RationalFunctionQ[el, x]], True,
List @@ expr];
RationalFunctionQ[HoldPattern[Power][e–, a–Integer], x–] :=
RationalFunctionQ[e, x];
RationalFunctionQ[x_, x–] := True;
RationalFunctionQ[expr : Except[Times]–Plus], x–List] :=
Fold[#1 && (expr === #2 || FreeQ[expr, #2])&, True, x];

PROGRAMMING AND COMPUTER SOFTWARE Vol. 35 No. 2 2009


70 KRAGLER

RationalFunctionQ[expr : Except[–Times|–Plus], x : Except[–List]] :=


FreeQ[expr, x];
td in Mathematica:
td[mono–] := Total[Exponent[mono, myVariables[mono]]];
td[mono–, vars–] := Total[Exponent[mono, vars]];
totalDeg in Mathematica:
totalDeg[poly–Plus] := Max[td/@ List @@ poly];
totalDeg[poly–] := td[poly];
totalDeg[poly–Plus, vars–] := Max[td[#, vars]& /@ List @@ poly];
totalDeg[poly–vars–] := td[poly, vars];
SubSet in Mathematica:
SubSet[A–, B–] :=
Module[{a = Tally[A][[All, 1]], b = Tally[B][[All, 1]]},
Length[Intersection[a, b]] == Length[a] ];
(4) Building monomials extension: ToIndetsAndDerivation, ToTerms, denD
ToIndetsAndDerivation in Mathematica:
Clear[ToIndetsAndDerivation];
ToIndetsAndDerivation[f–, x–, t–] :=
Module[{vars, terms, deriv, newF, limitList, list, F, dterms, count = 0},
F = f //. {Exp exp};
terms = Select[myVariables[F], PolynomialQ[#, x] == False &];
dterms = Union[Select[Flatten[myVariables[D[terms, x]]],
(PolynomialQ[#, x] == False &)], terms];
While[Not[SubSet[dterms, terms]] && count < 15,
terms = Union[terms, dterms];
dterms = Union[Select[Flatten[myVariables[D[terms, x]]],
(PolynomialQ[#,x] == False &)],terms];
count = count + 1 ];
If [count > 15, Return[$Failed] ];
deriv = D[terms, x];
vars = Map[t, Range[Length[terms]] ];
limitList = Thread[terms –> vars];
newF = F /. limitList;
deriv = deriv /. limitList /.
{HoldPattern[Power]a–, bPlus] :>
Times @@ ((aˆApply[List, b]) /. limitList)};
If [True || Fold[#1 && RationalFunctionQ[#2, Join[{x},vars] ]&,
True, deriv],
{newF, terms, Join[{x}, vars], Join[{1}, deriv]}, %Failed]
(∗ Else ∗)
] //. {exp[y–] :> Exp[y]};

PROGRAMMING AND COMPUTER SOFTWARE Vol. 35 No. 2 2009


ON MATHEMATICA PROGRAM FOR “POOR MAN’S INTEGRATOR” 71

Here f is the integrand, x the variable of integration —to adjoin the variables in order to calculate the
and t is a dummy variable whose purpose is to name the integral. This information is needed when changing
new transcendental variables as t1, t2, …. The output of back the result in terms of the original variables.
the procedure ToIndetsAndDerivation is: —The last two elements of the output are of the
form {x, t1, t2, …} and {1, D[t1], D[t2], …}. These ele-
—the integrand f in terms of new variables, ments are needed to obtain totalDerivation.

ToTerms in Mathematica:
ToTerms[F–, terms–List, vars–List] := F /. Thread[vars –> terms]

It is assumed that “derivations” are the list of deriv- given at the time, when denD. In particular, it takes the
atives of transcendental variables ti . This list should be last element of ToIndetsAndDerivation[f, x, t].
denD in Mathematica:
denD[derivations–List] := PolynomialLCM @@ Denominator[Together[derivations]];

Finally, some auxillary definitions are needed for The inverse of the function f(w) = weW is called the
simplification of the expressions etc. Omega function. The Wright Omega function is
(5) Transformations: LambertRule, log2ArctanRule, defined in terms of the Lambert W function with argu-
pureFctConversion ment Ex.
Because Lambert’s W function is implemented in The Omega in Mathematica is defined as:
Mathematica as the function ProductLog, the following Ω[x–] := LambertW[Ex]
substitution rule is used.
In order to recast the logarithmic representation of
LambertRule in Mathematica: the arctan function into the usual representation a
LambertRule = {ProductLog[z–] –> lambertW[z]}; sequence of replacement rules has to be defined.

log2ArctanRule in Mathematica:
log2ArctanRule[result–] :=
((( (result /. {Log[a–] – Log[b–] –> Log[a/b]}) /.
{Log[(–I + z–)/(I + z–)] –> Log[–((1 + I ∗ z)/(1 – I ∗ z))] }) /.
{Log[–c–] –> Log[c] + Log[–1]}) /.
{Log[(1 + I ∗ z–)/(1 – I ∗ z–)] –> 2I ∗ ArcTan[z]}
) // Simplify

Furthermore, the following rule achieves the con- function representation with Function[par, body] and
version between the two forms of Mathematica's pure body[#]&.

pureFctConversion in Mathematica:
pureFctConversion =
Literal[Function[par–, body–]] /; FreeQ[body, #] :>
Unevaluated[Function[body] /. par #];
Finally, DRPrint is used for debugging:
DRPrint[w–––] /; ($DebugRisch === True) := Print[w];

3. DEMONSTRATION OF PMINT (b) Rational functions;


In order to demonstrate the potential of the heuristic (c) Trigonometric rational functions;
parallel integrator pmint a selection of examples will (d) Transcendental functions of the form Log – Exp;
given. There are several categories such as: (e) Liouvillian special functions (Error function);
(a) Elementary (non-rational and non-rational trigo- (f) Airy functions;
nometric) functions; (g) Bessel functions;

PROGRAMMING AND COMPUTER SOFTWARE Vol. 35 No. 2 2009


72 KRAGLER

(h) Lambert W function; (a) Elementary functions distinct from the conven-
tional rational functions and from rational expressions
(i) Wright Omega function. of trigonometric functions
As will be shown below some examples involving In the case of elementary functions such as (non-
Airy, Bessel, Lambert W, Wright Omega and Whit- rational) polynomials involving powers of xn or combi-
nations of trigonometric functions pmint reproduces the
taker W functions where pmint gives a result cannot be same results as found with the built-in integrators of
dealt with either by Maple's built-in integrator int Mathematica or Maple. Generally, there arise some
or/and by Mathematica 's built-in procedure Integrate. problems to cast the results in the same form. Thus, as
If available the results of the built-in integrators shown by the subsequent example it needs some addi-
obtained by Maple and/or Mathematica will be com- tional efforts, i.e. a sequence of Mathematica com-
pared with the result of pmint. mands, until the result looks the same.

|| res1 = pmint[x2 Csc[x3] Sec[x3], x]


⇒ –(1/3) Log[–1 + Tan[x3/2]] + 1/3 Log[Tan[x3/2]] – 1/3 Log[1 + Tan[x3/2]]
The result which looks quite complicated can be simplified by a sequence of transformation rules:
|| res11 = (((res1 // TrigFactor) //. {Log[aJ] – Log[b–] Log[a/b]}
// FullSimplify) /. {Log[(–(1/2)) ∗ a–] –Log[–2] + Log[a]} // Expand);
res11 //. {(c = Select[res11, FreeQ[#, x]&]) C1}
⇒ 1/3 Log[Tan[x3]] + C1

and agrees with the result of Integrate: || D[res1 – res2, x] // Simplify


|| res2 = Integrate[x2 Csc[x3] Sec[x3], x] // Simplify ⇒0
(b) Rational functions
up to an complex integration constant C1 = –(1/3)
(Log[2] + I ∗ π) as can be easily proofed by differenti- Handling rational polynomial functions seems to be
ating both results of both expressions: no problem for pmint

7 4 2
x – 24x – 4x + 8x – 8
|| pmint ---------------------------------------------------------
8 6 4 2
-, x // Simplify // Apart
x + 6x + 12x + 8x
2 3
4 + 6x + 8x + 3x
⇒ --------------------------------------------
2 2
+ Log [ x ]
x(2 + x )
1
However, the obviously simple integration pmint --------------2, x with result ArcTan[x] only works with extension
1+x
to complex numbers by the additional option of pmint, i.e. Extension Algebraic
1
|| res1 = pmint --------------2 , x, Extension Algebraic // PowerExpand // Together
1+x
⇒ –(1/2) I (Log[–I + x] – Log[I + x])

With a sequence of replacement rules which is the result of Integrate up to an integration con-
log2ArctanRule the logarithmic terms are finally casted stant –I/2Log[–1] = π/2.
into the function ArcTan
(c) Rational expressions in trigonometric functions
|| res1 // log2ArctanRule and powers of the integration variable
⇒ ArcTan[x] + π/2 pmint can handle such integrands.

PROGRAMMING AND COMPUTER SOFTWARE Vol. 35 No. 2 2009


ON MATHEMATICA PROGRAM FOR “POOR MAN’S INTEGRATOR” 73

However, pmint cannot cope with the following sim- 2368081x


13
276580459x
15

ple example, because Cos [ x ] has no representation – ------------------------------------- – -----------------------------------------------


398529331200 167382319104000
in terms of transcendentals ti . The result of Integrate is coincides with the series expansion of result of
x x
an elliptic integral of the second kind 2EllipticE ---, 2 . 2EllipticE ---, 2 .
2 2
But, if the series expansion of the integrand, i.e. The straightforward calculation of the integral
series[ Cos [ x ] , x, 0, 14] // Normal is used pmint can 1
pmint -------------------------, x fails because it requires an
deals with the series expansion to arbitrary order. The 2 + Sin [ x ]
resulting power series extension to rationals for factorization. Therefore,
3 5 7 9 11 with the additional option Extension Algebraic
x x 19x 559x 2651x which is passed to FactorList the procedure pmint
x – ------ – --------- – --------------- – ---------------------- – ----------------------------
12 480 40320 5806080 116121600 finds a solution

|| res1 = pmint [ 1/ ( 2 + Sin [ x ] ), x, Extension Algebraic ]


( – 1 ) Log [ ( – 1 ) + Tan [ x/2 ] ] ( – 1 ) Log [ – ( – 1 ) + Tan [ x/2 ] ]
2/3 1/3 2/3 1/3
⇒ ----------------------------------------------------------------------------- – ---------------------------------------------------------------------------------
-
1 + ( –1 ) 1 + ( –1 )
1/3 1/3

Alternatively, the Extension (–1)1/3, could have tor first the roots (–1), i.e. {(–1)1/3, (–1)2/3} have to be
been chosen but this choice would require some kind of
1 i 3
preknowledge of the result; therefore the option Exten- casted into ± --- + --------- by means of the substitution rule
sion Algebraic is more general. In order to obtain 2 2
the result in the same form given by the built-in integra- algNumbRule:

|| algNumbRule = Thread[{(–1)1/3, (–1)2/3} ComplexExpand[{(–1)1/3, (–1)2/3}] ]


|| res1a = (res1 /. algNumbRule // FullSimplify) /. {Log[arg–] – Log[2 arg]} //
|| Simplify
With the help of the subsequent rewrite rule

|| (((res1a/. {1 + 2 Tan[x/2] – 3 z, –1 – 2 Tan[x/2] – 3 z} // Simplify) /.


|| {Log[a–] – Log[b–] Log[a/b]}) /.
|| {Log[(I – z)/(I + z)] –(Log[1 – I ∗ z] – Log[1 + I ∗ z]) } // ExpToTrig) /.

|| {z – (1 + 2 Tan[x/2])/ 3 }

the result finally agrees with that of Integrate. The straightforward calculation fails but the calcula-
tion is doable if the integrand is casted into a rational poly-
2 1 + 2Tan [ x/2 ] nomial using the substitution Tan[x/2] z. Because of
⇒ ------- ArcTan ------------------------------------ this substitution the transformed integrand fct(z) has to be
3 3
divided by an additional factor (1 + z2)/2. Hence using
Another intricate example is Apart and ComplexExpand the integrand becomes f1 =
2
1 4 – 4z 2 7 + 2z – z
----------- + --------------------2 + -------------2 and f2 = -----------------------------------------
-.
( Cos [ x ] – Sin [ x ] )Sin [ x ] 1 + z ( 1 + z2 ) 1+z – 1 – z – 3z + z
2 3
|| pmint --------------------------------------------------------------, x
1 + Cot [ x ] + Sin [ x ] Now,

PROGRAMMING AND COMPUTER SOFTWARE Vol. 35 No. 2 2009


74 KRAGLER

|| F1 = pmint[f1, z, Extension Algebraic] //. {z Tan[x/2]} // Simplify


⇒ 1 + Cos[x] – 2I Log[–I + Tan[x/2]] + 2I Log[I + Tan[x/2]]
+ Log[1 + Tan[x/2]] + Sin[x]
The result of the second part F2 is quite lengthy
|| F2 = ((pmint [f 2, z, Extension Algebraic] // Simplify) //. {z Tan[x/2]})
|| F2 // Short[#, 4]&
⇒ (22/3(〈〈1〉〉)Log[–1 + 1/6(1 + I 3 )(54 – 6 33 )1/3 + (1 – I 3 )

(9 + 〈〈1〉〉)1/3/62/3 + Tan[x/2]])/(–264 21/3 35/6 11 + 〈〈4〉〉

+ (9 – 33 )2/3(–35/6(13I + 3 11 )(2(9 + 33 ))1/3 + (39 + 3I 11 )〈〈1〉〉

〈 〈 1〉 〉
+ 6(9 + 3I 3 + I 11 + 33 ))) + --------------------------
-
3 ( 〈 〈 1〉 〉 )
1/6

( 〈 〈 1〉 〉 ) 〈 〈 1〉 〉 4 ( 〈 〈 1〉 〉 )
+ --------------------------------
- + ----------------------
6
〈 〈 1〉 〉
( 〈 〈 1〉 〉 ) 〈 〈 1〉 〉

but it is an explicit solution. Yet, interesting is the comparison with Integrate. The straightforward application
of Integrate leads to a result much shorter which, however, is given as an implicit representation in terms of Math-
ematica's RootSum

|| K = Integrate[(Sin[x]Cos[x] – Sin[x]2)/(1 + Sin[x] + Cot[x]), x] // FullSimplify

⇒ 2x + Cox[x] + Log[Sec[x/4]2] + Log[Cos[x/2] + Sin[x/2]] + Sin[x]

+ 8 RootSum[–7 + 296 #1 + 704 #12 + 5632 #13&,

Log[–25 + 2(9 + 88 #1(–1 + 8 #1))Tan[x/4] + 25Tan[x/4]2] #1&]

Numerical approximations of the both results of K and F1 + F2 agree up to integr ation constants.
(d) Transcendental functions of the form Log – Exp
Here is an example where pmint gives a solution

– 2e + 2xe + 3 3Log [ – 1 + x ]
2x 2r 2
|| pmint ------------------------------------------------------------------------------------
-, x
( – 1 + x ) ( e + 3Log [ – 1 + x ] )
2x 3

⇒ Log[e2x + 3 Log[–1 + x]3]

but Integrate fails.


(e) Liouvillian special functions
Liouvillian special functions are rational polynomials containing powers of the error functions erf(x)) together
2
–x
with e :

Exp [ – x ]Erf [ x ]
2
|| pmint ----------------------------------------------------------------------------
-, x
Erf [ x ] – Erf [ x ] – Erf [ x ] + 1
3 2

π
⇒ ------- ⎛ – ------------------------------- + Log [ – 1 + Erf [ x ] ] – Log [ 1 + Erf [ x ] ]⎞
2
8 ⎝ – 1 + Erf [ x ] ⎠

PROGRAMMING AND COMPUTER SOFTWARE Vol. 35 No. 2 2009


ON MATHEMATICA PROGRAM FOR “POOR MAN’S INTEGRATOR” 75

The result of integration is the same for pmint and the integrators built into Maple and Mathematica. However,
2 2
–x –x
for a slightly more complicated case where the numerator e Erf[x] is replaced by e Erf[x ex] neither pmint,
nor the implemented integrators of Maple or Mathematica can deal with this case.
(f) Airy functions
For the subsequent examples which involve AiryAi and AiryAiPrime functions pmint is able to find solutions
while Integrate fails in all cases.
|| pmint[x AiryAiPrime[x] Cos[AiryAi[x]] + Sin[AiryAi[x]], x]
2x Tan [ AiryAi [ x ]/2 ]
⇒ ---------------------------------------------------------2
1 + Tan [ AiryAi [ x ]/2 ]
Here is another integral involving combinations of AiryAi, AiryAiPrime, Log and ArcTan:
AiryAi [ x ] ArcTan [ x ] AiryAi [ x ] Log [ x ]
|| pmint -------------------------------------------------------- + ---------------------------------------------
2
-
x 1+x
|| +AiryAiPrime[x] ArcTan[x] Log[x], x] // Simplify
⇒ AiryAi[x] ArcTan[x] Log[x]
Another integral which pmint can solve but not Integrate is:

AiryAiPrime [ x ] 2x AiryAi [ x ] AiryPrime [ x ]


2
|| pmint ----------------------------------------- -, x
- – -------------------------------------------------------------------------
AiryAi [ x ]
2 2 2
AiryAi [ x ]
AiryAi [ x ]
⇒ ---------------------------
AiryAi [ x ]
2

Finally
AiryAi [ x ] AiryAi [ x ]
AiryAiPrime [ x ] e ( 1 + 3 AiryAi [ x ] AiryAiPrime [ x ] )
2
e
|| pmint --------------------------------------------------------------- -, x
- – ------------------------------------------------------------------------------------------------------------
x + AiryAi [ x ]
3 3 2
( x + AiryAi [ x ] )
AiryAi [ x ] AiryAi [ x ]
AiryAi [ x ]
3
e x+e
⇒ ------------------------------------------------------------------------------
3 2
( x + AiryAi [ x ] )
In order to obtain this result the CPU time (with BesselJ [ n + 1, x ]
respect to the computer being used) is quite long. || pmint -------------------------------------------, x
BesselJ [ n, x ]
(g) Bessel functions
A straightforward integration for the quotient of The reason why pmint cannot directly cope with this
BesselJ [ n + 1, x ] integrand and hangs up is that every differentiation
Bessel functions ------------------------------------------- fails both for
BesselJ [ n, x ] introduces new orders of BesselJ functions in this spe-
pmint and Integrate. cific case

|| NestList[D[#, x]&, BesselJ[n, x], 4] // Simplify //


|| TraditionalForm // ColumnForm
⇒ Jn(x)
1/2(Jn – 1(x) – Jn + 1(x))
1/4(Jn – 2(x) – 2Jn(x) + Jn + 2(x))
1/8(Jn – 3(x) – 3Jn – 1(x) + 3Jn + 1(x) – Jn – 3(x))
1/16(Jn – 4(x) – 4Jn – 2(x) + 6Jn(x) – 4Jn – 2(x) + Jn + 4(x))
In order to circumvent this feature of generating instead a recurrence relation for Bessel functions
additional orders of BesselJ functions one applies according to [12] to obtain a simple differentiation rule.

PROGRAMMING AND COMPUTER SOFTWARE Vol. 35 No. 2 2009


76 KRAGLER

|| D[{BesselJ[n, x], BesselJ[n + 1, x]}, x] //


|| SimplifyiRecurrenceShift[#, TargetFunctions BesselJ[n, x]]& //
|| Simplify /. {BesselJ[n, x] t1, BesselJ[n + 1, x] t2}

⎧ n t1 ( n + 1 ) t2 ⎫
⇒ ⎨ – t2 + ----------, t1 – ------------------------ ⎬
⎩ x x ⎭
This result serves as a guidance for the definition of t1' and t2' as “pure” functions

n t1 [ z ]
|| {Derivative[1][t1] = Function z, ----------------- – t2 [ z ] /. pureFctConversion,
z

( n + 1 ) t2 [ z ]
|| Derivative[1][t2] = Function[z, t1[z] – z, t1 [ z ] – ------------------------------- /. pureFctConversion}
z

⎧ n t1 [ #1 ] ( n + 1 ) t2 [ #1 ] ⎫
⇒ ⎨ --------------------- – t2 [ #1 ]$, t1 [ #1 ] – ----------------------------------- $ ⎬
⎩ #1 #1 ⎭

The great advantage of pmint is that one only needs to know the derivative of a function (which needs to be in
the monomial extension of transcendental functions) in order to be able to perform the integration. It is assumed
that the differential is closed on that extension. Therefore, because the derivative of
|| D[nLog[x] – Log[t1[x]], x] // Simplify

t2 [ x ]
⇒ -------------
t1 [ x ]

t2 [ x ]
turns out to be ------------- , pmint can now calculate the integral
t1 [ x ]

t2 [ x ]
|| pmint -------------, x /. {t1[x] BesselJ[n, x], t2[x] BesselJ[n + 1, x]}
t1 [ x ]

⇒ n Log[x] – Log[BesselJ[n, x]]

The same strategy can also be used for the calcula- (h) Lambert W function
tion of
In Mathematica the Lambert W function is identical
x BesselJ [ n + 1, x ] – n Bessel [ n, x ] with the function ProductLog. Hence, either LambertW
|| pmint -------------------------------------------------------------------------------------------, x or ProductLog can be used. The function w = Product-
x Log[z] is the principal solution for z = w ew. (The k-th
where a direct calculation again fails but with the solution is denoted by ProductLog[k, z]). The solutions
help of the auxillary functions t1 and t2 and their first are ordered according to their imaginary parts. For z >
derivatives the integration gives −1/e ProductLog[z] is real. Moreover, ProductLog[z]
dw w
x t2 [ x ] – t1 [ x ] satisfies the differential equation ------- = -------------------- .
|| pmint -------------------------------------, x dz z ( 1 + w )
x
Both pmint and Integrate can handle the following
⇒ n BesselJ [ n, x ] integral:

PROGRAMMING AND COMPUTER SOFTWARE Vol. 35 No. 2 2009


ON MATHEMATICA PROGRAM FOR “POOR MAN’S INTEGRATOR” 77

|| pmint[Sin[ProductLog[x]], x] // FullSimplify
1
⇒ --- (–x Cos[ProductLog[x]] + (eProductLog[x] + x) Sin[ProductLog[x]])
2
For the next example
2ProductLog [ x ] + ProductLog [ x ]
2
-, x
|| pmint -----------------------------------------------------------------------------------------------------------------
( 1 + ProductLog [ x ] ) ( 1 + x ProductLog [ x ]
2 2

a straightforward integration with pmint does not work. Because pmint has the default
OptionsPattern[{Extension 0}],
this example fails due to the fact that certain polynomials cannot be factorized. However, it suffices to enlarge
the extension to Extension I in order to obtain the solution.
2ProductLog [ x ] + ProductLog [ x ]
2
|| pmint -----------------------------------------------------------------------------------------------------------------
- , x, Extension I] // Simplify
( 1 + ProductLog [ x ] ) ( 1 + x ProductLog [ x ]
2 2

⇒ (I/2)(Log[–I + x ProductLog[x]] – Log[I + x ProductLog[x]])


With the help of the transformation rule log2ArctanRule the logarithms are finally simplified to
⇒ π/2 + ArcTan[x ProductLog[x]]
The following integral can only be handled with pmint whereas Integrate fails.
|| pmint[(2 LambertW[x2] Cos[LambertW[x2]] (ax + LambertW[x2])
|| + a x(1 + LambertW[x2]) + 2 LambertW[x2])/((1 + LambertW[x2])
|| (a x + LambertW[x2])x), x] // FullSimplify
⇒ Log[a x + ProductLog[x2]] + Sin[ProductLog[x2]]
(i) Wright Omega-function
The Wright Omega function is defined in terms of the Lambert W function with argument Ex:
|| Ω[x–] := LambertW[Exp[x]]
Again, pmint gives a solution whereas Integrate fails:
|| pmint[Ω[x], x] // Simplify
⇒ –1 + ProductLog[Ex] + 1/2 ProductLog[Ex]2
This applies to the following example too:
( 1 + Ω [ x ] ( 2 + Cos [ Ω [ x ] ] ( x + Ω [ x ] ) ) )
|| pmint ------------------------------------------------------------------------------------------------, x // FullSimplify
(1 + Ω[ x ])( x + Ω[ x ])
⇒ Log [ x + ProductLog [ E ] ] + Sin [ ProductLog [ E ] ]
x x

Again, the built-in Mathematica integrator Integrate cannot not find a solution whereas pmint does.

4. CONCLUSIONS intended to be a replacement for existing integrators—


It has to be emphasized that the Poor Man’s Integra- rather an extension, or a cheap and powerful alternative
tor (pmint) is not intended to be as complete as the large for any computer algebra project.
integrators based on the Risch algorithm built into
Maple and Mathematica. The very small size of pmint
REFERENCES
makes it easy to port this procedure to any computer
algebra system or library capable of factoring multi- 1. Abramov, S.A., In Memory of Manuel Bronstein, Pro-
variate polynomials. Because it is applicable to special gramming and Computer Software, 2006, vol. 32, no. 1,
functions (such as Airy, Bessel, Lambert W and Wright pp. 56–58.
Omega functions etc.), the Poor Man’s Integrator is 2. Bronstein, M., Parallel Integration (Extended Abstract),
able to compute integrals some of which cannot be han- Programming and Computer Software, 2006, vol. 32,
dled by existing integrators. Therefore, pmint is not no. 1, pp. 59, 60.

PROGRAMMING AND COMPUTER SOFTWARE Vol. 35 No. 2 2009


78 KRAGLER

3. Norman, A.C. and Moore, P.M.A., Implementing the 8. Davenport, J.H., On the Parallel Risch Algorithm (III):
New Risch Integration Algorithm, Proc. the 4th Interna- Use of Tangents, SIGSAM Bulletin, 1982, vol. 16, pp. 3–6.
tional Colloquium on Advanced Computing Methods in
Theoretical Physics, 1977, pp. 99–110. 9. Davenport, J.H. and Trager, B.M., On the Parallel Risch
4. Harrington, S.H., A New Symbolic Integration System Algorithm (II), ACM Transactions on Mathematical
in Reduce, The Computer Journal, 1979, vol. 22, Software, 1985, no. 11, pp. 356–362.
pp. 127–131.
10. http://www-sop.inria.fr/cafe/Manuel.Bronstein/pmint/ind-
5. Fitch, J., User-Based Integration Software, Proc.
SYMSAC'81, ACM Press, 1981, pp. 245–248. ex.html.
6. Geddes, K. and Stefanus, L., On the Risch-Norman Inte- 11. Bronstein, M., Symbolic Integration I. Transcendental
gration Method and Its Implementation in Maple, Proc. Functions, Berlin-Heidelberg: Springer-Verlag, 2nd ed.,
ISSAC'89, ACM Press, 1989, pp. 212–217. 2005.
7. Davenport, J.H., On the Parallel Risch Algorithm (I).
Proceedings of EUROCAM'82, LNCS, Springer, 1982, 12. Pavlyk, A., WRI, November 2007, Private communica-
vol. 144, pp. 144–157. tion.

PROGRAMMING AND COMPUTER SOFTWARE Vol. 35 No. 2 2009

You might also like