1"""Test sparse rational functions. """
2
3from sympy.polys.fields import field, sfield, FracField, FracElement
4from sympy.polys.rings import ring
5from sympy.polys.domains import ZZ, QQ
6from sympy.polys.orderings import lex
7
8from sympy.testing.pytest import raises, XFAIL
9from sympy.core import symbols, E
10from sympy import sqrt, Rational, exp, log
11
12def test_FracField___init__():
13    F1 = FracField("x,y", ZZ, lex)
14    F2 = FracField("x,y", ZZ, lex)
15    F3 = FracField("x,y,z", ZZ, lex)
16
17    assert F1.x == F1.gens[0]
18    assert F1.y == F1.gens[1]
19    assert F1.x == F2.x
20    assert F1.y == F2.y
21    assert F1.x != F3.x
22    assert F1.y != F3.y
23
24def test_FracField___hash__():
25    F, x, y, z = field("x,y,z", QQ)
26    assert hash(F)
27
28def test_FracField___eq__():
29    assert field("x,y,z", QQ)[0] == field("x,y,z", QQ)[0]
30    assert field("x,y,z", QQ)[0] is field("x,y,z", QQ)[0]
31
32    assert field("x,y,z", QQ)[0] != field("x,y,z", ZZ)[0]
33    assert field("x,y,z", QQ)[0] is not field("x,y,z", ZZ)[0]
34
35    assert field("x,y,z", ZZ)[0] != field("x,y,z", QQ)[0]
36    assert field("x,y,z", ZZ)[0] is not field("x,y,z", QQ)[0]
37
38    assert field("x,y,z", QQ)[0] != field("x,y", QQ)[0]
39    assert field("x,y,z", QQ)[0] is not field("x,y", QQ)[0]
40
41    assert field("x,y", QQ)[0] != field("x,y,z", QQ)[0]
42    assert field("x,y", QQ)[0] is not field("x,y,z", QQ)[0]
43
44def test_sfield():
45    x = symbols("x")
46
47    F = FracField((E, exp(exp(x)), exp(x)), ZZ, lex)
48    e, exex, ex = F.gens
49    assert sfield(exp(x)*exp(exp(x) + 1 + log(exp(x) + 3)/2)**2/(exp(x) + 3)) \
50        == (F, e**2*exex**2*ex)
51
52    F = FracField((x, exp(1/x), log(x), x**QQ(1, 3)), ZZ, lex)
53    _, ex, lg, x3 = F.gens
54    assert sfield(((x-3)*log(x)+4*x**2)*exp(1/x+log(x)/3)/x**2) == \
55        (F, (4*F.x**2*ex + F.x*ex*lg - 3*ex*lg)/x3**5)
56
57    F = FracField((x, log(x), sqrt(x + log(x))), ZZ, lex)
58    _, lg, srt = F.gens
59    assert sfield((x + 1) / (x * (x + log(x))**QQ(3, 2)) - 1/(x * log(x)**2)) \
60        == (F, (F.x*lg**2 - F.x*srt + lg**2 - lg*srt)/
61            (F.x**2*lg**2*srt + F.x*lg**3*srt))
62
63def test_FracElement___hash__():
64    F, x, y, z = field("x,y,z", QQ)
65    assert hash(x*y/z)
66
67def test_FracElement_copy():
68    F, x, y, z = field("x,y,z", ZZ)
69
70    f = x*y/3*z
71    g = f.copy()
72
73    assert f == g
74    g.numer[(1, 1, 1)] = 7
75    assert f != g
76
77def test_FracElement_as_expr():
78    F, x, y, z = field("x,y,z", ZZ)
79    f = (3*x**2*y - x*y*z)/(7*z**3 + 1)
80
81    X, Y, Z = F.symbols
82    g = (3*X**2*Y - X*Y*Z)/(7*Z**3 + 1)
83
84    assert f != g
85    assert f.as_expr() == g
86
87    X, Y, Z = symbols("x,y,z")
88    g = (3*X**2*Y - X*Y*Z)/(7*Z**3 + 1)
89
90    assert f != g
91    assert f.as_expr(X, Y, Z) == g
92
93    raises(ValueError, lambda: f.as_expr(X))
94
95def test_FracElement_from_expr():
96    x, y, z = symbols("x,y,z")
97    F, X, Y, Z = field((x, y, z), ZZ)
98
99    f = F.from_expr(1)
100    assert f == 1 and isinstance(f, F.dtype)
101
102    f = F.from_expr(Rational(3, 7))
103    assert f == F(3)/7 and isinstance(f, F.dtype)
104
105    f = F.from_expr(x)
106    assert f == X and isinstance(f, F.dtype)
107
108    f = F.from_expr(Rational(3,7)*x)
109    assert f == X*Rational(3, 7) and isinstance(f, F.dtype)
110
111    f = F.from_expr(1/x)
112    assert f == 1/X and isinstance(f, F.dtype)
113
114    f = F.from_expr(x*y*z)
115    assert f == X*Y*Z and isinstance(f, F.dtype)
116
117    f = F.from_expr(x*y/z)
118    assert f == X*Y/Z and isinstance(f, F.dtype)
119
120    f = F.from_expr(x*y*z + x*y + x)
121    assert f == X*Y*Z + X*Y + X and isinstance(f, F.dtype)
122
123    f = F.from_expr((x*y*z + x*y + x)/(x*y + 7))
124    assert f == (X*Y*Z + X*Y + X)/(X*Y + 7) and isinstance(f, F.dtype)
125
126    f = F.from_expr(x**3*y*z + x**2*y**7 + 1)
127    assert f == X**3*Y*Z + X**2*Y**7 + 1 and isinstance(f, F.dtype)
128
129    raises(ValueError, lambda: F.from_expr(2**x))
130    raises(ValueError, lambda: F.from_expr(7*x + sqrt(2)))
131
132    assert isinstance(ZZ[2**x].get_field().convert(2**(-x)),
133        FracElement)
134    assert isinstance(ZZ[x**2].get_field().convert(x**(-6)),
135        FracElement)
136    assert isinstance(ZZ[exp(Rational(1, 3))].get_field().convert(E),
137        FracElement)
138
139
140def test_FracField_nested():
141    a, b, x = symbols('a b x')
142    F1 = ZZ.frac_field(a, b)
143    F2 = F1.frac_field(x)
144    frac = F2(a + b)
145    assert frac.numer == F1.poly_ring(x)(a + b)
146    assert frac.numer.coeffs() == [F1(a + b)]
147    assert frac.denom == F1.poly_ring(x)(1)
148
149    F3 = ZZ.poly_ring(a, b)
150    F4 = F3.frac_field(x)
151    frac = F4(a + b)
152    assert frac.numer == F3.poly_ring(x)(a + b)
153    assert frac.numer.coeffs() == [F3(a + b)]
154    assert frac.denom == F3.poly_ring(x)(1)
155
156    frac = F2(F3(a + b))
157    assert frac.numer == F1.poly_ring(x)(a + b)
158    assert frac.numer.coeffs() == [F1(a + b)]
159    assert frac.denom == F1.poly_ring(x)(1)
160
161    frac = F4(F1(a + b))
162    assert frac.numer == F3.poly_ring(x)(a + b)
163    assert frac.numer.coeffs() == [F3(a + b)]
164    assert frac.denom == F3.poly_ring(x)(1)
165
166
167def test_FracElement__lt_le_gt_ge__():
168    F, x, y = field("x,y", ZZ)
169
170    assert F(1) < 1/x < 1/x**2 < 1/x**3
171    assert F(1) <= 1/x <= 1/x**2 <= 1/x**3
172
173    assert -7/x < 1/x < 3/x < y/x < 1/x**2
174    assert -7/x <= 1/x <= 3/x <= y/x <= 1/x**2
175
176    assert 1/x**3 > 1/x**2 > 1/x > F(1)
177    assert 1/x**3 >= 1/x**2 >= 1/x >= F(1)
178
179    assert 1/x**2 > y/x > 3/x > 1/x > -7/x
180    assert 1/x**2 >= y/x >= 3/x >= 1/x >= -7/x
181
182def test_FracElement___neg__():
183    F, x,y = field("x,y", QQ)
184
185    f = (7*x - 9)/y
186    g = (-7*x + 9)/y
187
188    assert -f == g
189    assert -g == f
190
191def test_FracElement___add__():
192    F, x,y = field("x,y", QQ)
193
194    f, g = 1/x, 1/y
195    assert f + g == g + f == (x + y)/(x*y)
196
197    assert x + F.ring.gens[0] == F.ring.gens[0] + x == 2*x
198
199    F, x,y = field("x,y", ZZ)
200    assert x + 3 == 3 + x
201    assert x + QQ(3,7) == QQ(3,7) + x == (7*x + 3)/7
202
203    Fuv, u,v = field("u,v", ZZ)
204    Fxyzt, x,y,z,t = field("x,y,z,t", Fuv)
205
206    f = (u*v + x)/(y + u*v)
207    assert dict(f.numer) == {(1, 0, 0, 0): 1, (0, 0, 0, 0): u*v}
208    assert dict(f.denom) == {(0, 1, 0, 0): 1, (0, 0, 0, 0): u*v}
209
210    Ruv, u,v = ring("u,v", ZZ)
211    Fxyzt, x,y,z,t = field("x,y,z,t", Ruv)
212
213    f = (u*v + x)/(y + u*v)
214    assert dict(f.numer) == {(1, 0, 0, 0): 1, (0, 0, 0, 0): u*v}
215    assert dict(f.denom) == {(0, 1, 0, 0): 1, (0, 0, 0, 0): u*v}
216
217def test_FracElement___sub__():
218    F, x,y = field("x,y", QQ)
219
220    f, g = 1/x, 1/y
221    assert f - g == (-x + y)/(x*y)
222
223    assert x - F.ring.gens[0] == F.ring.gens[0] - x == 0
224
225    F, x,y = field("x,y", ZZ)
226    assert x - 3 == -(3 - x)
227    assert x - QQ(3,7) == -(QQ(3,7) - x) == (7*x - 3)/7
228
229    Fuv, u,v = field("u,v", ZZ)
230    Fxyzt, x,y,z,t = field("x,y,z,t", Fuv)
231
232    f = (u*v - x)/(y - u*v)
233    assert dict(f.numer) == {(1, 0, 0, 0):-1, (0, 0, 0, 0): u*v}
234    assert dict(f.denom) == {(0, 1, 0, 0): 1, (0, 0, 0, 0):-u*v}
235
236    Ruv, u,v = ring("u,v", ZZ)
237    Fxyzt, x,y,z,t = field("x,y,z,t", Ruv)
238
239    f = (u*v - x)/(y - u*v)
240    assert dict(f.numer) == {(1, 0, 0, 0):-1, (0, 0, 0, 0): u*v}
241    assert dict(f.denom) == {(0, 1, 0, 0): 1, (0, 0, 0, 0):-u*v}
242
243def test_FracElement___mul__():
244    F, x,y = field("x,y", QQ)
245
246    f, g = 1/x, 1/y
247    assert f*g == g*f == 1/(x*y)
248
249    assert x*F.ring.gens[0] == F.ring.gens[0]*x == x**2
250
251    F, x,y = field("x,y", ZZ)
252    assert x*3 == 3*x
253    assert x*QQ(3,7) == QQ(3,7)*x == x*Rational(3, 7)
254
255    Fuv, u,v = field("u,v", ZZ)
256    Fxyzt, x,y,z,t = field("x,y,z,t", Fuv)
257
258    f = ((u + 1)*x*y + 1)/((v - 1)*z - t*u*v - 1)
259    assert dict(f.numer) == {(1, 1, 0, 0): u + 1, (0, 0, 0, 0): 1}
260    assert dict(f.denom) == {(0, 0, 1, 0): v - 1, (0, 0, 0, 1): -u*v, (0, 0, 0, 0): -1}
261
262    Ruv, u,v = ring("u,v", ZZ)
263    Fxyzt, x,y,z,t = field("x,y,z,t", Ruv)
264
265    f = ((u + 1)*x*y + 1)/((v - 1)*z - t*u*v - 1)
266    assert dict(f.numer) == {(1, 1, 0, 0): u + 1, (0, 0, 0, 0): 1}
267    assert dict(f.denom) == {(0, 0, 1, 0): v - 1, (0, 0, 0, 1): -u*v, (0, 0, 0, 0): -1}
268
269def test_FracElement___truediv__():
270    F, x,y = field("x,y", QQ)
271
272    f, g = 1/x, 1/y
273    assert f/g == y/x
274
275    assert x/F.ring.gens[0] == F.ring.gens[0]/x == 1
276
277    F, x,y = field("x,y", ZZ)
278    assert x*3 == 3*x
279    assert x/QQ(3,7) == (QQ(3,7)/x)**-1 == x*Rational(7, 3)
280
281    raises(ZeroDivisionError, lambda: x/0)
282    raises(ZeroDivisionError, lambda: 1/(x - x))
283    raises(ZeroDivisionError, lambda: x/(x - x))
284
285    Fuv, u,v = field("u,v", ZZ)
286    Fxyzt, x,y,z,t = field("x,y,z,t", Fuv)
287
288    f = (u*v)/(x*y)
289    assert dict(f.numer) == {(0, 0, 0, 0): u*v}
290    assert dict(f.denom) == {(1, 1, 0, 0): 1}
291
292    g = (x*y)/(u*v)
293    assert dict(g.numer) == {(1, 1, 0, 0): 1}
294    assert dict(g.denom) == {(0, 0, 0, 0): u*v}
295
296    Ruv, u,v = ring("u,v", ZZ)
297    Fxyzt, x,y,z,t = field("x,y,z,t", Ruv)
298
299    f = (u*v)/(x*y)
300    assert dict(f.numer) == {(0, 0, 0, 0): u*v}
301    assert dict(f.denom) == {(1, 1, 0, 0): 1}
302
303    g = (x*y)/(u*v)
304    assert dict(g.numer) == {(1, 1, 0, 0): 1}
305    assert dict(g.denom) == {(0, 0, 0, 0): u*v}
306
307def test_FracElement___pow__():
308    F, x,y = field("x,y", QQ)
309
310    f, g = 1/x, 1/y
311
312    assert f**3 == 1/x**3
313    assert g**3 == 1/y**3
314
315    assert (f*g)**3 == 1/(x**3*y**3)
316    assert (f*g)**-3 == (x*y)**3
317
318    raises(ZeroDivisionError, lambda: (x - x)**-3)
319
320def test_FracElement_diff():
321    F, x,y,z = field("x,y,z", ZZ)
322
323    assert ((x**2 + y)/(z + 1)).diff(x) == 2*x/(z + 1)
324
325@XFAIL
326def test_FracElement___call__():
327    F, x,y,z = field("x,y,z", ZZ)
328    f = (x**2 + 3*y)/z
329
330    r = f(1, 1, 1)
331    assert r == 4 and not isinstance(r, FracElement)
332    raises(ZeroDivisionError, lambda: f(1, 1, 0))
333
334def test_FracElement_evaluate():
335    F, x,y,z = field("x,y,z", ZZ)
336    Fyz = field("y,z", ZZ)[0]
337    f = (x**2 + 3*y)/z
338
339    assert f.evaluate(x, 0) == 3*Fyz.y/Fyz.z
340    raises(ZeroDivisionError, lambda: f.evaluate(z, 0))
341
342def test_FracElement_subs():
343    F, x,y,z = field("x,y,z", ZZ)
344    f = (x**2 + 3*y)/z
345
346    assert f.subs(x, 0) == 3*y/z
347    raises(ZeroDivisionError, lambda: f.subs(z, 0))
348
349def test_FracElement_compose():
350    pass
351
352def test_FracField_index():
353    a = symbols("a")
354    F, x, y, z = field('x y z', QQ)
355    assert F.index(x) == 0
356    assert F.index(y) == 1
357
358    raises(ValueError, lambda: F.index(1))
359    raises(ValueError, lambda: F.index(a))
360    pass
361