1#
2# test_linsolve.py
3#
4#    Test the internal implementation of linsolve.
5#
6
7from sympy.testing.pytest import raises
8
9from sympy import S, Eq, I
10from sympy.abc import x, y, z
11
12from sympy.polys.matrices.linsolve import _linsolve
13from sympy.polys.solvers import PolyNonlinearError
14
15
16def test__linsolve():
17    assert _linsolve([], [x]) == {x:x}
18    assert _linsolve([S.Zero], [x]) == {x:x}
19    assert _linsolve([x-1,x-2], [x]) is None
20    assert _linsolve([x-1], [x]) == {x:1}
21    assert _linsolve([x-1, y], [x, y]) == {x:1, y:S.Zero}
22    assert _linsolve([2*I], [x]) is None
23    raises(PolyNonlinearError, lambda: _linsolve([x*(1 + x)], [x]))
24
25
26def test__linsolve_float():
27
28    # This should give the exact answer:
29    eqs = [
30        y - x,
31        y - 0.0216 * x
32    ]
33    sol = {x:0.0, y:0.0}
34    assert _linsolve(eqs, (x, y)) == sol
35
36    # Other cases should be close to eps
37
38    def all_close(sol1, sol2, eps=1e-15):
39        close = lambda a, b: abs(a - b) < eps
40        assert sol1.keys() == sol2.keys()
41        return all(close(sol1[s], sol2[s]) for s in sol1)
42
43    eqs = [
44        0.8*x +         0.8*z + 0.2,
45        0.9*x + 0.7*y + 0.2*z + 0.9,
46        0.7*x + 0.2*y + 0.2*z + 0.5
47    ]
48    sol_exact = {x:-29/42, y:-11/21, z:37/84}
49    sol_linsolve = _linsolve(eqs, [x,y,z])
50    assert all_close(sol_exact, sol_linsolve)
51
52    eqs = [
53        0.9*x + 0.3*y + 0.4*z + 0.6,
54        0.6*x + 0.9*y + 0.1*z + 0.7,
55        0.4*x + 0.6*y + 0.9*z + 0.5
56    ]
57    sol_exact = {x:-88/175, y:-46/105, z:-1/25}
58    sol_linsolve = _linsolve(eqs, [x,y,z])
59    assert all_close(sol_exact, sol_linsolve)
60
61    eqs = [
62        0.4*x + 0.3*y + 0.6*z + 0.7,
63        0.4*x + 0.3*y + 0.9*z + 0.9,
64        0.7*x + 0.9*y,
65    ]
66    sol_exact = {x:-9/5, y:7/5, z:-2/3}
67    sol_linsolve = _linsolve(eqs, [x,y,z])
68    assert all_close(sol_exact, sol_linsolve)
69
70    eqs = [
71        x*(0.7 + 0.6*I) + y*(0.4 + 0.7*I) + z*(0.9 + 0.1*I) + 0.5,
72        0.2*I*x + 0.2*I*y + z*(0.9 + 0.2*I) + 0.1,
73        x*(0.9 + 0.7*I) + y*(0.9 + 0.7*I) + z*(0.9 + 0.4*I) + 0.4,
74    ]
75    sol_exact = {
76        x:-6157/7995 - 411/5330*I,
77        y:8519/15990 + 1784/7995*I,
78        z:-34/533 + 107/1599*I,
79    }
80    sol_linsolve = _linsolve(eqs, [x,y,z])
81    assert all_close(sol_exact, sol_linsolve)
82
83    # XXX: This system for x and y over RR(z) is problematic.
84    #
85    # eqs = [
86    #     x*(0.2*z + 0.9) + y*(0.5*z + 0.8) + 0.6,
87    #     0.1*x*z + y*(0.1*z + 0.6) + 0.9,
88    # ]
89    #
90    # linsolve(eqs, [x, y])
91    # The solution for x comes out as
92    #
93    #       -3.9e-5*z**2 - 3.6e-5*z - 8.67361737988404e-20
94    #  x =  ----------------------------------------------
95    #           3.0e-6*z**3 - 1.3e-5*z**2 - 5.4e-5*z
96    #
97    # The 8e-20 in the numerator should be zero which would allow z to cancel
98    # from top and bottom. It should be possible to avoid this somehow because
99    # the inverse of the matrix only has a quadratic factor (the determinant)
100    # in the denominator.
101
102
103def test__linsolve_deprecated():
104    assert _linsolve([Eq(x**2, x**2+y)], [x, y]) == {x:x, y:S.Zero}
105    assert _linsolve([(x+y)**2-x**2], [x]) == {x:-y/2}
106    assert _linsolve([Eq((x+y)**2, x**2)], [x]) == {x:-y/2}
107