1"""Most of these tests come from the examples in Bronstein's book."""
2from sympy import (Poly, I, S, Function, log, symbols, exp, tan, sqrt,
3    Symbol, Lambda, sin, Ne, Piecewise, factor, expand_log, cancel,
4    diff, pi, atan, Rational)
5from sympy.integrals.risch import (gcdex_diophantine, frac_in, as_poly_1t,
6    derivation, splitfactor, splitfactor_sqf, canonical_representation,
7    hermite_reduce, polynomial_reduce, residue_reduce, residue_reduce_to_basic,
8    integrate_primitive, integrate_hyperexponential_polynomial,
9    integrate_hyperexponential, integrate_hypertangent_polynomial,
10    integrate_nonlinear_no_specials, integer_powers, DifferentialExtension,
11    risch_integrate, DecrementLevel, NonElementaryIntegral, recognize_log_derivative,
12    recognize_derivative, laurent_series)
13from sympy.testing.pytest import raises
14
15from sympy.abc import x, t, nu, z, a, y
16t0, t1, t2 = symbols('t:3')
17i = Symbol('i')
18
19def test_gcdex_diophantine():
20    assert gcdex_diophantine(Poly(x**4 - 2*x**3 - 6*x**2 + 12*x + 15),
21    Poly(x**3 + x**2 - 4*x - 4), Poly(x**2 - 1)) == \
22        (Poly((-x**2 + 4*x - 3)/5), Poly((x**3 - 7*x**2 + 16*x - 10)/5))
23    assert gcdex_diophantine(Poly(x**3 + 6*x + 7), Poly(x**2 + 3*x + 2), Poly(x + 1)) == \
24        (Poly(1/13, x, domain='QQ'), Poly(-1/13*x + 3/13, x, domain='QQ'))
25
26
27def test_frac_in():
28    assert frac_in(Poly((x + 1)/x*t, t), x) == \
29        (Poly(t*x + t, x), Poly(x, x))
30    assert frac_in((x + 1)/x*t, x) == \
31        (Poly(t*x + t, x), Poly(x, x))
32    assert frac_in((Poly((x + 1)/x*t, t), Poly(t + 1, t)), x) == \
33        (Poly(t*x + t, x), Poly((1 + t)*x, x))
34    raises(ValueError, lambda: frac_in((x + 1)/log(x)*t, x))
35    assert frac_in(Poly((2 + 2*x + x*(1 + x))/(1 + x)**2, t), x, cancel=True) == \
36        (Poly(x + 2, x), Poly(x + 1, x))
37
38
39def test_as_poly_1t():
40    assert as_poly_1t(2/t + t, t, z) in [
41        Poly(t + 2*z, t, z), Poly(t + 2*z, z, t)]
42    assert as_poly_1t(2/t + 3/t**2, t, z) in [
43        Poly(2*z + 3*z**2, t, z), Poly(2*z + 3*z**2, z, t)]
44    assert as_poly_1t(2/((exp(2) + 1)*t), t, z) in [
45        Poly(2/(exp(2) + 1)*z, t, z), Poly(2/(exp(2) + 1)*z, z, t)]
46    assert as_poly_1t(2/((exp(2) + 1)*t) + t, t, z) in [
47        Poly(t + 2/(exp(2) + 1)*z, t, z), Poly(t + 2/(exp(2) + 1)*z, z, t)]
48    assert as_poly_1t(S.Zero, t, z) == Poly(0, t, z)
49
50
51def test_derivation():
52    p = Poly(4*x**4*t**5 + (-4*x**3 - 4*x**4)*t**4 + (-3*x**2 + 2*x**3)*t**3 +
53        (2*x + 7*x**2 + 2*x**3)*t**2 + (1 - 4*x - 4*x**2)*t - 1 + 2*x, t)
54    DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(-t**2 - 3/(2*x)*t + 1/(2*x), t)]})
55    assert derivation(p, DE) == Poly(-20*x**4*t**6 + (2*x**3 + 16*x**4)*t**5 +
56        (21*x**2 + 12*x**3)*t**4 + (x*Rational(7, 2) - 25*x**2 - 12*x**3)*t**3 +
57        (-5 - x*Rational(15, 2) + 7*x**2)*t**2 - (3 - 8*x - 10*x**2 - 4*x**3)/(2*x)*t +
58        (1 - 4*x**2)/(2*x), t)
59    assert derivation(Poly(1, t), DE) == Poly(0, t)
60    assert derivation(Poly(t, t), DE) == DE.d
61    assert derivation(Poly(t**2 + 1/x*t + (1 - 2*x)/(4*x**2), t), DE) == \
62        Poly(-2*t**3 - 4/x*t**2 - (5 - 2*x)/(2*x**2)*t - (1 - 2*x)/(2*x**3), t, domain='ZZ(x)')
63    DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t1), Poly(t, t)]})
64    assert derivation(Poly(x*t*t1, t), DE) == Poly(t*t1 + x*t*t1 + t, t)
65    assert derivation(Poly(x*t*t1, t), DE, coefficientD=True) == \
66        Poly((1 + t1)*t, t)
67    DE = DifferentialExtension(extension={'D': [Poly(1, x)]})
68    assert derivation(Poly(x, x), DE) == Poly(1, x)
69    # Test basic option
70    assert derivation((x + 1)/(x - 1), DE, basic=True) == -2/(1 - 2*x + x**2)
71    DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)]})
72    assert derivation((t + 1)/(t - 1), DE, basic=True) == -2*t/(1 - 2*t + t**2)
73    assert derivation(t + 1, DE, basic=True) == t
74
75
76def test_splitfactor():
77    p = Poly(4*x**4*t**5 + (-4*x**3 - 4*x**4)*t**4 + (-3*x**2 + 2*x**3)*t**3 +
78        (2*x + 7*x**2 + 2*x**3)*t**2 + (1 - 4*x - 4*x**2)*t - 1 + 2*x, t, field=True)
79    DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(-t**2 - 3/(2*x)*t + 1/(2*x), t)]})
80    assert splitfactor(p, DE) == (Poly(4*x**4*t**3 + (-8*x**3 - 4*x**4)*t**2 +
81        (4*x**2 + 8*x**3)*t - 4*x**2, t, domain='ZZ(x)'),
82        Poly(t**2 + 1/x*t + (1 - 2*x)/(4*x**2), t, domain='ZZ(x)'))
83    assert splitfactor(Poly(x, t), DE) == (Poly(x, t), Poly(1, t))
84    r = Poly(-4*x**4*z**2 + 4*x**6*z**2 - z*x**3 - 4*x**5*z**3 + 4*x**3*z**3 + x**4 + z*x**5 - x**6, t)
85    DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t)]})
86    assert splitfactor(r, DE, coefficientD=True) == \
87        (Poly(x*z - x**2 - z*x**3 + x**4, t), Poly(-x**2 + 4*x**2*z**2, t))
88    assert splitfactor_sqf(r, DE, coefficientD=True) == \
89        (((Poly(x*z - x**2 - z*x**3 + x**4, t), 1),), ((Poly(-x**2 + 4*x**2*z**2, t), 1),))
90    assert splitfactor(Poly(0, t), DE) == (Poly(0, t), Poly(1, t))
91    assert splitfactor_sqf(Poly(0, t), DE) == (((Poly(0, t), 1),), ())
92
93
94def test_canonical_representation():
95    DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1 + t**2, t)]})
96    assert canonical_representation(Poly(x - t, t), Poly(t**2, t), DE) == \
97        (Poly(0, t, domain='ZZ[x]'), (Poly(0, t, domain='QQ[x]'),
98        Poly(1, t, domain='ZZ')), (Poly(-t + x, t, domain='QQ[x]'),
99        Poly(t**2, t)))
100    DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t**2 + 1, t)]})
101    assert canonical_representation(Poly(t**5 + t**3 + x**2*t + 1, t),
102    Poly((t**2 + 1)**3, t), DE) == \
103        (Poly(0, t, domain='ZZ[x]'), (Poly(t**5 + t**3 + x**2*t + 1, t, domain='QQ[x]'),
104         Poly(t**6 + 3*t**4 + 3*t**2 + 1, t, domain='QQ')),
105        (Poly(0, t, domain='QQ[x]'), Poly(1, t, domain='QQ')))
106
107
108def test_hermite_reduce():
109    DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t**2 + 1, t)]})
110
111    assert hermite_reduce(Poly(x - t, t), Poly(t**2, t), DE) == \
112        ((Poly(-x, t, domain='QQ[x]'), Poly(t, t, domain='QQ[x]')),
113         (Poly(0, t, domain='QQ[x]'), Poly(1, t, domain='QQ[x]')),
114         (Poly(-x, t, domain='QQ[x]'), Poly(1, t, domain='QQ[x]')))
115
116    DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(-t**2 - t/x - (1 - nu**2/x**2), t)]})
117
118    assert hermite_reduce(
119            Poly(x**2*t**5 + x*t**4 - nu**2*t**3 - x*(x**2 + 1)*t**2 - (x**2 - nu**2)*t - x**5/4, t),
120            Poly(x**2*t**4 + x**2*(x**2 + 2)*t**2 + x**2 + x**4 + x**6/4, t), DE) == \
121        ((Poly(-x**2 - 4, t, domain='ZZ(x,nu)'), Poly(4*t**2 + 2*x**2 + 4, t, domain='ZZ(x,nu)')),
122         (Poly((-2*nu**2 - x**4)*t - (2*x**3 + 2*x), t, domain='ZZ(x,nu)'),
123          Poly(2*x**2*t**2 + x**4 + 2*x**2, t, domain='ZZ(x,nu)')),
124         (Poly(x*t + 1, t, domain='ZZ(x,nu)'), Poly(x, t, domain='ZZ(x,nu)')))
125
126    DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t)]})
127
128    a = Poly((-2 + 3*x)*t**3 + (-1 + x)*t**2 + (-4*x + 2*x**2)*t + x**2, t)
129    d = Poly(x*t**6 - 4*x**2*t**5 + 6*x**3*t**4 - 4*x**4*t**3 + x**5*t**2, t)
130
131    assert hermite_reduce(a, d, DE) == \
132        ((Poly(3*t**2 + t + 3*x, t, domain='ZZ(x)'),
133          Poly(3*t**4 - 9*x*t**3 + 9*x**2*t**2 - 3*x**3*t, t, domain='ZZ(x)')),
134         (Poly(0, t, domain='ZZ(x)'), Poly(1, t, domain='ZZ(x)')),
135         (Poly(0, t, domain='ZZ(x)'), Poly(1, t, domain='ZZ(x)')))
136
137    assert hermite_reduce(
138            Poly(-t**2 + 2*t + 2, t, domain='ZZ(x)'),
139            Poly(-x*t**2 + 2*x*t - x, t, domain='ZZ(x)'), DE) == \
140        ((Poly(3, t, domain='ZZ(x)'), Poly(t - 1, t, domain='ZZ(x)')),
141         (Poly(0, t, domain='ZZ(x)'), Poly(1, t, domain='ZZ(x)')),
142         (Poly(1, t, domain='ZZ(x)'), Poly(x, t, domain='ZZ(x)')))
143
144    assert hermite_reduce(
145            Poly(-x**2*t**6 + (-1 - 2*x**3 + x**4)*t**3 + (-3 - 3*x**4)*t**2 -
146                2*x*t - x - 3*x**2, t, domain='ZZ(x)'),
147            Poly(x**4*t**6 - 2*x**2*t**3 + 1, t, domain='ZZ(x)'), DE) == \
148        ((Poly(x**3*t + x**4 + 1, t, domain='ZZ(x)'), Poly(x**3*t**3 - x, t, domain='ZZ(x)')),
149         (Poly(0, t, domain='ZZ(x)'), Poly(1, t, domain='ZZ(x)')),
150         (Poly(-1, t, domain='ZZ(x)'), Poly(x**2, t, domain='ZZ(x)')))
151
152    assert hermite_reduce(
153            Poly((-2 + 3*x)*t**3 + (-1 + x)*t**2 + (-4*x + 2*x**2)*t + x**2, t),
154            Poly(x*t**6 - 4*x**2*t**5 + 6*x**3*t**4 - 4*x**4*t**3 + x**5*t**2, t), DE) == \
155        ((Poly(3*t**2 + t + 3*x, t, domain='ZZ(x)'),
156          Poly(3*t**4 - 9*x*t**3 + 9*x**2*t**2 - 3*x**3*t, t, domain='ZZ(x)')),
157         (Poly(0, t, domain='ZZ(x)'), Poly(1, t, domain='ZZ(x)')),
158         (Poly(0, t, domain='ZZ(x)'), Poly(1, t, domain='ZZ(x)')))
159
160
161def test_polynomial_reduce():
162    DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1 + t**2, t)]})
163    assert polynomial_reduce(Poly(1 + x*t + t**2, t), DE) == \
164        (Poly(t, t), Poly(x*t, t))
165    assert polynomial_reduce(Poly(0, t), DE) == \
166        (Poly(0, t), Poly(0, t))
167
168
169def test_laurent_series():
170    DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1, t)]})
171    a = Poly(36, t)
172    d = Poly((t - 2)*(t**2 - 1)**2, t)
173    F = Poly(t**2 - 1, t)
174    n = 2
175    assert laurent_series(a, d, F, n, DE) == \
176        (Poly(-3*t**3 + 3*t**2 - 6*t - 8, t), Poly(t**5 + t**4 - 2*t**3 - 2*t**2 + t + 1, t),
177        [Poly(-3*t**3 - 6*t**2, t, domain='QQ'), Poly(2*t**6 + 6*t**5 - 8*t**3, t, domain='QQ')])
178
179
180def test_recognize_derivative():
181    DE = DifferentialExtension(extension={'D': [Poly(1, t)]})
182    a = Poly(36, t)
183    d = Poly((t - 2)*(t**2 - 1)**2, t)
184    assert recognize_derivative(a, d, DE) == False
185    DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t)]})
186    a = Poly(2, t)
187    d = Poly(t**2 - 1, t)
188    assert recognize_derivative(a, d, DE) == False
189    assert recognize_derivative(Poly(x*t, t), Poly(1, t), DE) == True
190    DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t**2 + 1, t)]})
191    assert recognize_derivative(Poly(t, t), Poly(1, t), DE) == True
192
193
194def test_recognize_log_derivative():
195
196    a = Poly(2*x**2 + 4*x*t - 2*t - x**2*t, t)
197    d = Poly((2*x + t)*(t + x**2), t)
198    DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)]})
199    assert recognize_log_derivative(a, d, DE, z) == True
200    DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t)]})
201    assert recognize_log_derivative(Poly(t + 1, t), Poly(t + x, t), DE) == True
202    assert recognize_log_derivative(Poly(2, t), Poly(t**2 - 1, t), DE) == True
203    DE = DifferentialExtension(extension={'D': [Poly(1, x)]})
204    assert recognize_log_derivative(Poly(1, x), Poly(x**2 - 2, x), DE) == False
205    assert recognize_log_derivative(Poly(1, x), Poly(x**2 + x, x), DE) == True
206    DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t**2 + 1, t)]})
207    assert recognize_log_derivative(Poly(1, t), Poly(t**2 - 2, t), DE) == False
208    assert recognize_log_derivative(Poly(1, t), Poly(t**2 + t, t), DE) == False
209
210
211def test_residue_reduce():
212    a = Poly(2*t**2 - t - x**2, t)
213    d = Poly(t**3 - x**2*t, t)
214    DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t)], 'Tfuncs': [log]})
215    assert residue_reduce(a, d, DE, z, invert=False) == \
216        ([(Poly(z**2 - Rational(1, 4), z, domain='ZZ(x)'),
217          Poly((1 + 3*x*z - 6*z**2 - 2*x**2 + 4*x**2*z**2)*t - x*z + x**2 +
218              2*x**2*z**2 - 2*z*x**3, t, domain='ZZ(z, x)'))], False)
219    assert residue_reduce(a, d, DE, z, invert=True) == \
220        ([(Poly(z**2 - Rational(1, 4), z, domain='ZZ(x)'), Poly(t + 2*x*z, t))], False)
221    assert residue_reduce(Poly(-2/x, t), Poly(t**2 - 1, t,), DE, z, invert=False) == \
222        ([(Poly(z**2 - 1, z, domain='QQ'), Poly(-2*z*t/x - 2/x, t, domain='ZZ(z,x)'))], True)
223    ans = residue_reduce(Poly(-2/x, t), Poly(t**2 - 1, t), DE, z, invert=True)
224    assert ans == ([(Poly(z**2 - 1, z, domain='QQ'), Poly(t + z, t))], True)
225    assert residue_reduce_to_basic(ans[0], DE, z) == -log(-1 + log(x)) + log(1 + log(x))
226
227    DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(-t**2 - t/x - (1 - nu**2/x**2), t)]})
228    # TODO: Skip or make faster
229    assert residue_reduce(Poly((-2*nu**2 - x**4)/(2*x**2)*t - (1 + x**2)/x, t),
230    Poly(t**2 + 1 + x**2/2, t), DE, z) == \
231        ([(Poly(z + S.Half, z, domain='QQ'), Poly(t**2 + 1 + x**2/2, t,
232            domain='ZZ(x,nu)'))], True)
233    DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1 + t**2, t)]})
234    assert residue_reduce(Poly(-2*x*t + 1 - x**2, t),
235    Poly(t**2 + 2*x*t + 1 + x**2, t), DE, z) == \
236        ([(Poly(z**2 + Rational(1, 4), z), Poly(t + x + 2*z, t))], True)
237    DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)]})
238    assert residue_reduce(Poly(t, t), Poly(t + sqrt(2), t), DE, z) == \
239        ([(Poly(z - 1, z, domain='QQ'), Poly(t + sqrt(2), t))], True)
240
241
242def test_integrate_hyperexponential():
243    # TODO: Add tests for integrate_hyperexponential() from the book
244    a = Poly((1 + 2*t1 + t1**2 + 2*t1**3)*t**2 + (1 + t1**2)*t + 1 + t1**2, t)
245    d = Poly(1, t)
246    DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1 + t1**2, t1),
247        Poly(t*(1 + t1**2), t)], 'Tfuncs': [tan, Lambda(i, exp(tan(i)))]})
248    assert integrate_hyperexponential(a, d, DE) == \
249        (exp(2*tan(x))*tan(x) + exp(tan(x)), 1 + t1**2, True)
250    a = Poly((t1**3 + (x + 1)*t1**2 + t1 + x + 2)*t, t)
251    assert integrate_hyperexponential(a, d, DE) == \
252        ((x + tan(x))*exp(tan(x)), 0, True)
253
254    a = Poly(t, t)
255    d = Poly(1, t)
256    DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(2*x*t, t)],
257        'Tfuncs': [Lambda(i, exp(x**2))]})
258
259    assert integrate_hyperexponential(a, d, DE) == \
260        (0, NonElementaryIntegral(exp(x**2), x), False)
261
262    DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)], 'Tfuncs': [exp]})
263    assert integrate_hyperexponential(a, d, DE) == (exp(x), 0, True)
264
265    a = Poly(25*t**6 - 10*t**5 + 7*t**4 - 8*t**3 + 13*t**2 + 2*t - 1, t)
266    d = Poly(25*t**6 + 35*t**4 + 11*t**2 + 1, t)
267    assert integrate_hyperexponential(a, d, DE) == \
268        (-(11 - 10*exp(x))/(5 + 25*exp(2*x)) + log(1 + exp(2*x)), -1, True)
269    DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t0, t0), Poly(t0*t, t)],
270        'Tfuncs': [exp, Lambda(i, exp(exp(i)))]})
271    assert integrate_hyperexponential(Poly(2*t0*t**2, t), Poly(1, t), DE) == (exp(2*exp(x)), 0, True)
272
273    DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t0, t0), Poly(-t0*t, t)],
274        'Tfuncs': [exp, Lambda(i, exp(-exp(i)))]})
275    assert integrate_hyperexponential(Poly(-27*exp(9) - 162*t0*exp(9) +
276    27*x*t0*exp(9), t), Poly((36*exp(18) + x**2*exp(18) - 12*x*exp(18))*t, t), DE) == \
277        (27*exp(exp(x))/(-6*exp(9) + x*exp(9)), 0, True)
278
279    DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)], 'Tfuncs': [exp]})
280    assert integrate_hyperexponential(Poly(x**2/2*t, t), Poly(1, t), DE) == \
281        ((2 - 2*x + x**2)*exp(x)/2, 0, True)
282    assert integrate_hyperexponential(Poly(1 + t, t), Poly(t, t), DE) == \
283        (-exp(-x), 1, True)  # x - exp(-x)
284    assert integrate_hyperexponential(Poly(x, t), Poly(t + 1, t), DE) == \
285        (0, NonElementaryIntegral(x/(1 + exp(x)), x), False)
286
287    DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t0), Poly(2*x*t1, t1)],
288        'Tfuncs': [log, Lambda(i, exp(i**2))]})
289
290    elem, nonelem, b = integrate_hyperexponential(Poly((8*x**7 - 12*x**5 + 6*x**3 - x)*t1**4 +
291        (8*t0*x**7 - 8*t0*x**6 - 4*t0*x**5 + 2*t0*x**3 + 2*t0*x**2 - t0*x +
292        24*x**8 - 36*x**6 - 4*x**5 + 22*x**4 + 4*x**3 - 7*x**2 - x + 1)*t1**3
293        + (8*t0*x**8 - 4*t0*x**6 - 16*t0*x**5 - 2*t0*x**4 + 12*t0*x**3 +
294        t0*x**2 - 2*t0*x + 24*x**9 - 36*x**7 - 8*x**6 + 22*x**5 + 12*x**4 -
295        7*x**3 - 6*x**2 + x + 1)*t1**2 + (8*t0*x**8 - 8*t0*x**6 - 16*t0*x**5 +
296        6*t0*x**4 + 10*t0*x**3 - 2*t0*x**2 - t0*x + 8*x**10 - 12*x**8 - 4*x**7
297        + 2*x**6 + 12*x**5 + 3*x**4 - 9*x**3 - x**2 + 2*x)*t1 + 8*t0*x**7 -
298        12*t0*x**6 - 4*t0*x**5 + 8*t0*x**4 - t0*x**2 - 4*x**7 + 4*x**6 +
299        4*x**5 - 4*x**4 - x**3 + x**2, t1), Poly((8*x**7 - 12*x**5 + 6*x**3 -
300        x)*t1**4 + (24*x**8 + 8*x**7 - 36*x**6 - 12*x**5 + 18*x**4 + 6*x**3 -
301        3*x**2 - x)*t1**3 + (24*x**9 + 24*x**8 - 36*x**7 - 36*x**6 + 18*x**5 +
302        18*x**4 - 3*x**3 - 3*x**2)*t1**2 + (8*x**10 + 24*x**9 - 12*x**8 -
303        36*x**7 + 6*x**6 + 18*x**5 - x**4 - 3*x**3)*t1 + 8*x**10 - 12*x**8 +
304        6*x**6 - x**4, t1), DE)
305
306    assert factor(elem) == -((x - 1)*log(x)/((x + exp(x**2))*(2*x**2 - 1)))
307    assert (nonelem, b) == (NonElementaryIntegral(exp(x**2)/(exp(x**2) + 1), x), False)
308
309def test_integrate_hyperexponential_polynomial():
310    # Without proper cancellation within integrate_hyperexponential_polynomial(),
311    # this will take a long time to complete, and will return a complicated
312    # expression
313    p = Poly((-28*x**11*t0 - 6*x**8*t0 + 6*x**9*t0 - 15*x**8*t0**2 +
314        15*x**7*t0**2 + 84*x**10*t0**2 - 140*x**9*t0**3 - 20*x**6*t0**3 +
315        20*x**7*t0**3 - 15*x**6*t0**4 + 15*x**5*t0**4 + 140*x**8*t0**4 -
316        84*x**7*t0**5 - 6*x**4*t0**5 + 6*x**5*t0**5 + x**3*t0**6 - x**4*t0**6 +
317        28*x**6*t0**6 - 4*x**5*t0**7 + x**9 - x**10 + 4*x**12)/(-8*x**11*t0 +
318        28*x**10*t0**2 - 56*x**9*t0**3 + 70*x**8*t0**4 - 56*x**7*t0**5 +
319        28*x**6*t0**6 - 8*x**5*t0**7 + x**4*t0**8 + x**12)*t1**2 +
320        (-28*x**11*t0 - 12*x**8*t0 + 12*x**9*t0 - 30*x**8*t0**2 +
321        30*x**7*t0**2 + 84*x**10*t0**2 - 140*x**9*t0**3 - 40*x**6*t0**3 +
322        40*x**7*t0**3 - 30*x**6*t0**4 + 30*x**5*t0**4 + 140*x**8*t0**4 -
323        84*x**7*t0**5 - 12*x**4*t0**5 + 12*x**5*t0**5 - 2*x**4*t0**6 +
324        2*x**3*t0**6 + 28*x**6*t0**6 - 4*x**5*t0**7 + 2*x**9 - 2*x**10 +
325        4*x**12)/(-8*x**11*t0 + 28*x**10*t0**2 - 56*x**9*t0**3 +
326        70*x**8*t0**4 - 56*x**7*t0**5 + 28*x**6*t0**6 - 8*x**5*t0**7 +
327        x**4*t0**8 + x**12)*t1 + (-2*x**2*t0 + 2*x**3*t0 + x*t0**2 -
328        x**2*t0**2 + x**3 - x**4)/(-4*x**5*t0 + 6*x**4*t0**2 - 4*x**3*t0**3 +
329        x**2*t0**4 + x**6), t1, z, expand=False)
330    DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t0), Poly(2*x*t1, t1)]})
331    assert integrate_hyperexponential_polynomial(p, DE, z) == (
332        Poly((x - t0)*t1**2 + (-2*t0 + 2*x)*t1, t1), Poly(-2*x*t0 + x**2 +
333        t0**2, t1), True)
334
335    DE = DifferentialExtension(extension={'D':[Poly(1, x), Poly(t0, t0)]})
336    assert integrate_hyperexponential_polynomial(Poly(0, t0), DE, z) == (
337        Poly(0, t0), Poly(1, t0), True)
338
339
340def test_integrate_hyperexponential_returns_piecewise():
341    a, b = symbols('a b')
342    DE = DifferentialExtension(a**x, x)
343    assert integrate_hyperexponential(DE.fa, DE.fd, DE) == (Piecewise(
344        (exp(x*log(a))/log(a), Ne(log(a), 0)), (x, True)), 0, True)
345    DE = DifferentialExtension(a**(b*x), x)
346    assert integrate_hyperexponential(DE.fa, DE.fd, DE) == (Piecewise(
347        (exp(b*x*log(a))/(b*log(a)), Ne(b*log(a), 0)), (x, True)), 0, True)
348    DE = DifferentialExtension(exp(a*x), x)
349    assert integrate_hyperexponential(DE.fa, DE.fd, DE) == (Piecewise(
350        (exp(a*x)/a, Ne(a, 0)), (x, True)), 0, True)
351    DE = DifferentialExtension(x*exp(a*x), x)
352    assert integrate_hyperexponential(DE.fa, DE.fd, DE) == (Piecewise(
353        ((a*x - 1)*exp(a*x)/a**2, Ne(a**2, 0)), (x**2/2, True)), 0, True)
354    DE = DifferentialExtension(x**2*exp(a*x), x)
355    assert integrate_hyperexponential(DE.fa, DE.fd, DE) == (Piecewise(
356        ((x**2*a**2 - 2*a*x + 2)*exp(a*x)/a**3, Ne(a**3, 0)),
357        (x**3/3, True)), 0, True)
358    DE = DifferentialExtension(x**y + z, y)
359    assert integrate_hyperexponential(DE.fa, DE.fd, DE) == (Piecewise(
360        (exp(log(x)*y)/log(x), Ne(log(x), 0)), (y, True)), z, True)
361    DE = DifferentialExtension(x**y + z + x**(2*y), y)
362    assert integrate_hyperexponential(DE.fa, DE.fd, DE) == (Piecewise(
363        ((exp(2*log(x)*y)*log(x) +
364            2*exp(log(x)*y)*log(x))/(2*log(x)**2), Ne(2*log(x)**2, 0)),
365            (2*y, True),
366        ), z, True)
367    # TODO: Add a test where two different parts of the extension use a
368    # Piecewise, like y**x + z**x.
369
370def test_issue_13947():
371    a, t, s = symbols('a t s')
372    assert risch_integrate(2**(-pi)/(2**t + 1), t) == \
373        2**(-pi)*t - 2**(-pi)*log(2**t + 1)/log(2)
374    assert risch_integrate(a**(t - s)/(a**t + 1), t) == \
375        exp(-s*log(a))*log(a**t + 1)/log(a)
376
377def test_integrate_primitive():
378    DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t)],
379        'Tfuncs': [log]})
380    assert integrate_primitive(Poly(t, t), Poly(1, t), DE) == (x*log(x), -1, True)
381    assert integrate_primitive(Poly(x, t), Poly(t, t), DE) == (0, NonElementaryIntegral(x/log(x), x), False)
382
383    DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t1), Poly(1/(x + 1), t2)],
384        'Tfuncs': [log, Lambda(i, log(i + 1))]})
385    assert integrate_primitive(Poly(t1, t2), Poly(t2, t2), DE) == \
386        (0, NonElementaryIntegral(log(x)/log(1 + x), x), False)
387
388    DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t1), Poly(1/(x*t1), t2)],
389        'Tfuncs': [log, Lambda(i, log(log(i)))]})
390    assert integrate_primitive(Poly(t2, t2), Poly(t1, t2), DE) == \
391        (0, NonElementaryIntegral(log(log(x))/log(x), x), False)
392
393    DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t0)],
394        'Tfuncs': [log]})
395    assert integrate_primitive(Poly(x**2*t0**3 + (3*x**2 + x)*t0**2 + (3*x**2
396    + 2*x)*t0 + x**2 + x, t0), Poly(x**2*t0**4 + 4*x**2*t0**3 + 6*x**2*t0**2 +
397    4*x**2*t0 + x**2, t0), DE) == \
398        (-1/(log(x) + 1), NonElementaryIntegral(1/(log(x) + 1), x), False)
399
400def test_integrate_hypertangent_polynomial():
401    DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t**2 + 1, t)]})
402    assert integrate_hypertangent_polynomial(Poly(t**2 + x*t + 1, t), DE) == \
403        (Poly(t, t), Poly(x/2, t))
404    DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(a*(t**2 + 1), t)]})
405    assert integrate_hypertangent_polynomial(Poly(t**5, t), DE) == \
406        (Poly(1/(4*a)*t**4 - 1/(2*a)*t**2, t), Poly(1/(2*a), t))
407
408
409def test_integrate_nonlinear_no_specials():
410    a, d, = Poly(x**2*t**5 + x*t**4 - nu**2*t**3 - x*(x**2 + 1)*t**2 - (x**2 -
411    nu**2)*t - x**5/4, t), Poly(x**2*t**4 + x**2*(x**2 + 2)*t**2 + x**2 + x**4 + x**6/4, t)
412    # f(x) == phi_nu(x), the logarithmic derivative of J_v, the Bessel function,
413    # which has no specials (see Chapter 5, note 4 of Bronstein's book).
414    f = Function('phi_nu')
415    DE = DifferentialExtension(extension={'D': [Poly(1, x),
416        Poly(-t**2 - t/x - (1 - nu**2/x**2), t)], 'Tfuncs': [f]})
417    assert integrate_nonlinear_no_specials(a, d, DE) == \
418        (-log(1 + f(x)**2 + x**2/2)/2 + (- 4 - x**2)/(4 + 2*x**2 + 4*f(x)**2), True)
419    assert integrate_nonlinear_no_specials(Poly(t, t), Poly(1, t), DE) == \
420        (0, False)
421
422
423def test_integer_powers():
424    assert integer_powers([x, x/2, x**2 + 1, x*Rational(2, 3)]) == [
425            (x/6, [(x, 6), (x/2, 3), (x*Rational(2, 3), 4)]),
426            (1 + x**2, [(1 + x**2, 1)])]
427
428
429def test_DifferentialExtension_exp():
430    assert DifferentialExtension(exp(x) + exp(x**2), x)._important_attrs == \
431        (Poly(t1 + t0, t1), Poly(1, t1), [Poly(1, x,), Poly(t0, t0),
432        Poly(2*x*t1, t1)], [x, t0, t1], [Lambda(i, exp(i)),
433        Lambda(i, exp(i**2))], [], [None, 'exp', 'exp'], [None, x, x**2])
434    assert DifferentialExtension(exp(x) + exp(2*x), x)._important_attrs == \
435        (Poly(t0**2 + t0, t0), Poly(1, t0), [Poly(1, x), Poly(t0, t0)], [x, t0],
436        [Lambda(i, exp(i))], [], [None, 'exp'], [None, x])
437    assert DifferentialExtension(exp(x) + exp(x/2), x)._important_attrs == \
438        (Poly(t0**2 + t0, t0), Poly(1, t0), [Poly(1, x), Poly(t0/2, t0)],
439        [x, t0], [Lambda(i, exp(i/2))], [], [None, 'exp'], [None, x/2])
440    assert DifferentialExtension(exp(x) + exp(x**2) + exp(x + x**2), x)._important_attrs == \
441        (Poly((1 + t0)*t1 + t0, t1), Poly(1, t1), [Poly(1, x), Poly(t0, t0),
442        Poly(2*x*t1, t1)], [x, t0, t1], [Lambda(i, exp(i)),
443        Lambda(i, exp(i**2))], [], [None, 'exp', 'exp'], [None, x, x**2])
444    assert DifferentialExtension(exp(x) + exp(x**2) + exp(x + x**2 + 1), x)._important_attrs == \
445        (Poly((1 + S.Exp1*t0)*t1 + t0, t1), Poly(1, t1), [Poly(1, x),
446        Poly(t0, t0), Poly(2*x*t1, t1)], [x, t0, t1], [Lambda(i, exp(i)),
447        Lambda(i, exp(i**2))], [], [None, 'exp', 'exp'], [None, x, x**2])
448    assert DifferentialExtension(exp(x) + exp(x**2) + exp(x/2 + x**2), x)._important_attrs == \
449        (Poly((t0 + 1)*t1 + t0**2, t1), Poly(1, t1), [Poly(1, x),
450        Poly(t0/2, t0), Poly(2*x*t1, t1)], [x, t0, t1],
451        [Lambda(i, exp(i/2)), Lambda(i, exp(i**2))],
452        [(exp(x/2), sqrt(exp(x)))], [None, 'exp', 'exp'], [None, x/2, x**2])
453    assert DifferentialExtension(exp(x) + exp(x**2) + exp(x/2 + x**2 + 3), x)._important_attrs == \
454        (Poly((t0*exp(3) + 1)*t1 + t0**2, t1), Poly(1, t1), [Poly(1, x),
455        Poly(t0/2, t0), Poly(2*x*t1, t1)], [x, t0, t1], [Lambda(i, exp(i/2)),
456        Lambda(i, exp(i**2))], [(exp(x/2), sqrt(exp(x)))], [None, 'exp', 'exp'],
457        [None, x/2, x**2])
458    assert DifferentialExtension(sqrt(exp(x)), x)._important_attrs == \
459        (Poly(t0, t0), Poly(1, t0), [Poly(1, x), Poly(t0/2, t0)], [x, t0],
460        [Lambda(i, exp(i/2))], [(exp(x/2), sqrt(exp(x)))], [None, 'exp'], [None, x/2])
461
462    assert DifferentialExtension(exp(x/2), x)._important_attrs == \
463        (Poly(t0, t0), Poly(1, t0), [Poly(1, x), Poly(t0/2, t0)], [x, t0],
464        [Lambda(i, exp(i/2))], [], [None, 'exp'], [None, x/2])
465
466
467def test_DifferentialExtension_log():
468    assert DifferentialExtension(log(x)*log(x + 1)*log(2*x**2 + 2*x), x)._important_attrs == \
469        (Poly(t0*t1**2 + (t0*log(2) + t0**2)*t1, t1), Poly(1, t1),
470        [Poly(1, x), Poly(1/x, t0),
471        Poly(1/(x + 1), t1, expand=False)], [x, t0, t1],
472        [Lambda(i, log(i)), Lambda(i, log(i + 1))], [], [None, 'log', 'log'],
473        [None, x, x + 1])
474    assert DifferentialExtension(x**x*log(x), x)._important_attrs == \
475        (Poly(t0*t1, t1), Poly(1, t1), [Poly(1, x), Poly(1/x, t0),
476        Poly((1 + t0)*t1, t1)], [x, t0, t1], [Lambda(i, log(i)),
477        Lambda(i, exp(t0*i))], [(exp(x*log(x)), x**x)], [None, 'log', 'exp'],
478        [None, x, t0*x])
479
480
481def test_DifferentialExtension_symlog():
482    # See comment on test_risch_integrate below
483    assert DifferentialExtension(log(x**x), x)._important_attrs == \
484        (Poly(t0*x, t1), Poly(1, t1), [Poly(1, x), Poly(1/x, t0), Poly((t0 +
485            1)*t1, t1)], [x, t0, t1], [Lambda(i, log(i)), Lambda(i, exp(i*t0))],
486            [(exp(x*log(x)), x**x)], [None, 'log', 'exp'], [None, x, t0*x])
487    assert DifferentialExtension(log(x**y), x)._important_attrs == \
488        (Poly(y*t0, t0), Poly(1, t0), [Poly(1, x), Poly(1/x, t0)], [x, t0],
489        [Lambda(i, log(i))], [(y*log(x), log(x**y))], [None, 'log'],
490        [None, x])
491    assert DifferentialExtension(log(sqrt(x)), x)._important_attrs == \
492        (Poly(t0, t0), Poly(2, t0), [Poly(1, x), Poly(1/x, t0)], [x, t0],
493        [Lambda(i, log(i))], [(log(x)/2, log(sqrt(x)))], [None, 'log'],
494        [None, x])
495
496
497def test_DifferentialExtension_handle_first():
498    assert DifferentialExtension(exp(x)*log(x), x, handle_first='log')._important_attrs == \
499        (Poly(t0*t1, t1), Poly(1, t1), [Poly(1, x), Poly(1/x, t0),
500        Poly(t1, t1)], [x, t0, t1], [Lambda(i, log(i)), Lambda(i, exp(i))],
501        [], [None, 'log', 'exp'], [None, x, x])
502    assert DifferentialExtension(exp(x)*log(x), x, handle_first='exp')._important_attrs == \
503        (Poly(t0*t1, t1), Poly(1, t1), [Poly(1, x), Poly(t0, t0),
504        Poly(1/x, t1)], [x, t0, t1], [Lambda(i, exp(i)), Lambda(i, log(i))],
505        [], [None, 'exp', 'log'], [None, x, x])
506
507    # This one must have the log first, regardless of what we set it to
508    # (because the log is inside of the exponential: x**x == exp(x*log(x)))
509    assert DifferentialExtension(-x**x*log(x)**2 + x**x - x**x/x, x,
510    handle_first='exp')._important_attrs == \
511        DifferentialExtension(-x**x*log(x)**2 + x**x - x**x/x, x,
512        handle_first='log')._important_attrs == \
513        (Poly((-1 + x - x*t0**2)*t1, t1), Poly(x, t1),
514            [Poly(1, x), Poly(1/x, t0), Poly((1 + t0)*t1, t1)], [x, t0, t1],
515            [Lambda(i, log(i)), Lambda(i, exp(t0*i))], [(exp(x*log(x)), x**x)],
516            [None, 'log', 'exp'], [None, x, t0*x])
517
518
519def test_DifferentialExtension_all_attrs():
520    # Test 'unimportant' attributes
521    DE = DifferentialExtension(exp(x)*log(x), x, handle_first='exp')
522    assert DE.f == exp(x)*log(x)
523    assert DE.newf == t0*t1
524    assert DE.x == x
525    assert DE.cases == ['base', 'exp', 'primitive']
526    assert DE.case == 'primitive'
527
528    assert DE.level == -1
529    assert DE.t == t1 == DE.T[DE.level]
530    assert DE.d == Poly(1/x, t1) == DE.D[DE.level]
531    raises(ValueError, lambda: DE.increment_level())
532    DE.decrement_level()
533    assert DE.level == -2
534    assert DE.t == t0 == DE.T[DE.level]
535    assert DE.d == Poly(t0, t0) == DE.D[DE.level]
536    assert DE.case == 'exp'
537    DE.decrement_level()
538    assert DE.level == -3
539    assert DE.t == x == DE.T[DE.level] == DE.x
540    assert DE.d == Poly(1, x) == DE.D[DE.level]
541    assert DE.case == 'base'
542    raises(ValueError, lambda: DE.decrement_level())
543    DE.increment_level()
544    DE.increment_level()
545    assert DE.level == -1
546    assert DE.t == t1 == DE.T[DE.level]
547    assert DE.d == Poly(1/x, t1) == DE.D[DE.level]
548    assert DE.case == 'primitive'
549
550    # Test methods
551    assert DE.indices('log') == [2]
552    assert DE.indices('exp') == [1]
553
554
555def test_DifferentialExtension_extension_flag():
556    raises(ValueError, lambda: DifferentialExtension(extension={'T': [x, t]}))
557    DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)]})
558    assert DE._important_attrs == (None, None, [Poly(1, x), Poly(t, t)], [x, t],
559        None, None, None, None)
560    assert DE.d == Poly(t, t)
561    assert DE.t == t
562    assert DE.level == -1
563    assert DE.cases == ['base', 'exp']
564    assert DE.x == x
565    assert DE.case == 'exp'
566
567    DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)],
568        'exts': [None, 'exp'], 'extargs': [None, x]})
569    assert DE._important_attrs == (None, None, [Poly(1, x), Poly(t, t)], [x, t],
570        None, None, [None, 'exp'], [None, x])
571    raises(ValueError, lambda: DifferentialExtension())
572
573
574def test_DifferentialExtension_misc():
575    # Odd ends
576    assert DifferentialExtension(sin(y)*exp(x), x)._important_attrs == \
577        (Poly(sin(y)*t0, t0, domain='ZZ[sin(y)]'), Poly(1, t0, domain='ZZ'),
578        [Poly(1, x, domain='ZZ'), Poly(t0, t0, domain='ZZ')], [x, t0],
579        [Lambda(i, exp(i))], [], [None, 'exp'], [None, x])
580    raises(NotImplementedError, lambda: DifferentialExtension(sin(x), x))
581    assert DifferentialExtension(10**x, x)._important_attrs == \
582        (Poly(t0, t0), Poly(1, t0), [Poly(1, x), Poly(log(10)*t0, t0)], [x, t0],
583        [Lambda(i, exp(i*log(10)))], [(exp(x*log(10)), 10**x)], [None, 'exp'],
584        [None, x*log(10)])
585    assert DifferentialExtension(log(x) + log(x**2), x)._important_attrs in [
586        (Poly(3*t0, t0), Poly(2, t0), [Poly(1, x), Poly(2/x, t0)], [x, t0],
587        [Lambda(i, log(i**2))], [], [None, ], [], [1], [x**2]),
588        (Poly(3*t0, t0), Poly(1, t0), [Poly(1, x), Poly(1/x, t0)], [x, t0],
589        [Lambda(i, log(i))], [], [None, 'log'], [None, x])]
590    assert DifferentialExtension(S.Zero, x)._important_attrs == \
591        (Poly(0, x), Poly(1, x), [Poly(1, x)], [x], [], [], [None], [None])
592    assert DifferentialExtension(tan(atan(x).rewrite(log)), x)._important_attrs == \
593        (Poly(x, x), Poly(1, x), [Poly(1, x)], [x], [], [], [None], [None])
594
595
596def test_DifferentialExtension_Rothstein():
597    # Rothstein's integral
598    f = (2581284541*exp(x) + 1757211400)/(39916800*exp(3*x) +
599    119750400*exp(x)**2 + 119750400*exp(x) + 39916800)*exp(1/(exp(x) + 1) - 10*x)
600    assert DifferentialExtension(f, x)._important_attrs == \
601        (Poly((1757211400 + 2581284541*t0)*t1, t1), Poly(39916800 +
602        119750400*t0 + 119750400*t0**2 + 39916800*t0**3, t1),
603        [Poly(1, x), Poly(t0, t0), Poly(-(10 + 21*t0 + 10*t0**2)/(1 + 2*t0 +
604        t0**2)*t1, t1, domain='ZZ(t0)')], [x, t0, t1],
605        [Lambda(i, exp(i)), Lambda(i, exp(1/(t0 + 1) - 10*i))], [],
606        [None, 'exp', 'exp'], [None, x, 1/(t0 + 1) - 10*x])
607
608
609class _TestingException(Exception):
610    """Dummy Exception class for testing."""
611    pass
612
613
614def test_DecrementLevel():
615    DE = DifferentialExtension(x*log(exp(x) + 1), x)
616    assert DE.level == -1
617    assert DE.t == t1
618    assert DE.d == Poly(t0/(t0 + 1), t1)
619    assert DE.case == 'primitive'
620
621    with DecrementLevel(DE):
622        assert DE.level == -2
623        assert DE.t == t0
624        assert DE.d == Poly(t0, t0)
625        assert DE.case == 'exp'
626
627        with DecrementLevel(DE):
628            assert DE.level == -3
629            assert DE.t == x
630            assert DE.d == Poly(1, x)
631            assert DE.case == 'base'
632
633        assert DE.level == -2
634        assert DE.t == t0
635        assert DE.d == Poly(t0, t0)
636        assert DE.case == 'exp'
637
638    assert DE.level == -1
639    assert DE.t == t1
640    assert DE.d == Poly(t0/(t0 + 1), t1)
641    assert DE.case == 'primitive'
642
643    # Test that __exit__ is called after an exception correctly
644    try:
645        with DecrementLevel(DE):
646            raise _TestingException
647    except _TestingException:
648        pass
649    else:
650        raise AssertionError("Did not raise.")
651
652    assert DE.level == -1
653    assert DE.t == t1
654    assert DE.d == Poly(t0/(t0 + 1), t1)
655    assert DE.case == 'primitive'
656
657
658def test_risch_integrate():
659    assert risch_integrate(t0*exp(x), x) == t0*exp(x)
660    assert risch_integrate(sin(x), x, rewrite_complex=True) == -exp(I*x)/2 - exp(-I*x)/2
661
662    # From my GSoC writeup
663    assert risch_integrate((1 + 2*x**2 + x**4 + 2*x**3*exp(2*x**2))/
664    (x**4*exp(x**2) + 2*x**2*exp(x**2) + exp(x**2)), x) == \
665        NonElementaryIntegral(exp(-x**2), x) + exp(x**2)/(1 + x**2)
666
667
668    assert risch_integrate(0, x) == 0
669
670    # also tests prde_cancel()
671    e1 = log(x/exp(x) + 1)
672    ans1 = risch_integrate(e1, x)
673    assert ans1 == (x*log(x*exp(-x) + 1) + NonElementaryIntegral((x**2 - x)/(x + exp(x)), x))
674    assert cancel(diff(ans1, x) - e1) == 0
675
676    # also tests issue #10798
677    e2 = (log(-1/y)/2 - log(1/y)/2)/y - (log(1 - 1/y)/2 - log(1 + 1/y)/2)/y
678    ans2 = risch_integrate(e2, y)
679    assert ans2 == log(1/y)*log(1 - 1/y)/2 - log(1/y)*log(1 + 1/y)/2 + \
680            NonElementaryIntegral((I*pi*y**2 - 2*y*log(1/y) - I*pi)/(2*y**3 - 2*y), y)
681    assert expand_log(cancel(diff(ans2, y) - e2), force=True) == 0
682
683    # These are tested here in addition to in test_DifferentialExtension above
684    # (symlogs) to test that backsubs works correctly.  The integrals should be
685    # written in terms of the original logarithms in the integrands.
686
687    # XXX: Unfortunately, making backsubs work on this one is a little
688    # trickier, because x**x is converted to exp(x*log(x)), and so log(x**x)
689    # is converted to x*log(x). (x**2*log(x)).subs(x*log(x), log(x**x)) is
690    # smart enough, the issue is that these splits happen at different places
691    # in the algorithm.  Maybe a heuristic is in order
692    assert risch_integrate(log(x**x), x) == x**2*log(x)/2 - x**2/4
693
694    assert risch_integrate(log(x**y), x) == x*log(x**y) - x*y
695    assert risch_integrate(log(sqrt(x)), x) == x*log(sqrt(x)) - x/2
696
697
698def test_risch_integrate_float():
699    assert risch_integrate((-60*exp(x) - 19.2*exp(4*x))*exp(4*x), x) == -2.4*exp(8*x) - 12.0*exp(5*x)
700
701
702def test_NonElementaryIntegral():
703    assert isinstance(risch_integrate(exp(x**2), x), NonElementaryIntegral)
704    assert isinstance(risch_integrate(x**x*log(x), x), NonElementaryIntegral)
705    # Make sure methods of Integral still give back a NonElementaryIntegral
706    assert isinstance(NonElementaryIntegral(x**x*t0, x).subs(t0, log(x)), NonElementaryIntegral)
707
708
709def test_xtothex():
710    a = risch_integrate(x**x, x)
711    assert a == NonElementaryIntegral(x**x, x)
712    assert isinstance(a, NonElementaryIntegral)
713
714
715def test_DifferentialExtension_equality():
716    DE1 = DE2 = DifferentialExtension(log(x), x)
717    assert DE1 == DE2
718
719
720def test_DifferentialExtension_printing():
721    DE = DifferentialExtension(exp(2*x**2) + log(exp(x**2) + 1), x)
722    assert repr(DE) == ("DifferentialExtension(dict([('f', exp(2*x**2) + log(exp(x**2) + 1)), "
723        "('x', x), ('T', [x, t0, t1]), ('D', [Poly(1, x, domain='ZZ'), Poly(2*x*t0, t0, domain='ZZ[x]'), "
724        "Poly(2*t0*x/(t0 + 1), t1, domain='ZZ(x,t0)')]), ('fa', Poly(t1 + t0**2, t1, domain='ZZ[t0]')), "
725        "('fd', Poly(1, t1, domain='ZZ')), ('Tfuncs', [Lambda(i, exp(i**2)), Lambda(i, log(t0 + 1))]), "
726        "('backsubs', []), ('exts', [None, 'exp', 'log']), ('extargs', [None, x**2, t0 + 1]), "
727        "('cases', ['base', 'exp', 'primitive']), ('case', 'primitive'), ('t', t1), "
728        "('d', Poly(2*t0*x/(t0 + 1), t1, domain='ZZ(x,t0)')), ('newf', t0**2 + t1), ('level', -1), "
729        "('dummy', False)]))")
730
731    assert str(DE) == ("DifferentialExtension({fa=Poly(t1 + t0**2, t1, domain='ZZ[t0]'), "
732        "fd=Poly(1, t1, domain='ZZ'), D=[Poly(1, x, domain='ZZ'), Poly(2*x*t0, t0, domain='ZZ[x]'), "
733        "Poly(2*t0*x/(t0 + 1), t1, domain='ZZ(x,t0)')]})")
734