passagemath-symbolics 10.6.37__cp314-cp314t-macosx_13_0_arm64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- passagemath_symbolics/.dylibs/libgmp.10.dylib +0 -0
- passagemath_symbolics/__init__.py +3 -0
- passagemath_symbolics-10.6.37.dist-info/METADATA +187 -0
- passagemath_symbolics-10.6.37.dist-info/RECORD +172 -0
- passagemath_symbolics-10.6.37.dist-info/WHEEL +6 -0
- passagemath_symbolics-10.6.37.dist-info/top_level.txt +3 -0
- sage/all__sagemath_symbolics.py +17 -0
- sage/calculus/all.py +14 -0
- sage/calculus/calculus.py +2826 -0
- sage/calculus/desolvers.py +1866 -0
- sage/calculus/predefined.py +51 -0
- sage/calculus/tests.py +225 -0
- sage/calculus/var.cpython-314t-darwin.so +0 -0
- sage/calculus/var.pyx +401 -0
- sage/dynamics/all__sagemath_symbolics.py +6 -0
- sage/dynamics/complex_dynamics/all.py +5 -0
- sage/dynamics/complex_dynamics/mandel_julia.py +765 -0
- sage/dynamics/complex_dynamics/mandel_julia_helper.cpython-314t-darwin.so +0 -0
- sage/dynamics/complex_dynamics/mandel_julia_helper.pyx +1035 -0
- sage/ext/all__sagemath_symbolics.py +1 -0
- sage/ext_data/kenzo/CP2.txt +45 -0
- sage/ext_data/kenzo/CP3.txt +349 -0
- sage/ext_data/kenzo/CP4.txt +4774 -0
- sage/ext_data/kenzo/README.txt +49 -0
- sage/ext_data/kenzo/S4.txt +20 -0
- sage/ext_data/magma/latex/latex.m +1021 -0
- sage/ext_data/magma/latex/latex.spec +1 -0
- sage/ext_data/magma/sage/basic.m +356 -0
- sage/ext_data/magma/sage/sage.spec +1 -0
- sage/ext_data/magma/spec +9 -0
- sage/geometry/all__sagemath_symbolics.py +8 -0
- sage/geometry/hyperbolic_space/all.py +5 -0
- sage/geometry/hyperbolic_space/hyperbolic_coercion.py +743 -0
- sage/geometry/hyperbolic_space/hyperbolic_constants.py +5 -0
- sage/geometry/hyperbolic_space/hyperbolic_geodesic.py +2409 -0
- sage/geometry/hyperbolic_space/hyperbolic_interface.py +206 -0
- sage/geometry/hyperbolic_space/hyperbolic_isometry.py +1082 -0
- sage/geometry/hyperbolic_space/hyperbolic_model.py +1502 -0
- sage/geometry/hyperbolic_space/hyperbolic_point.py +621 -0
- sage/geometry/riemannian_manifolds/all.py +7 -0
- sage/geometry/riemannian_manifolds/parametrized_surface3d.py +1632 -0
- sage/geometry/riemannian_manifolds/surface3d_generators.py +461 -0
- sage/interfaces/all__sagemath_symbolics.py +1 -0
- sage/interfaces/magma.py +3017 -0
- sage/interfaces/magma_free.py +92 -0
- sage/interfaces/maple.py +1397 -0
- sage/interfaces/mathematica.py +1345 -0
- sage/interfaces/mathics.py +1312 -0
- sage/interfaces/sympy.py +1398 -0
- sage/interfaces/sympy_wrapper.py +197 -0
- sage/interfaces/tides.py +938 -0
- sage/libs/all__sagemath_symbolics.py +6 -0
- sage/manifolds/all.py +7 -0
- sage/manifolds/calculus_method.py +555 -0
- sage/manifolds/catalog.py +437 -0
- sage/manifolds/chart.py +4019 -0
- sage/manifolds/chart_func.py +3419 -0
- sage/manifolds/continuous_map.py +2183 -0
- sage/manifolds/continuous_map_image.py +155 -0
- sage/manifolds/differentiable/affine_connection.py +2475 -0
- sage/manifolds/differentiable/all.py +1 -0
- sage/manifolds/differentiable/automorphismfield.py +1383 -0
- sage/manifolds/differentiable/automorphismfield_group.py +604 -0
- sage/manifolds/differentiable/bundle_connection.py +1445 -0
- sage/manifolds/differentiable/characteristic_cohomology_class.py +1840 -0
- sage/manifolds/differentiable/chart.py +1241 -0
- sage/manifolds/differentiable/curve.py +1028 -0
- sage/manifolds/differentiable/de_rham_cohomology.py +541 -0
- sage/manifolds/differentiable/degenerate.py +559 -0
- sage/manifolds/differentiable/degenerate_submanifold.py +1671 -0
- sage/manifolds/differentiable/diff_form.py +1658 -0
- sage/manifolds/differentiable/diff_form_module.py +1062 -0
- sage/manifolds/differentiable/diff_map.py +1315 -0
- sage/manifolds/differentiable/differentiable_submanifold.py +291 -0
- sage/manifolds/differentiable/examples/all.py +1 -0
- sage/manifolds/differentiable/examples/euclidean.py +2517 -0
- sage/manifolds/differentiable/examples/real_line.py +897 -0
- sage/manifolds/differentiable/examples/sphere.py +1186 -0
- sage/manifolds/differentiable/examples/symplectic_space.py +187 -0
- sage/manifolds/differentiable/examples/symplectic_space_test.py +40 -0
- sage/manifolds/differentiable/integrated_curve.py +4035 -0
- sage/manifolds/differentiable/levi_civita_connection.py +841 -0
- sage/manifolds/differentiable/manifold.py +4254 -0
- sage/manifolds/differentiable/manifold_homset.py +1826 -0
- sage/manifolds/differentiable/metric.py +3032 -0
- sage/manifolds/differentiable/mixed_form.py +1507 -0
- sage/manifolds/differentiable/mixed_form_algebra.py +559 -0
- sage/manifolds/differentiable/multivector_module.py +800 -0
- sage/manifolds/differentiable/multivectorfield.py +1520 -0
- sage/manifolds/differentiable/poisson_tensor.py +268 -0
- sage/manifolds/differentiable/pseudo_riemannian.py +755 -0
- sage/manifolds/differentiable/pseudo_riemannian_submanifold.py +1839 -0
- sage/manifolds/differentiable/scalarfield.py +1343 -0
- sage/manifolds/differentiable/scalarfield_algebra.py +472 -0
- sage/manifolds/differentiable/symplectic_form.py +910 -0
- sage/manifolds/differentiable/symplectic_form_test.py +220 -0
- sage/manifolds/differentiable/tangent_space.py +412 -0
- sage/manifolds/differentiable/tangent_vector.py +616 -0
- sage/manifolds/differentiable/tensorfield.py +4665 -0
- sage/manifolds/differentiable/tensorfield_module.py +963 -0
- sage/manifolds/differentiable/tensorfield_paral.py +2450 -0
- sage/manifolds/differentiable/tensorfield_paral_test.py +16 -0
- sage/manifolds/differentiable/vector_bundle.py +1728 -0
- sage/manifolds/differentiable/vectorfield.py +1717 -0
- sage/manifolds/differentiable/vectorfield_module.py +2445 -0
- sage/manifolds/differentiable/vectorframe.py +1832 -0
- sage/manifolds/family.py +270 -0
- sage/manifolds/local_frame.py +1490 -0
- sage/manifolds/manifold.py +3090 -0
- sage/manifolds/manifold_homset.py +452 -0
- sage/manifolds/operators.py +359 -0
- sage/manifolds/point.py +994 -0
- sage/manifolds/scalarfield.py +3718 -0
- sage/manifolds/scalarfield_algebra.py +629 -0
- sage/manifolds/section.py +3111 -0
- sage/manifolds/section_module.py +831 -0
- sage/manifolds/structure.py +229 -0
- sage/manifolds/subset.py +2764 -0
- sage/manifolds/subsets/all.py +1 -0
- sage/manifolds/subsets/closure.py +131 -0
- sage/manifolds/subsets/pullback.py +885 -0
- sage/manifolds/topological_submanifold.py +891 -0
- sage/manifolds/trivialization.py +733 -0
- sage/manifolds/utilities.py +1348 -0
- sage/manifolds/vector_bundle.py +1342 -0
- sage/manifolds/vector_bundle_fiber.py +332 -0
- sage/manifolds/vector_bundle_fiber_element.py +111 -0
- sage/matrix/all__sagemath_symbolics.py +1 -0
- sage/matrix/matrix_symbolic_dense.cpython-314t-darwin.so +0 -0
- sage/matrix/matrix_symbolic_dense.pxd +6 -0
- sage/matrix/matrix_symbolic_dense.pyx +1022 -0
- sage/matrix/matrix_symbolic_sparse.cpython-314t-darwin.so +0 -0
- sage/matrix/matrix_symbolic_sparse.pxd +6 -0
- sage/matrix/matrix_symbolic_sparse.pyx +1029 -0
- sage/modules/all__sagemath_symbolics.py +1 -0
- sage/modules/vector_callable_symbolic_dense.py +105 -0
- sage/modules/vector_symbolic_dense.py +116 -0
- sage/modules/vector_symbolic_sparse.py +118 -0
- sage/rings/all__sagemath_symbolics.py +4 -0
- sage/rings/asymptotic/all.py +6 -0
- sage/rings/asymptotic/asymptotic_expansion_generators.py +1485 -0
- sage/rings/asymptotic/asymptotic_ring.py +4858 -0
- sage/rings/asymptotic/asymptotics_multivariate_generating_functions.py +4153 -0
- sage/rings/asymptotic/growth_group.py +5373 -0
- sage/rings/asymptotic/growth_group_cartesian.py +1400 -0
- sage/rings/asymptotic/term_monoid.py +5237 -0
- sage/rings/function_field/all__sagemath_symbolics.py +2 -0
- sage/rings/polynomial/all__sagemath_symbolics.py +1 -0
- sage/symbolic/all.py +15 -0
- sage/symbolic/assumptions.py +985 -0
- sage/symbolic/benchmark.py +93 -0
- sage/symbolic/callable.py +459 -0
- sage/symbolic/complexity_measures.py +35 -0
- sage/symbolic/constants.py +1287 -0
- sage/symbolic/expression_conversion_algebraic.py +310 -0
- sage/symbolic/expression_conversion_sympy.py +317 -0
- sage/symbolic/expression_conversions.py +1713 -0
- sage/symbolic/function_factory.py +355 -0
- sage/symbolic/integration/all.py +1 -0
- sage/symbolic/integration/external.py +270 -0
- sage/symbolic/integration/integral.py +1115 -0
- sage/symbolic/maxima_wrapper.py +162 -0
- sage/symbolic/operators.py +267 -0
- sage/symbolic/random_tests.py +462 -0
- sage/symbolic/relation.py +1907 -0
- sage/symbolic/ring.cpython-314t-darwin.so +0 -0
- sage/symbolic/ring.pxd +5 -0
- sage/symbolic/ring.pyx +1396 -0
- sage/symbolic/subring.py +1025 -0
- sage/symbolic/symengine.py +19 -0
- sage/symbolic/tests.py +40 -0
- sage/symbolic/units.py +1470 -0
|
@@ -0,0 +1,1907 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-symbolics
|
|
2
|
+
r"""
|
|
3
|
+
Symbolic Equations and Inequalities
|
|
4
|
+
|
|
5
|
+
Sage can solve symbolic equations and inequalities. For
|
|
6
|
+
example, we derive the quadratic formula as follows::
|
|
7
|
+
|
|
8
|
+
sage: a,b,c = var('a,b,c')
|
|
9
|
+
sage: qe = (a*x^2 + b*x + c == 0)
|
|
10
|
+
sage: qe
|
|
11
|
+
a*x^2 + b*x + c == 0
|
|
12
|
+
sage: print(solve(qe, x))
|
|
13
|
+
[
|
|
14
|
+
x == -1/2*(b + sqrt(b^2 - 4*a*c))/a,
|
|
15
|
+
x == -1/2*(b - sqrt(b^2 - 4*a*c))/a
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
The operator, left hand side, and right hand side
|
|
20
|
+
--------------------------------------------------
|
|
21
|
+
|
|
22
|
+
Operators::
|
|
23
|
+
|
|
24
|
+
sage: eqn = x^3 + 2/3 >= x - pi
|
|
25
|
+
sage: eqn.operator()
|
|
26
|
+
<built-in function ge>
|
|
27
|
+
sage: (x^3 + 2/3 < x - pi).operator()
|
|
28
|
+
<built-in function lt>
|
|
29
|
+
sage: (x^3 + 2/3 == x - pi).operator()
|
|
30
|
+
<built-in function eq>
|
|
31
|
+
|
|
32
|
+
Left hand side::
|
|
33
|
+
|
|
34
|
+
sage: eqn = x^3 + 2/3 >= x - pi
|
|
35
|
+
sage: eqn.lhs()
|
|
36
|
+
x^3 + 2/3
|
|
37
|
+
sage: eqn.left()
|
|
38
|
+
x^3 + 2/3
|
|
39
|
+
sage: eqn.left_hand_side()
|
|
40
|
+
x^3 + 2/3
|
|
41
|
+
|
|
42
|
+
Right hand side::
|
|
43
|
+
|
|
44
|
+
sage: (x + sqrt(2) >= sqrt(3) + 5/2).right()
|
|
45
|
+
sqrt(3) + 5/2
|
|
46
|
+
sage: (x + sqrt(2) >= sqrt(3) + 5/2).rhs()
|
|
47
|
+
sqrt(3) + 5/2
|
|
48
|
+
sage: (x + sqrt(2) >= sqrt(3) + 5/2).right_hand_side()
|
|
49
|
+
sqrt(3) + 5/2
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
Arithmetic
|
|
53
|
+
----------
|
|
54
|
+
Add two symbolic equations::
|
|
55
|
+
|
|
56
|
+
sage: var('a,b')
|
|
57
|
+
(a, b)
|
|
58
|
+
sage: m = 144 == -10 * a + b
|
|
59
|
+
sage: n = 136 == 10 * a + b
|
|
60
|
+
sage: m + n
|
|
61
|
+
280 == 2*b
|
|
62
|
+
sage: int(-144) + m
|
|
63
|
+
0 == -10*a + b - 144
|
|
64
|
+
|
|
65
|
+
Subtract two symbolic equations::
|
|
66
|
+
|
|
67
|
+
sage: var('a,b')
|
|
68
|
+
(a, b)
|
|
69
|
+
sage: m = 144 == 20 * a + b
|
|
70
|
+
sage: n = 136 == 10 * a + b
|
|
71
|
+
sage: m - n
|
|
72
|
+
8 == 10*a
|
|
73
|
+
sage: int(144) - m
|
|
74
|
+
0 == -20*a - b + 144
|
|
75
|
+
|
|
76
|
+
Multiply two symbolic equations::
|
|
77
|
+
|
|
78
|
+
sage: x = var('x')
|
|
79
|
+
sage: m = x == 5*x + 1
|
|
80
|
+
sage: n = sin(x) == sin(x+2*pi, hold=True)
|
|
81
|
+
sage: m * n
|
|
82
|
+
x*sin(x) == (5*x + 1)*sin(2*pi + x)
|
|
83
|
+
sage: m = 2*x == 3*x^2 - 5
|
|
84
|
+
sage: int(-1) * m
|
|
85
|
+
-2*x == -3*x^2 + 5
|
|
86
|
+
|
|
87
|
+
Divide two symbolic equations::
|
|
88
|
+
|
|
89
|
+
sage: x = var('x')
|
|
90
|
+
sage: m = x == 5*x + 1
|
|
91
|
+
sage: n = sin(x) == sin(x+2*pi, hold=True)
|
|
92
|
+
sage: m/n
|
|
93
|
+
x/sin(x) == (5*x + 1)/sin(2*pi + x)
|
|
94
|
+
sage: m = x != 5*x + 1
|
|
95
|
+
sage: n = sin(x) != sin(x+2*pi, hold=True)
|
|
96
|
+
sage: m/n
|
|
97
|
+
x/sin(x) != (5*x + 1)/sin(2*pi + x)
|
|
98
|
+
|
|
99
|
+
Substitution
|
|
100
|
+
------------
|
|
101
|
+
|
|
102
|
+
Substitution into relations::
|
|
103
|
+
|
|
104
|
+
sage: x, a = var('x, a')
|
|
105
|
+
sage: eq = (x^3 + a == sin(x/a)); eq
|
|
106
|
+
x^3 + a == sin(x/a)
|
|
107
|
+
sage: eq.substitute(x=5*x)
|
|
108
|
+
125*x^3 + a == sin(5*x/a)
|
|
109
|
+
sage: eq.substitute(a=1)
|
|
110
|
+
x^3 + 1 == sin(x)
|
|
111
|
+
sage: eq.substitute(a=x)
|
|
112
|
+
x^3 + x == sin(1)
|
|
113
|
+
sage: eq.substitute(a=x, x=1)
|
|
114
|
+
x + 1 == sin(1/x)
|
|
115
|
+
sage: eq.substitute({a:x, x:1})
|
|
116
|
+
x + 1 == sin(1/x)
|
|
117
|
+
|
|
118
|
+
You can even substitute multivariable and matrix
|
|
119
|
+
expressions::
|
|
120
|
+
|
|
121
|
+
sage: x,y = var('x, y')
|
|
122
|
+
sage: M = Matrix([[x+1,y],[x^2,y^3]]); M
|
|
123
|
+
[x + 1 y]
|
|
124
|
+
[ x^2 y^3]
|
|
125
|
+
sage: M.substitute({x:0,y:1})
|
|
126
|
+
[1 1]
|
|
127
|
+
[0 1]
|
|
128
|
+
|
|
129
|
+
Solving
|
|
130
|
+
-------
|
|
131
|
+
|
|
132
|
+
We can solve equations::
|
|
133
|
+
|
|
134
|
+
sage: x = var('x')
|
|
135
|
+
sage: S = solve(x^3 - 1 == 0, x)
|
|
136
|
+
sage: S
|
|
137
|
+
[x == 1/2*I*sqrt(3) - 1/2, x == -1/2*I*sqrt(3) - 1/2, x == 1]
|
|
138
|
+
sage: S[0]
|
|
139
|
+
x == 1/2*I*sqrt(3) - 1/2
|
|
140
|
+
sage: S[0].right()
|
|
141
|
+
1/2*I*sqrt(3) - 1/2
|
|
142
|
+
sage: S = solve(x^3 - 1 == 0, x, solution_dict=True)
|
|
143
|
+
sage: S
|
|
144
|
+
[{x: 1/2*I*sqrt(3) - 1/2}, {x: -1/2*I*sqrt(3) - 1/2}, {x: 1}]
|
|
145
|
+
sage: z = 5
|
|
146
|
+
sage: solve(z^2 == sqrt(3),z)
|
|
147
|
+
Traceback (most recent call last):
|
|
148
|
+
...
|
|
149
|
+
TypeError: 5 is not a valid variable.
|
|
150
|
+
|
|
151
|
+
We can also solve equations involving matrices. The following
|
|
152
|
+
example defines a multivariable function ``f(x,y)``, then solves
|
|
153
|
+
for where the partial derivatives with respect to ``x``
|
|
154
|
+
and ``y`` are zero. Then it substitutes one of the solutions
|
|
155
|
+
into the Hessian matrix ``H`` for ``f``::
|
|
156
|
+
|
|
157
|
+
sage: f(x,y) = x^2*y+y^2+y
|
|
158
|
+
sage: solutions = solve(list(f.diff()),[x,y],solution_dict=True)
|
|
159
|
+
sage: solutions == [{x: -I, y: 0}, {x: I, y: 0}, {x: 0, y: -1/2}]
|
|
160
|
+
True
|
|
161
|
+
sage: H = f.diff(2) # Hessian matrix
|
|
162
|
+
sage: H.subs(solutions[2])
|
|
163
|
+
[(x, y) |--> -1 (x, y) |--> 0]
|
|
164
|
+
[ (x, y) |--> 0 (x, y) |--> 2]
|
|
165
|
+
sage: H(x,y).subs(solutions[2])
|
|
166
|
+
[-1 0]
|
|
167
|
+
[ 0 2]
|
|
168
|
+
|
|
169
|
+
We illustrate finding multiplicities of solutions::
|
|
170
|
+
|
|
171
|
+
sage: f = (x-1)^5*(x^2+1)
|
|
172
|
+
sage: solve(f == 0, x)
|
|
173
|
+
[x == -I, x == I, x == 1]
|
|
174
|
+
sage: solve(f == 0, x, multiplicities=True)
|
|
175
|
+
([x == -I, x == I, x == 1], [1, 1, 5])
|
|
176
|
+
|
|
177
|
+
We can also solve many inequalities::
|
|
178
|
+
|
|
179
|
+
sage: solve(1/(x-1)<=8,x)
|
|
180
|
+
[[x < 1], [x >= (9/8)]]
|
|
181
|
+
|
|
182
|
+
We can numerically find roots of equations::
|
|
183
|
+
|
|
184
|
+
sage: (x == sin(x)).find_root(-2,2) # needs scipy
|
|
185
|
+
0.0
|
|
186
|
+
sage: (x^5 + 3*x + 2 == 0).find_root(-2,2,x) # needs scipy
|
|
187
|
+
-0.6328345202421523
|
|
188
|
+
sage: (cos(x) == sin(x)).find_root(10,20) # needs scipy
|
|
189
|
+
19.634954084936208
|
|
190
|
+
|
|
191
|
+
We illustrate some valid error conditions::
|
|
192
|
+
|
|
193
|
+
sage: (cos(x) != sin(x)).find_root(10,20) # needs scipy
|
|
194
|
+
Traceback (most recent call last):
|
|
195
|
+
...
|
|
196
|
+
ValueError: Symbolic equation must be an equality.
|
|
197
|
+
sage: (SR(3)==SR(2)).find_root(-1,1) # needs scipy
|
|
198
|
+
Traceback (most recent call last):
|
|
199
|
+
...
|
|
200
|
+
RuntimeError: no zero in the interval, since constant expression is not 0.
|
|
201
|
+
|
|
202
|
+
There must be at most one variable::
|
|
203
|
+
|
|
204
|
+
sage: x, y = var('x,y')
|
|
205
|
+
sage: (x == y).find_root(-2,2) # needs scipy
|
|
206
|
+
Traceback (most recent call last):
|
|
207
|
+
...
|
|
208
|
+
NotImplementedError: root finding currently only implemented in 1 dimension.
|
|
209
|
+
|
|
210
|
+
Assumptions
|
|
211
|
+
-----------
|
|
212
|
+
|
|
213
|
+
Forgetting assumptions::
|
|
214
|
+
|
|
215
|
+
sage: var('x,y')
|
|
216
|
+
(x, y)
|
|
217
|
+
sage: forget() #Clear assumptions
|
|
218
|
+
sage: assume(x>0, y < 2)
|
|
219
|
+
sage: assumptions()
|
|
220
|
+
[x > 0, y < 2]
|
|
221
|
+
sage: (y < 2).forget()
|
|
222
|
+
sage: assumptions()
|
|
223
|
+
[x > 0]
|
|
224
|
+
sage: forget()
|
|
225
|
+
sage: assumptions()
|
|
226
|
+
[]
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
Miscellaneous
|
|
230
|
+
-------------
|
|
231
|
+
|
|
232
|
+
Conversion to Maxima::
|
|
233
|
+
|
|
234
|
+
sage: x = var('x')
|
|
235
|
+
sage: eq = (x^(3/5) >= pi^2 + e^i)
|
|
236
|
+
sage: eq._maxima_init_()
|
|
237
|
+
'(_SAGE_VAR_x)^(3/5) >= ((%pi)^(2))+(exp(0+%i*1))'
|
|
238
|
+
sage: e1 = x^3 + x == sin(2*x)
|
|
239
|
+
sage: z = e1._maxima_()
|
|
240
|
+
sage: z.parent() is sage.calculus.calculus.maxima
|
|
241
|
+
True
|
|
242
|
+
sage: z = e1._maxima_(maxima)
|
|
243
|
+
sage: z.parent() is maxima
|
|
244
|
+
True
|
|
245
|
+
sage: z = maxima(e1)
|
|
246
|
+
sage: z.parent() is maxima
|
|
247
|
+
True
|
|
248
|
+
|
|
249
|
+
Conversion to Maple::
|
|
250
|
+
|
|
251
|
+
sage: x = var('x')
|
|
252
|
+
sage: eq = (x == 2)
|
|
253
|
+
sage: eq._maple_init_()
|
|
254
|
+
'x = 2'
|
|
255
|
+
|
|
256
|
+
Comparison::
|
|
257
|
+
|
|
258
|
+
sage: x = var('x')
|
|
259
|
+
sage: (x>0) == (x>0)
|
|
260
|
+
True
|
|
261
|
+
sage: (x>0) == (x>1)
|
|
262
|
+
False
|
|
263
|
+
sage: (x>0) != (x>1)
|
|
264
|
+
True
|
|
265
|
+
|
|
266
|
+
Variables appearing in the relation::
|
|
267
|
+
|
|
268
|
+
sage: var('x,y,z,w')
|
|
269
|
+
(x, y, z, w)
|
|
270
|
+
sage: f = (x+y+w) == (x^2 - y^2 - z^3); f
|
|
271
|
+
w + x + y == -z^3 + x^2 - y^2
|
|
272
|
+
sage: f.variables()
|
|
273
|
+
(w, x, y, z)
|
|
274
|
+
|
|
275
|
+
LaTeX output::
|
|
276
|
+
|
|
277
|
+
sage: latex(x^(3/5) >= pi)
|
|
278
|
+
x^{\frac{3}{5}} \geq \pi
|
|
279
|
+
|
|
280
|
+
When working with the symbolic complex number `I`, notice that comparisons do not
|
|
281
|
+
automatically simplify even in trivial situations::
|
|
282
|
+
|
|
283
|
+
sage: SR(I)^2 == -1
|
|
284
|
+
-1 == -1
|
|
285
|
+
sage: SR(I)^2 < 0
|
|
286
|
+
-1 < 0
|
|
287
|
+
sage: (SR(I)+1)^4 > 0
|
|
288
|
+
-4 > 0
|
|
289
|
+
|
|
290
|
+
Nevertheless, if you force the comparison, you get the right answer (:issue:`7160`)::
|
|
291
|
+
|
|
292
|
+
sage: bool(SR(I)^2 == -1)
|
|
293
|
+
True
|
|
294
|
+
sage: bool(SR(I)^2 < 0)
|
|
295
|
+
True
|
|
296
|
+
sage: bool((SR(I)+1)^4 > 0)
|
|
297
|
+
False
|
|
298
|
+
|
|
299
|
+
More Examples
|
|
300
|
+
-------------
|
|
301
|
+
|
|
302
|
+
::
|
|
303
|
+
|
|
304
|
+
sage: x,y,a = var('x,y,a')
|
|
305
|
+
sage: f = x^2 + y^2 == 1
|
|
306
|
+
sage: f.solve(x)
|
|
307
|
+
[x == -sqrt(-y^2 + 1), x == sqrt(-y^2 + 1)]
|
|
308
|
+
|
|
309
|
+
::
|
|
310
|
+
|
|
311
|
+
sage: f = x^5 + a
|
|
312
|
+
sage: solve(f==0,x)
|
|
313
|
+
[x == 1/4*(-a)^(1/5)*(sqrt(5) + I*sqrt(2*sqrt(5) + 10) - 1), x == -1/4*(-a)^(1/5)*(sqrt(5) - I*sqrt(-2*sqrt(5) + 10) + 1), x == -1/4*(-a)^(1/5)*(sqrt(5) + I*sqrt(-2*sqrt(5) + 10) + 1), x == 1/4*(-a)^(1/5)*(sqrt(5) - I*sqrt(2*sqrt(5) + 10) - 1), x == (-a)^(1/5)]
|
|
314
|
+
|
|
315
|
+
You can also do arithmetic with inequalities, as illustrated
|
|
316
|
+
below::
|
|
317
|
+
|
|
318
|
+
sage: var('x y')
|
|
319
|
+
(x, y)
|
|
320
|
+
sage: f = x + 3 == y - 2
|
|
321
|
+
sage: f
|
|
322
|
+
x + 3 == y - 2
|
|
323
|
+
sage: g = f - 3; g
|
|
324
|
+
x == y - 5
|
|
325
|
+
sage: h = x^3 + sqrt(2) == x*y*sin(x)
|
|
326
|
+
sage: h
|
|
327
|
+
x^3 + sqrt(2) == x*y*sin(x)
|
|
328
|
+
sage: h - sqrt(2)
|
|
329
|
+
x^3 == x*y*sin(x) - sqrt(2)
|
|
330
|
+
sage: h + f
|
|
331
|
+
x^3 + x + sqrt(2) + 3 == x*y*sin(x) + y - 2
|
|
332
|
+
sage: f = x + 3 < y - 2
|
|
333
|
+
sage: g = 2 < x+10
|
|
334
|
+
sage: f - g
|
|
335
|
+
x + 1 < -x + y - 12
|
|
336
|
+
sage: f + g
|
|
337
|
+
x + 5 < x + y + 8
|
|
338
|
+
sage: f*(-1)
|
|
339
|
+
-x - 3 < -y + 2
|
|
340
|
+
|
|
341
|
+
TESTS:
|
|
342
|
+
|
|
343
|
+
We test serializing symbolic equations::
|
|
344
|
+
|
|
345
|
+
sage: eqn = x^3 + 2/3 >= x
|
|
346
|
+
sage: loads(dumps(eqn))
|
|
347
|
+
x^3 + 2/3 >= x
|
|
348
|
+
sage: loads(dumps(eqn)) == eqn
|
|
349
|
+
True
|
|
350
|
+
|
|
351
|
+
AUTHORS:
|
|
352
|
+
|
|
353
|
+
- Bobby Moretti: initial version (based on a trick that Robert
|
|
354
|
+
Bradshaw suggested).
|
|
355
|
+
|
|
356
|
+
- William Stein: second version
|
|
357
|
+
|
|
358
|
+
- William Stein (2007-07-16): added arithmetic with symbolic equations
|
|
359
|
+
"""
|
|
360
|
+
from itertools import product
|
|
361
|
+
import operator
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
def test_relation_maxima(relation):
|
|
365
|
+
"""
|
|
366
|
+
Return ``True`` if this (in)equality is definitely true. Return ``False``
|
|
367
|
+
if it is false or the algorithm for testing (in)equality is inconclusive.
|
|
368
|
+
|
|
369
|
+
EXAMPLES::
|
|
370
|
+
|
|
371
|
+
sage: from sage.symbolic.relation import test_relation_maxima
|
|
372
|
+
sage: k = var('k')
|
|
373
|
+
sage: pol = 1/(k-1) - 1/k -1/k/(k-1)
|
|
374
|
+
sage: test_relation_maxima(pol == 0)
|
|
375
|
+
True
|
|
376
|
+
sage: f = sin(x)^2 + cos(x)^2 - 1
|
|
377
|
+
sage: test_relation_maxima(f == 0)
|
|
378
|
+
True
|
|
379
|
+
sage: test_relation_maxima( x == x )
|
|
380
|
+
True
|
|
381
|
+
sage: test_relation_maxima( x != x )
|
|
382
|
+
False
|
|
383
|
+
sage: test_relation_maxima( x > x )
|
|
384
|
+
False
|
|
385
|
+
sage: test_relation_maxima( x^2 > x )
|
|
386
|
+
False
|
|
387
|
+
sage: test_relation_maxima( x + 2 > x )
|
|
388
|
+
True
|
|
389
|
+
sage: test_relation_maxima( x - 2 > x )
|
|
390
|
+
False
|
|
391
|
+
|
|
392
|
+
Here are some examples involving assumptions::
|
|
393
|
+
|
|
394
|
+
sage: x, y, z = var('x, y, z')
|
|
395
|
+
sage: assume(x>=y,y>=z,z>=x)
|
|
396
|
+
sage: test_relation_maxima(x==z)
|
|
397
|
+
True
|
|
398
|
+
sage: test_relation_maxima(z<x)
|
|
399
|
+
False
|
|
400
|
+
sage: test_relation_maxima(z>y)
|
|
401
|
+
False
|
|
402
|
+
sage: test_relation_maxima(y==z)
|
|
403
|
+
True
|
|
404
|
+
sage: forget()
|
|
405
|
+
sage: assume(x>=1,x<=1)
|
|
406
|
+
sage: test_relation_maxima(x==1)
|
|
407
|
+
True
|
|
408
|
+
sage: test_relation_maxima(x>1)
|
|
409
|
+
False
|
|
410
|
+
sage: test_relation_maxima(x>=1)
|
|
411
|
+
True
|
|
412
|
+
sage: test_relation_maxima(x!=1)
|
|
413
|
+
False
|
|
414
|
+
sage: forget()
|
|
415
|
+
sage: assume(x>0)
|
|
416
|
+
sage: test_relation_maxima(x==0)
|
|
417
|
+
False
|
|
418
|
+
sage: test_relation_maxima(x>-1)
|
|
419
|
+
True
|
|
420
|
+
sage: test_relation_maxima(x!=0)
|
|
421
|
+
True
|
|
422
|
+
sage: test_relation_maxima(x!=1)
|
|
423
|
+
False
|
|
424
|
+
sage: forget()
|
|
425
|
+
|
|
426
|
+
TESTS:
|
|
427
|
+
|
|
428
|
+
Ensure that ``canonicalize_radical()`` and ``simplify_log`` are not
|
|
429
|
+
used inappropriately, :issue:`17389`. Either one would simplify ``f``
|
|
430
|
+
to zero below::
|
|
431
|
+
|
|
432
|
+
sage: x,y = SR.var('x,y')
|
|
433
|
+
sage: assume(y, 'complex')
|
|
434
|
+
sage: f = log(x*y) - (log(x) + log(y))
|
|
435
|
+
sage: f(x=-1, y=i)
|
|
436
|
+
-2*I*pi
|
|
437
|
+
sage: test_relation_maxima(f == 0)
|
|
438
|
+
False
|
|
439
|
+
sage: forget()
|
|
440
|
+
|
|
441
|
+
Ensure that the ``sqrt(x^2)`` -> ``abs(x)`` simplification is not
|
|
442
|
+
performed when testing equality::
|
|
443
|
+
|
|
444
|
+
sage: assume(x, 'complex')
|
|
445
|
+
sage: f = sqrt(x^2) - abs(x)
|
|
446
|
+
sage: test_relation_maxima(f == 0)
|
|
447
|
+
False
|
|
448
|
+
sage: forget()
|
|
449
|
+
|
|
450
|
+
If assumptions are made, ``simplify_rectform()`` is used::
|
|
451
|
+
|
|
452
|
+
sage: assume(x, 'real')
|
|
453
|
+
sage: f1 = ( e^(I*x) - e^(-I*x) ) / ( I*e^(I*x) + I*e^(-I*x) )
|
|
454
|
+
sage: f2 = sin(x)/cos(x)
|
|
455
|
+
sage: test_relation_maxima(f1 - f2 == 0)
|
|
456
|
+
True
|
|
457
|
+
sage: forget()
|
|
458
|
+
|
|
459
|
+
But not if ``x`` itself is complex::
|
|
460
|
+
|
|
461
|
+
sage: assume(x, 'complex')
|
|
462
|
+
sage: f1 = ( e^(I*x) - e^(-I*x) ) / ( I*e^(I*x) + I*e^(-I*x) )
|
|
463
|
+
sage: f2 = sin(x)/cos(x)
|
|
464
|
+
sage: test_relation_maxima(f1 - f2 == 0)
|
|
465
|
+
False
|
|
466
|
+
sage: forget()
|
|
467
|
+
|
|
468
|
+
If assumptions are made, then ``simplify_factorial()`` is used::
|
|
469
|
+
|
|
470
|
+
sage: n,k = SR.var('n,k')
|
|
471
|
+
sage: assume(n, 'integer')
|
|
472
|
+
sage: assume(k, 'integer')
|
|
473
|
+
sage: f1 = factorial(n+1)/factorial(n)
|
|
474
|
+
sage: f2 = n + 1
|
|
475
|
+
sage: test_relation_maxima(f1 - f2 == 0)
|
|
476
|
+
True
|
|
477
|
+
sage: forget()
|
|
478
|
+
|
|
479
|
+
In case an equation is to be solved for non-integers, ''assume()''
|
|
480
|
+
is used::
|
|
481
|
+
|
|
482
|
+
sage: k = var('k')
|
|
483
|
+
sage: assume(k,'noninteger')
|
|
484
|
+
sage: solve([k^3==1],k)
|
|
485
|
+
[k == 1/2*I*sqrt(3) - 1/2, k == -1/2*I*sqrt(3) - 1/2]
|
|
486
|
+
sage: assumptions()
|
|
487
|
+
[k is noninteger]
|
|
488
|
+
"""
|
|
489
|
+
m = relation._maxima_()
|
|
490
|
+
|
|
491
|
+
# Handle some basic cases first
|
|
492
|
+
if repr(m) in ['0=0']:
|
|
493
|
+
return True
|
|
494
|
+
elif repr(m) in ['0#0', '1#1']:
|
|
495
|
+
return False
|
|
496
|
+
|
|
497
|
+
if relation.operator() == operator.eq: # operator is equality
|
|
498
|
+
try:
|
|
499
|
+
s = m.parent()._eval_line('is (equal(%s,%s))' % (repr(m.lhs()),
|
|
500
|
+
repr(m.rhs())))
|
|
501
|
+
except TypeError:
|
|
502
|
+
raise ValueError("unable to evaluate the predicate '%s'" % repr(relation))
|
|
503
|
+
|
|
504
|
+
elif relation.operator() == operator.ne: # operator is not equal
|
|
505
|
+
try:
|
|
506
|
+
s = m.parent()._eval_line('is (notequal(%s,%s))' % (repr(m.lhs()),
|
|
507
|
+
repr(m.rhs())))
|
|
508
|
+
except TypeError:
|
|
509
|
+
raise ValueError("unable to evaluate the predicate '%s'" % repr(relation))
|
|
510
|
+
|
|
511
|
+
else: # operator is < or > or <= or >=, which Maxima handles fine
|
|
512
|
+
try:
|
|
513
|
+
s = m.parent()._eval_line('is (%s)' % repr(m))
|
|
514
|
+
except TypeError:
|
|
515
|
+
raise ValueError("unable to evaluate the predicate '%s'" % repr(relation))
|
|
516
|
+
|
|
517
|
+
if s == 'true':
|
|
518
|
+
return True
|
|
519
|
+
elif s == 'false':
|
|
520
|
+
return False # if neither of these, s=='unknown' and we try a few other tricks
|
|
521
|
+
|
|
522
|
+
if relation.operator() != operator.eq:
|
|
523
|
+
return False
|
|
524
|
+
|
|
525
|
+
difference = relation.lhs() - relation.rhs()
|
|
526
|
+
if difference.is_trivial_zero():
|
|
527
|
+
return True
|
|
528
|
+
|
|
529
|
+
# Try to apply some simplifications to see if left - right == 0.
|
|
530
|
+
#
|
|
531
|
+
# TODO: If simplify_log() is ever removed from simplify_full(), we
|
|
532
|
+
# can replace all of these individual simplifications with a
|
|
533
|
+
# single call to simplify_full(). That would work in cases where
|
|
534
|
+
# two simplifications are needed consecutively; the current
|
|
535
|
+
# approach does not.
|
|
536
|
+
#
|
|
537
|
+
simp_list = [difference.simplify_factorial(),
|
|
538
|
+
difference.simplify_rational(),
|
|
539
|
+
difference.simplify_rectform(),
|
|
540
|
+
difference.simplify_trig()]
|
|
541
|
+
for f in simp_list:
|
|
542
|
+
try:
|
|
543
|
+
if f().is_trivial_zero():
|
|
544
|
+
return True
|
|
545
|
+
break
|
|
546
|
+
except Exception:
|
|
547
|
+
pass
|
|
548
|
+
return False
|
|
549
|
+
|
|
550
|
+
|
|
551
|
+
def string_to_list_of_solutions(s):
|
|
552
|
+
r"""
|
|
553
|
+
Used internally by the symbolic solve command to convert the output
|
|
554
|
+
of Maxima's solve command to a list of solutions in Sage's symbolic
|
|
555
|
+
package.
|
|
556
|
+
|
|
557
|
+
EXAMPLES:
|
|
558
|
+
|
|
559
|
+
We derive the (monic) quadratic formula::
|
|
560
|
+
|
|
561
|
+
sage: var('x,a,b')
|
|
562
|
+
(x, a, b)
|
|
563
|
+
sage: solve(x^2 + a*x + b == 0, x)
|
|
564
|
+
[x == -1/2*a - 1/2*sqrt(a^2 - 4*b), x == -1/2*a + 1/2*sqrt(a^2 - 4*b)]
|
|
565
|
+
|
|
566
|
+
Behind the scenes when the above is evaluated the function
|
|
567
|
+
:func:`string_to_list_of_solutions` is called with input the
|
|
568
|
+
string `s` below::
|
|
569
|
+
|
|
570
|
+
sage: s = '[x=-(sqrt(a^2-4*b)+a)/2,x=(sqrt(a^2-4*b)-a)/2]'
|
|
571
|
+
sage: sage.symbolic.relation.string_to_list_of_solutions(s)
|
|
572
|
+
[x == -1/2*a - 1/2*sqrt(a^2 - 4*b), x == -1/2*a + 1/2*sqrt(a^2 - 4*b)]
|
|
573
|
+
"""
|
|
574
|
+
from sage.categories.objects import Objects
|
|
575
|
+
from sage.structure.sequence import Sequence
|
|
576
|
+
from sage.calculus.calculus import symbolic_expression_from_maxima_string
|
|
577
|
+
v = symbolic_expression_from_maxima_string(s, equals_sub=True)
|
|
578
|
+
return Sequence(v, universe=Objects(), cr_str=True)
|
|
579
|
+
|
|
580
|
+
###########
|
|
581
|
+
# Solving #
|
|
582
|
+
###########
|
|
583
|
+
|
|
584
|
+
|
|
585
|
+
def solve(f, *args, **kwds):
|
|
586
|
+
r"""
|
|
587
|
+
Algebraically solve an equation or system of equations (over the
|
|
588
|
+
complex numbers) for given variables. Inequalities and systems
|
|
589
|
+
of inequalities are also supported.
|
|
590
|
+
|
|
591
|
+
INPUT:
|
|
592
|
+
|
|
593
|
+
- ``f`` -- equation or system of equations (given by a list or tuple)
|
|
594
|
+
|
|
595
|
+
- ``*args`` -- variables to solve for
|
|
596
|
+
|
|
597
|
+
- ``solution_dict`` -- boolean (default: ``False``); if ``True`` or nonzero,
|
|
598
|
+
return a list of dictionaries containing the solutions. If there
|
|
599
|
+
are no solutions, return an empty list (rather than a list containing
|
|
600
|
+
an empty dictionary). Likewise, if there's only a single solution,
|
|
601
|
+
return a list containing one dictionary with that solution.
|
|
602
|
+
|
|
603
|
+
There are a few optional keywords if you are trying to solve a single
|
|
604
|
+
equation. They may only be used in that context.
|
|
605
|
+
|
|
606
|
+
- ``multiplicities`` -- boolean (default: ``False``); if True,
|
|
607
|
+
return corresponding multiplicities. This keyword is
|
|
608
|
+
incompatible with ``to_poly_solve=True`` and does not make
|
|
609
|
+
any sense when solving inequalities.
|
|
610
|
+
|
|
611
|
+
- ``explicit_solutions`` -- boolean (default: ``False``); require that
|
|
612
|
+
all roots be explicit rather than implicit. Not used
|
|
613
|
+
when solving inequalities.
|
|
614
|
+
|
|
615
|
+
- ``to_poly_solve`` -- boolean (default: ``False``) or string; use
|
|
616
|
+
Maxima's ``to_poly_solver`` package to search for more possible
|
|
617
|
+
solutions, but possibly encounter approximate solutions.
|
|
618
|
+
This keyword is incompatible with ``multiplicities=True``
|
|
619
|
+
and is not used when solving inequalities. Setting ``to_poly_solve``
|
|
620
|
+
to 'force' (string) omits Maxima's solve command (useful when
|
|
621
|
+
some solutions of trigonometric equations are lost).
|
|
622
|
+
|
|
623
|
+
- ``algorithm`` -- string (default: ``'maxima'``); to use SymPy's
|
|
624
|
+
solvers set this to 'sympy'. Note that SymPy is always used
|
|
625
|
+
for diophantine equations. Another choice, if it is installed,
|
|
626
|
+
is 'giac'.
|
|
627
|
+
|
|
628
|
+
- ``domain`` -- string (default: ``'complex'``); setting this to 'real'
|
|
629
|
+
changes the way SymPy solves single equations; inequalities
|
|
630
|
+
are always solved in the real domain.
|
|
631
|
+
|
|
632
|
+
EXAMPLES::
|
|
633
|
+
|
|
634
|
+
sage: x, y = var('x, y')
|
|
635
|
+
sage: solve([x+y==6, x-y==4], x, y)
|
|
636
|
+
[[x == 5, y == 1]]
|
|
637
|
+
sage: solve([x^2+y^2 == 1, y^2 == x^3 + x + 1], x, y)
|
|
638
|
+
[[x == -1/2*I*sqrt(3) - 1/2, y == -sqrt(-1/2*I*sqrt(3) + 3/2)],
|
|
639
|
+
[x == -1/2*I*sqrt(3) - 1/2, y == sqrt(-1/2*I*sqrt(3) + 3/2)],
|
|
640
|
+
[x == 1/2*I*sqrt(3) - 1/2, y == -sqrt(1/2*I*sqrt(3) + 3/2)],
|
|
641
|
+
[x == 1/2*I*sqrt(3) - 1/2, y == sqrt(1/2*I*sqrt(3) + 3/2)],
|
|
642
|
+
[x == 0, y == -1],
|
|
643
|
+
[x == 0, y == 1]]
|
|
644
|
+
sage: solve([sqrt(x) + sqrt(y) == 5, x + y == 10], x, y)
|
|
645
|
+
[[x == -5/2*I*sqrt(5) + 5, y == 5/2*I*sqrt(5) + 5], [x == 5/2*I*sqrt(5) + 5, y == -5/2*I*sqrt(5) + 5]]
|
|
646
|
+
sage: solutions = solve([x^2+y^2 == 1, y^2 == x^3 + x + 1], x, y, solution_dict=True)
|
|
647
|
+
sage: for solution in solutions: print("{} , {}".format(solution[x].n(digits=3), solution[y].n(digits=3)))
|
|
648
|
+
-0.500 - 0.866*I , -1.27 + 0.341*I
|
|
649
|
+
-0.500 - 0.866*I , 1.27 - 0.341*I
|
|
650
|
+
-0.500 + 0.866*I , -1.27 - 0.341*I
|
|
651
|
+
-0.500 + 0.866*I , 1.27 + 0.341*I
|
|
652
|
+
0.000 , -1.00
|
|
653
|
+
0.000 , 1.00
|
|
654
|
+
|
|
655
|
+
Whenever possible, answers will be symbolic, but with systems of
|
|
656
|
+
equations, at times approximations will be given by Maxima, due to the
|
|
657
|
+
underlying algorithm::
|
|
658
|
+
|
|
659
|
+
sage: sols = solve([x^3==y,y^2==x], [x,y]); sols[-1], sols[0] # abs tol 1e-15
|
|
660
|
+
([x == 0, y == 0],
|
|
661
|
+
[x == (0.3090169943749475 + 0.9510565162951535*I),
|
|
662
|
+
y == (-0.8090169943749475 - 0.5877852522924731*I)])
|
|
663
|
+
sage: sols[0][0].rhs().pyobject().parent()
|
|
664
|
+
Complex Double Field
|
|
665
|
+
|
|
666
|
+
sage: solve([y^6==y],y)
|
|
667
|
+
[y == 1/4*sqrt(5) + 1/4*I*sqrt(2*sqrt(5) + 10) - 1/4,
|
|
668
|
+
y == -1/4*sqrt(5) + 1/4*I*sqrt(-2*sqrt(5) + 10) - 1/4,
|
|
669
|
+
y == -1/4*sqrt(5) - 1/4*I*sqrt(-2*sqrt(5) + 10) - 1/4,
|
|
670
|
+
y == 1/4*sqrt(5) - 1/4*I*sqrt(2*sqrt(5) + 10) - 1/4,
|
|
671
|
+
y == 1,
|
|
672
|
+
y == 0]
|
|
673
|
+
sage: solve( [y^6 == y], y)==solve( y^6 == y, y)
|
|
674
|
+
True
|
|
675
|
+
|
|
676
|
+
Here we demonstrate very basic use of the optional keywords::
|
|
677
|
+
|
|
678
|
+
sage: ((x^2-1)^2).solve(x)
|
|
679
|
+
[x == -1, x == 1]
|
|
680
|
+
sage: ((x^2-1)^2).solve(x,multiplicities=True)
|
|
681
|
+
([x == -1, x == 1], [2, 2])
|
|
682
|
+
sage: solve(sin(x)==x,x)
|
|
683
|
+
[x == sin(x)]
|
|
684
|
+
sage: solve(sin(x)==x,x,explicit_solutions=True)
|
|
685
|
+
[]
|
|
686
|
+
sage: solve(abs(1-abs(1-x)) == 10, x)
|
|
687
|
+
[abs(abs(x - 1) - 1) == 10]
|
|
688
|
+
sage: solve(abs(1-abs(1-x)) == 10, x, to_poly_solve=True)
|
|
689
|
+
[x == -10, x == 12]
|
|
690
|
+
|
|
691
|
+
sage: from sage.symbolic.expression import Expression
|
|
692
|
+
sage: Expression.solve(x^2==1,x)
|
|
693
|
+
[x == -1, x == 1]
|
|
694
|
+
|
|
695
|
+
We must solve with respect to actual variables::
|
|
696
|
+
|
|
697
|
+
sage: z = 5
|
|
698
|
+
sage: solve([8*z + y == 3, -z +7*y == 0],y,z)
|
|
699
|
+
Traceback (most recent call last):
|
|
700
|
+
...
|
|
701
|
+
TypeError: 5 is not a valid variable.
|
|
702
|
+
|
|
703
|
+
If we ask for dictionaries containing the solutions, we get them::
|
|
704
|
+
|
|
705
|
+
sage: solve([x^2-1],x,solution_dict=True)
|
|
706
|
+
[{x: -1}, {x: 1}]
|
|
707
|
+
sage: solve([x^2-4*x+4],x,solution_dict=True)
|
|
708
|
+
[{x: 2}]
|
|
709
|
+
sage: res = solve([x^2 == y, y == 4],x,y,solution_dict=True)
|
|
710
|
+
sage: for soln in res: print("x: %s, y: %s" % (soln[x], soln[y]))
|
|
711
|
+
x: 2, y: 4
|
|
712
|
+
x: -2, y: 4
|
|
713
|
+
|
|
714
|
+
If there is a parameter in the answer, that will show up as
|
|
715
|
+
a new variable. In the following example, ``r1`` is an arbitrary
|
|
716
|
+
constant (because of the ``r``)::
|
|
717
|
+
|
|
718
|
+
sage: forget()
|
|
719
|
+
sage: x, y = var('x,y')
|
|
720
|
+
sage: solve([x+y == 3, 2*x+2*y == 6],x,y)
|
|
721
|
+
[[x == -r1 + 3, y == r1]]
|
|
722
|
+
|
|
723
|
+
sage: var('b, c')
|
|
724
|
+
(b, c)
|
|
725
|
+
sage: solve((b-1)*(c-1), [b,c])
|
|
726
|
+
[[b == 1, c == r...], [b == r..., c == 1]]
|
|
727
|
+
|
|
728
|
+
Especially with trigonometric functions, the dummy variable may
|
|
729
|
+
be implicitly an integer (hence the ``z``)::
|
|
730
|
+
|
|
731
|
+
sage: solve( sin(x)==cos(x), x, to_poly_solve=True)
|
|
732
|
+
[x == 1/4*pi + pi*z...]
|
|
733
|
+
sage: solve([cos(x)*sin(x) == 1/2, x+y == 0],x,y)
|
|
734
|
+
[[x == 1/4*pi + pi*z..., y == -1/4*pi - pi*z...]]
|
|
735
|
+
|
|
736
|
+
Expressions which are not equations are assumed to be set equal
|
|
737
|
+
to zero, as with `x` in the following example::
|
|
738
|
+
|
|
739
|
+
sage: solve([x, y == 2],x,y)
|
|
740
|
+
[[x == 0, y == 2]]
|
|
741
|
+
|
|
742
|
+
If ``True`` appears in the list of equations it is
|
|
743
|
+
ignored, and if ``False`` appears in the list then no
|
|
744
|
+
solutions are returned. E.g., note that the first
|
|
745
|
+
``3==3`` evaluates to ``True``, not to a
|
|
746
|
+
symbolic equation.
|
|
747
|
+
|
|
748
|
+
::
|
|
749
|
+
|
|
750
|
+
sage: solve([3==3, 1.00000000000000*x^3 == 0], x)
|
|
751
|
+
[x == 0]
|
|
752
|
+
sage: solve([1.00000000000000*x^3 == 0], x)
|
|
753
|
+
[x == 0]
|
|
754
|
+
|
|
755
|
+
Here, the first equation evaluates to ``False``, so
|
|
756
|
+
there are no solutions::
|
|
757
|
+
|
|
758
|
+
sage: solve([1==3, 1.00000000000000*x^3 == 0], x)
|
|
759
|
+
[]
|
|
760
|
+
|
|
761
|
+
Completely symbolic solutions are supported::
|
|
762
|
+
|
|
763
|
+
sage: var('s,j,b,m,g')
|
|
764
|
+
(s, j, b, m, g)
|
|
765
|
+
sage: sys = [ m*(1-s) - b*s*j, b*s*j-g*j ]
|
|
766
|
+
sage: solve(sys,s,j)
|
|
767
|
+
[[s == 1, j == 0], [s == g/b, j == (b - g)*m/(b*g)]]
|
|
768
|
+
sage: solve(sys,(s,j))
|
|
769
|
+
[[s == 1, j == 0], [s == g/b, j == (b - g)*m/(b*g)]]
|
|
770
|
+
sage: solve(sys,[s,j])
|
|
771
|
+
[[s == 1, j == 0], [s == g/b, j == (b - g)*m/(b*g)]]
|
|
772
|
+
|
|
773
|
+
sage: z = var('z')
|
|
774
|
+
sage: solve((x-z)^2==2, x)
|
|
775
|
+
[x == z - sqrt(2), x == z + sqrt(2)]
|
|
776
|
+
|
|
777
|
+
Inequalities can be also solved::
|
|
778
|
+
|
|
779
|
+
sage: solve(x^2>8,x)
|
|
780
|
+
[[x < -2*sqrt(2)], [x > 2*sqrt(2)]]
|
|
781
|
+
sage: x,y = var('x,y'); (ln(x)-ln(y)>0).solve(x)
|
|
782
|
+
[[log(x) - log(y) > 0]]
|
|
783
|
+
sage: x,y = var('x,y'); (ln(x)>ln(y)).solve(x) # random
|
|
784
|
+
[[0 < y, y < x, 0 < x]]
|
|
785
|
+
[[y < x, 0 < y]]
|
|
786
|
+
|
|
787
|
+
A simple example to show the use of the keyword
|
|
788
|
+
``multiplicities``::
|
|
789
|
+
|
|
790
|
+
sage: ((x^2-1)^2).solve(x)
|
|
791
|
+
[x == -1, x == 1]
|
|
792
|
+
sage: ((x^2-1)^2).solve(x,multiplicities=True)
|
|
793
|
+
([x == -1, x == 1], [2, 2])
|
|
794
|
+
sage: ((x^2-1)^2).solve(x,multiplicities=True,to_poly_solve=True)
|
|
795
|
+
Traceback (most recent call last):
|
|
796
|
+
...
|
|
797
|
+
NotImplementedError: to_poly_solve does not return multiplicities
|
|
798
|
+
|
|
799
|
+
Here is how the ``explicit_solutions`` keyword functions::
|
|
800
|
+
|
|
801
|
+
sage: solve(sin(x)==x,x)
|
|
802
|
+
[x == sin(x)]
|
|
803
|
+
sage: solve(sin(x)==x,x,explicit_solutions=True)
|
|
804
|
+
[]
|
|
805
|
+
sage: solve(x*sin(x)==x^2,x)
|
|
806
|
+
[x == 0, x == sin(x)]
|
|
807
|
+
sage: solve(x*sin(x)==x^2,x,explicit_solutions=True)
|
|
808
|
+
[x == 0]
|
|
809
|
+
|
|
810
|
+
The following examples show the use of the keyword ``to_poly_solve``::
|
|
811
|
+
|
|
812
|
+
sage: solve(abs(1-abs(1-x)) == 10, x)
|
|
813
|
+
[abs(abs(x - 1) - 1) == 10]
|
|
814
|
+
sage: solve(abs(1-abs(1-x)) == 10, x, to_poly_solve=True)
|
|
815
|
+
[x == -10, x == 12]
|
|
816
|
+
|
|
817
|
+
sage: var('Q')
|
|
818
|
+
Q
|
|
819
|
+
sage: solve(Q*sqrt(Q^2 + 2) - 1, Q)
|
|
820
|
+
[Q == 1/sqrt(Q^2 + 2)]
|
|
821
|
+
|
|
822
|
+
The following example is a regression in Maxima 5.39.0.
|
|
823
|
+
It used to be possible to get one more solution here,
|
|
824
|
+
namely ``1/sqrt(sqrt(2) + 1)``, see
|
|
825
|
+
https://sourceforge.net/p/maxima/bugs/3276/::
|
|
826
|
+
|
|
827
|
+
sage: solve(Q*sqrt(Q^2 + 2) - 1, Q, to_poly_solve=True)
|
|
828
|
+
[Q == -sqrt(-sqrt(2) - 1), Q == sqrt(sqrt(2) + 1)*(sqrt(2) - 1)]
|
|
829
|
+
|
|
830
|
+
An effort is made to only return solutions that satisfy
|
|
831
|
+
the current assumptions::
|
|
832
|
+
|
|
833
|
+
sage: solve(x^2==4, x)
|
|
834
|
+
[x == -2, x == 2]
|
|
835
|
+
sage: assume(x<0)
|
|
836
|
+
sage: solve(x^2==4, x)
|
|
837
|
+
[x == -2]
|
|
838
|
+
sage: solve((x^2-4)^2 == 0, x, multiplicities=True)
|
|
839
|
+
([x == -2], [2])
|
|
840
|
+
sage: solve(x^2==2, x)
|
|
841
|
+
[x == -sqrt(2)]
|
|
842
|
+
sage: z = var('z')
|
|
843
|
+
sage: solve(x^2==2-z, x)
|
|
844
|
+
[x == -sqrt(-z + 2)]
|
|
845
|
+
sage: assume(x, 'rational')
|
|
846
|
+
sage: solve(x^2 == 2, x)
|
|
847
|
+
[]
|
|
848
|
+
|
|
849
|
+
In some cases it may be worthwhile to directly use ``to_poly_solve``
|
|
850
|
+
if one suspects some answers are being missed::
|
|
851
|
+
|
|
852
|
+
sage: forget()
|
|
853
|
+
sage: solve(cos(x)==0, x)
|
|
854
|
+
[x == 1/2*pi]
|
|
855
|
+
sage: solve(cos(x)==0, x, to_poly_solve=True)
|
|
856
|
+
[x == 1/2*pi]
|
|
857
|
+
sage: solve(cos(x)==0, x, to_poly_solve='force')
|
|
858
|
+
[x == 1/2*pi + pi*z...]
|
|
859
|
+
|
|
860
|
+
The same may also apply if a returned unsolved expression has a
|
|
861
|
+
denominator, but the original one did not::
|
|
862
|
+
|
|
863
|
+
sage: solve(cos(x) * sin(x) == 1/2, x, to_poly_solve=True)
|
|
864
|
+
[sin(x) == 1/2/cos(x)]
|
|
865
|
+
sage: solve(cos(x) * sin(x) == 1/2, x, to_poly_solve=True, explicit_solutions=True)
|
|
866
|
+
[x == 1/4*pi + pi*z...]
|
|
867
|
+
sage: solve(cos(x) * sin(x) == 1/2, x, to_poly_solve='force')
|
|
868
|
+
[x == 1/4*pi + pi*z...]
|
|
869
|
+
|
|
870
|
+
We use ``use_grobner`` in Maxima if no solution is obtained from
|
|
871
|
+
Maxima's ``to_poly_solve``::
|
|
872
|
+
|
|
873
|
+
sage: x,y = var('x y')
|
|
874
|
+
sage: c1(x,y) = (x-5)^2+y^2-16
|
|
875
|
+
sage: c2(x,y) = (y-3)^2+x^2-9
|
|
876
|
+
sage: solve([c1(x,y),c2(x,y)],[x,y])
|
|
877
|
+
[[x == -9/68*sqrt(55) + 135/68, y == -15/68*sqrt(55) + 123/68],
|
|
878
|
+
[x == 9/68*sqrt(55) + 135/68, y == 15/68*sqrt(55) + 123/68]]
|
|
879
|
+
|
|
880
|
+
We use SymPy for Diophantine equations, see
|
|
881
|
+
``Expression.solve_diophantine``::
|
|
882
|
+
|
|
883
|
+
sage: assume(x, 'integer')
|
|
884
|
+
sage: assume(z, 'integer')
|
|
885
|
+
sage: solve((x-z)^2==2, x)
|
|
886
|
+
[]
|
|
887
|
+
|
|
888
|
+
sage: forget()
|
|
889
|
+
|
|
890
|
+
The following shows some more of SymPy's capabilities that cannot be
|
|
891
|
+
handled by Maxima::
|
|
892
|
+
|
|
893
|
+
sage: _ = var('t')
|
|
894
|
+
sage: r = solve([x^2 - y^2/exp(x), y-1], x, y, algorithm='sympy')
|
|
895
|
+
sage: (r[0][x], r[0][y])
|
|
896
|
+
(2*lambert_w(-1/2), 1)
|
|
897
|
+
sage: solve(-2*x**3 + 4*x**2 - 2*x + 6 > 0, x, algorithm='sympy')
|
|
898
|
+
[x < 1/3*(1/2)^(1/3)*(9*sqrt(77) + 79)^(1/3) + 2/3*(1/2)^(2/3)/(9*sqrt(77) + 79)^(1/3) + 2/3]
|
|
899
|
+
sage: solve(sqrt(2*x^2 - 7) - (3 - x),x,algorithm='sympy')
|
|
900
|
+
[x == -8, x == 2]
|
|
901
|
+
sage: solve(sqrt(2*x + 9) - sqrt(x + 1) - sqrt(x + 4),x,algorithm='sympy')
|
|
902
|
+
[x == 0]
|
|
903
|
+
sage: r = solve([x + y + z + t, -z - t], x, y, z, t, algorithm='sympy')
|
|
904
|
+
sage: (r[0][x], r[0][z])
|
|
905
|
+
(-y, -t)
|
|
906
|
+
sage: r = solve([x^2+y+z, y+x^2+z, x+y+z^2], x, y,z, algorithm='sympy')
|
|
907
|
+
sage: (r[0][x], r[0][y])
|
|
908
|
+
(z, -(z + 1)*z)
|
|
909
|
+
sage: (r[1][x], r[1][y])
|
|
910
|
+
(-z + 1, -z^2 + z - 1)
|
|
911
|
+
sage: solve(abs(x + 3) - 2*abs(x - 3),x,algorithm='sympy',domain='real')
|
|
912
|
+
[x == 1, x == 9]
|
|
913
|
+
|
|
914
|
+
We cannot translate all results from SymPy but we can at least
|
|
915
|
+
print them::
|
|
916
|
+
|
|
917
|
+
sage: solve(sinh(x) - 2*cosh(x),x,algorithm='sympy')
|
|
918
|
+
[ImageSet(Lambda(_n, I*(2*_n*pi + pi/2) + log(sqrt(3))), Integers),
|
|
919
|
+
ImageSet(Lambda(_n, I*(2*_n*pi - pi/2) + log(sqrt(3))), Integers)]
|
|
920
|
+
sage: solve(2*sin(x) - 2*sin(2*x), x,algorithm='sympy')
|
|
921
|
+
[ImageSet(Lambda(_n, 2*_n*pi), Integers),
|
|
922
|
+
ImageSet(Lambda(_n, 2*_n*pi + pi), Integers),
|
|
923
|
+
ImageSet(Lambda(_n, 2*_n*pi + 5*pi/3), Integers),
|
|
924
|
+
ImageSet(Lambda(_n, 2*_n*pi + pi/3), Integers)]
|
|
925
|
+
|
|
926
|
+
sage: solve(x^5 + 3*x^3 + 7, x, algorithm='sympy')[0] # known bug
|
|
927
|
+
complex_root_of(x^5 + 3*x^3 + 7, 0)
|
|
928
|
+
|
|
929
|
+
A basic interface to Giac is provided::
|
|
930
|
+
|
|
931
|
+
sage: # needs sage.libs.giac
|
|
932
|
+
sage: solve([(2/3)^x-2], [x], algorithm='giac')
|
|
933
|
+
...[[-log(2)/(log(3) - log(2))]]
|
|
934
|
+
|
|
935
|
+
sage: # needs sage.libs.giac
|
|
936
|
+
sage: f = (sin(x) - 8*cos(x)*sin(x))*(sin(x)^2 + cos(x)) - (2*cos(x)*sin(x) - sin(x))*(-2*sin(x)^2 + 2*cos(x)^2 - cos(x))
|
|
937
|
+
sage: solve(f, x, algorithm='giac')
|
|
938
|
+
...[-2*arctan(sqrt(2)), 0, 2*arctan(sqrt(2)), pi]
|
|
939
|
+
|
|
940
|
+
sage: # needs sage.libs.giac
|
|
941
|
+
sage: x, y = SR.var('x,y')
|
|
942
|
+
sage: solve([x+y-4,x*y-3],[x,y],algorithm='giac')
|
|
943
|
+
[[1, 3], [3, 1]]
|
|
944
|
+
|
|
945
|
+
TESTS::
|
|
946
|
+
|
|
947
|
+
sage: solve([sin(x)==x,y^2==x],x,y)
|
|
948
|
+
[sin(x) == x, y^2 == x]
|
|
949
|
+
sage: solve(0==1,x)
|
|
950
|
+
Traceback (most recent call last):
|
|
951
|
+
...
|
|
952
|
+
TypeError: The first argument must be a symbolic expression or a list of symbolic expressions.
|
|
953
|
+
|
|
954
|
+
Test if the empty list is returned, too, when (a list of)
|
|
955
|
+
dictionaries (is) are requested (:issue:`8553`)::
|
|
956
|
+
|
|
957
|
+
sage: solve([SR(0)==1],x)
|
|
958
|
+
[]
|
|
959
|
+
sage: solve([SR(0)==1],x,solution_dict=True)
|
|
960
|
+
[]
|
|
961
|
+
sage: solve([x==1,x==-1],x)
|
|
962
|
+
[]
|
|
963
|
+
sage: solve([x==1,x==-1],x,solution_dict=True)
|
|
964
|
+
[]
|
|
965
|
+
sage: solve((x==1,x==-1),x,solution_dict=0)
|
|
966
|
+
[]
|
|
967
|
+
|
|
968
|
+
Relaxed form, suggested by Mike Hansen (:issue:`8553`)::
|
|
969
|
+
|
|
970
|
+
sage: solve([x^2-1],x,solution_dict=-1)
|
|
971
|
+
[{x: -1}, {x: 1}]
|
|
972
|
+
sage: solve([x^2-1],x,solution_dict=1)
|
|
973
|
+
[{x: -1}, {x: 1}]
|
|
974
|
+
sage: solve((x==1,x==-1),x,solution_dict=-1)
|
|
975
|
+
[]
|
|
976
|
+
sage: solve((x==1,x==-1),x,solution_dict=1)
|
|
977
|
+
[]
|
|
978
|
+
|
|
979
|
+
This inequality holds for any real ``x`` (:issue:`8078`)::
|
|
980
|
+
|
|
981
|
+
sage: solve(x^4+2>0,x)
|
|
982
|
+
[x < +Infinity]
|
|
983
|
+
|
|
984
|
+
Test for user friendly input handling :issue:`13645`::
|
|
985
|
+
|
|
986
|
+
sage: poly.<a,b> = PolynomialRing(RR)
|
|
987
|
+
sage: solve([a+b+a*b == 1], a)
|
|
988
|
+
Traceback (most recent call last):
|
|
989
|
+
...
|
|
990
|
+
TypeError: a is not a valid variable.
|
|
991
|
+
sage: a,b = var('a,b')
|
|
992
|
+
sage: solve([a+b+a*b == 1], a)
|
|
993
|
+
[a == -(b - 1)/(b + 1)]
|
|
994
|
+
sage: solve([a, b], (1, a))
|
|
995
|
+
Traceback (most recent call last):
|
|
996
|
+
...
|
|
997
|
+
TypeError: 1 is not a valid variable.
|
|
998
|
+
sage: solve([x == 1], (1, a))
|
|
999
|
+
Traceback (most recent call last):
|
|
1000
|
+
...
|
|
1001
|
+
TypeError: 1 is not a valid variable.
|
|
1002
|
+
sage: x.solve((1,2))
|
|
1003
|
+
Traceback (most recent call last):
|
|
1004
|
+
...
|
|
1005
|
+
TypeError: 1 is not a valid variable.
|
|
1006
|
+
|
|
1007
|
+
Test that the original version of a system in the French Sage book
|
|
1008
|
+
now works (:issue:`14306`)::
|
|
1009
|
+
|
|
1010
|
+
sage: var('y,z')
|
|
1011
|
+
(y, z)
|
|
1012
|
+
sage: solve([x^2 * y * z == 18, x * y^3 * z == 24, x * y * z^4 == 6], x, y, z)
|
|
1013
|
+
[[x == 3, y == 2, z == 1],
|
|
1014
|
+
[x == (1.337215067... - 2.685489874...*I),
|
|
1015
|
+
y == (-1.700434271... + 1.052864325...*I),
|
|
1016
|
+
z == (0.9324722294... - 0.3612416661...*I)],
|
|
1017
|
+
...]
|
|
1018
|
+
|
|
1019
|
+
:issue:`13286` fixed::
|
|
1020
|
+
|
|
1021
|
+
sage: solve([x-4], [x])
|
|
1022
|
+
[x == 4]
|
|
1023
|
+
|
|
1024
|
+
Test for a list of non-symbolic expressions as first argument
|
|
1025
|
+
(:issue:`31714`)::
|
|
1026
|
+
|
|
1027
|
+
sage: solve([1], x)
|
|
1028
|
+
Traceback (most recent call last):
|
|
1029
|
+
...
|
|
1030
|
+
TypeError: The first argument to solve() should be a symbolic expression
|
|
1031
|
+
or a list of symbolic expressions.
|
|
1032
|
+
"""
|
|
1033
|
+
from sage.structure.element import Expression
|
|
1034
|
+
explicit_solutions = kwds.get('explicit_solutions', None)
|
|
1035
|
+
multiplicities = kwds.get('multiplicities', None)
|
|
1036
|
+
to_poly_solve = kwds.get('to_poly_solve', None)
|
|
1037
|
+
solution_dict = kwds.get('solution_dict', False)
|
|
1038
|
+
algorithm = kwds.get('algorithm', None)
|
|
1039
|
+
domain = kwds.get('domain', None)
|
|
1040
|
+
|
|
1041
|
+
if len(args) > 1:
|
|
1042
|
+
x = args
|
|
1043
|
+
else:
|
|
1044
|
+
x = args[0]
|
|
1045
|
+
if isinstance(x, (list, tuple)):
|
|
1046
|
+
for i in x:
|
|
1047
|
+
if not isinstance(i, Expression):
|
|
1048
|
+
raise TypeError("%s is not a valid variable." % repr(i))
|
|
1049
|
+
elif x is None:
|
|
1050
|
+
vars = f.variables()
|
|
1051
|
+
if len(vars) == 0:
|
|
1052
|
+
if multiplicities:
|
|
1053
|
+
return [], []
|
|
1054
|
+
else:
|
|
1055
|
+
return []
|
|
1056
|
+
x = vars[0]
|
|
1057
|
+
elif not isinstance(x, Expression):
|
|
1058
|
+
raise TypeError("%s is not a valid variable." % repr(x))
|
|
1059
|
+
|
|
1060
|
+
if isinstance(f, (list, tuple)) and len(f) == 1:
|
|
1061
|
+
# f is a list with a single element
|
|
1062
|
+
if isinstance(f[0], Expression):
|
|
1063
|
+
f = f[0]
|
|
1064
|
+
else:
|
|
1065
|
+
raise TypeError("The first argument to solve() should be a "
|
|
1066
|
+
"symbolic expression or a list of symbolic "
|
|
1067
|
+
"expressions.")
|
|
1068
|
+
|
|
1069
|
+
if isinstance(f, Expression): # f is a single expression
|
|
1070
|
+
return _solve_expression(f, x, explicit_solutions, multiplicities, to_poly_solve, solution_dict, algorithm, domain)
|
|
1071
|
+
|
|
1072
|
+
if not isinstance(f, (list, tuple)):
|
|
1073
|
+
raise TypeError("The first argument must be a symbolic expression or a list of symbolic expressions.")
|
|
1074
|
+
|
|
1075
|
+
# f is a list of such expressions or equations
|
|
1076
|
+
|
|
1077
|
+
if not args:
|
|
1078
|
+
raise TypeError("Please input variables to solve for.")
|
|
1079
|
+
if isinstance(x, Expression) and x.is_symbol():
|
|
1080
|
+
variables = args
|
|
1081
|
+
else:
|
|
1082
|
+
variables = tuple(x)
|
|
1083
|
+
|
|
1084
|
+
for v in variables:
|
|
1085
|
+
if not (isinstance(v, Expression) and v.is_symbol()):
|
|
1086
|
+
raise TypeError("%s is not a valid variable." % repr(v))
|
|
1087
|
+
|
|
1088
|
+
try:
|
|
1089
|
+
f = [s for s in f if s is not True]
|
|
1090
|
+
except TypeError:
|
|
1091
|
+
raise ValueError("Unable to solve %s for %s" % (f, args))
|
|
1092
|
+
|
|
1093
|
+
if any(s is False for s in f):
|
|
1094
|
+
return []
|
|
1095
|
+
|
|
1096
|
+
if algorithm == 'sympy':
|
|
1097
|
+
from sympy import solve as ssolve
|
|
1098
|
+
from sage.interfaces.sympy import sympy_set_to_list
|
|
1099
|
+
if isinstance(f, Expression): # f is a single expression
|
|
1100
|
+
sympy_f = f._sympy_()
|
|
1101
|
+
else:
|
|
1102
|
+
sympy_f = [s._sympy_() for s in f]
|
|
1103
|
+
if isinstance(f, Expression) and f.is_symbol():
|
|
1104
|
+
sympy_vars = (x._sympy_(),)
|
|
1105
|
+
else:
|
|
1106
|
+
sympy_vars = tuple([v._sympy_() for v in x])
|
|
1107
|
+
if len(sympy_vars) > 1 or not isinstance(f, Expression):
|
|
1108
|
+
ret = ssolve(sympy_f, sympy_vars, dict=True)
|
|
1109
|
+
if isinstance(ret, dict):
|
|
1110
|
+
if solution_dict:
|
|
1111
|
+
l = []
|
|
1112
|
+
for d in ret:
|
|
1113
|
+
r = {}
|
|
1114
|
+
for (v, ex) in d.items():
|
|
1115
|
+
r[v._sage_()] = ex._sage_()
|
|
1116
|
+
l.append(r)
|
|
1117
|
+
return l
|
|
1118
|
+
else:
|
|
1119
|
+
return [[v._sage_() == ex._sage_()
|
|
1120
|
+
for v, ex in d.items()]
|
|
1121
|
+
for d in ret]
|
|
1122
|
+
elif isinstance(ret, list):
|
|
1123
|
+
l = []
|
|
1124
|
+
for sol in ret:
|
|
1125
|
+
r = {}
|
|
1126
|
+
for (v, ex) in sol.items():
|
|
1127
|
+
r[v._sage_()] = ex._sage_()
|
|
1128
|
+
l.append(r)
|
|
1129
|
+
return l
|
|
1130
|
+
else:
|
|
1131
|
+
return sympy_set_to_list(ret, sympy_vars)
|
|
1132
|
+
|
|
1133
|
+
if algorithm == 'giac':
|
|
1134
|
+
return _giac_solver(f, x, solution_dict)
|
|
1135
|
+
|
|
1136
|
+
from sage.calculus.calculus import maxima
|
|
1137
|
+
m = maxima(f)
|
|
1138
|
+
|
|
1139
|
+
try:
|
|
1140
|
+
s = m.solve(variables)
|
|
1141
|
+
except Exception: # if Maxima gave an error, try its to_poly_solve
|
|
1142
|
+
try:
|
|
1143
|
+
s = m.to_poly_solve(variables)
|
|
1144
|
+
except TypeError as mess: # if that gives an error, raise an error.
|
|
1145
|
+
if "Error executing code in Maxima" in str(mess):
|
|
1146
|
+
raise ValueError("Sage is unable to determine whether the system %s can be solved for %s" % (f, args))
|
|
1147
|
+
else:
|
|
1148
|
+
raise
|
|
1149
|
+
|
|
1150
|
+
if len(s) == 0: # if Maxima's solve gave no solutions, try its to_poly_solve
|
|
1151
|
+
try:
|
|
1152
|
+
s = m.to_poly_solve(variables)
|
|
1153
|
+
except Exception: # if that gives an error, stick with no solutions
|
|
1154
|
+
s = []
|
|
1155
|
+
|
|
1156
|
+
if len(s) == 0: # if to_poly_solve gave no solutions, try use_grobner
|
|
1157
|
+
try:
|
|
1158
|
+
s = m.to_poly_solve(variables, 'use_grobner=true')
|
|
1159
|
+
except Exception: # if that gives an error, stick with no solutions
|
|
1160
|
+
s = []
|
|
1161
|
+
|
|
1162
|
+
sol_list = string_to_list_of_solutions(repr(s))
|
|
1163
|
+
|
|
1164
|
+
# Relaxed form suggested by Mike Hansen (#8553):
|
|
1165
|
+
if kwds.get('solution_dict', None):
|
|
1166
|
+
if not sol_list: # fixes IndexError on empty solution list (#8553)
|
|
1167
|
+
return []
|
|
1168
|
+
if isinstance(sol_list[0], list):
|
|
1169
|
+
sol_dict = [{eq.left(): eq.right() for eq in solution}
|
|
1170
|
+
for solution in sol_list]
|
|
1171
|
+
else:
|
|
1172
|
+
sol_dict = [{eq.left(): eq.right()} for eq in sol_list]
|
|
1173
|
+
|
|
1174
|
+
return sol_dict
|
|
1175
|
+
else:
|
|
1176
|
+
return sol_list
|
|
1177
|
+
|
|
1178
|
+
|
|
1179
|
+
def _solve_expression(f, x, explicit_solutions, multiplicities,
|
|
1180
|
+
to_poly_solve, solution_dict, algorithm, domain):
|
|
1181
|
+
"""
|
|
1182
|
+
Solve an expression ``f``. For more information, see :func:`solve`.
|
|
1183
|
+
|
|
1184
|
+
.. NOTE::
|
|
1185
|
+
|
|
1186
|
+
This is an auxiliary function only meant to be called
|
|
1187
|
+
from :func:`solve`.
|
|
1188
|
+
|
|
1189
|
+
TESTS:
|
|
1190
|
+
|
|
1191
|
+
:issue:`7325` (solving inequalities)::
|
|
1192
|
+
|
|
1193
|
+
sage: (x^2>1).solve(x)
|
|
1194
|
+
[[x < -1], [x > 1]]
|
|
1195
|
+
|
|
1196
|
+
Catch error message from Maxima::
|
|
1197
|
+
|
|
1198
|
+
sage: solve(acot(x),x)
|
|
1199
|
+
Traceback (most recent call last):
|
|
1200
|
+
...
|
|
1201
|
+
TypeError: ECL says: cot: argument 0 isn't in the domain of cot.
|
|
1202
|
+
|
|
1203
|
+
::
|
|
1204
|
+
|
|
1205
|
+
sage: solve(acot(x),x,to_poly_solve=True)
|
|
1206
|
+
Traceback (most recent call last):
|
|
1207
|
+
...
|
|
1208
|
+
TypeError: ECL says: cot: argument 0 isn't in the domain of cot.
|
|
1209
|
+
|
|
1210
|
+
:issue:`7491` fixed::
|
|
1211
|
+
|
|
1212
|
+
sage: y = var('y')
|
|
1213
|
+
sage: solve(y==y,y)
|
|
1214
|
+
[y == r1]
|
|
1215
|
+
sage: solve(y==y,y,multiplicities=True)
|
|
1216
|
+
([y == r1], [])
|
|
1217
|
+
|
|
1218
|
+
sage: from sage.symbolic.assumptions import GenericDeclaration
|
|
1219
|
+
sage: GenericDeclaration(x, 'rational').assume()
|
|
1220
|
+
sage: solve(x^2 == 2, x)
|
|
1221
|
+
[]
|
|
1222
|
+
sage: forget()
|
|
1223
|
+
|
|
1224
|
+
:issue:`8390` fixed::
|
|
1225
|
+
|
|
1226
|
+
sage: solve(sin(x)==1/2,x)
|
|
1227
|
+
[x == 1/6*pi]
|
|
1228
|
+
|
|
1229
|
+
::
|
|
1230
|
+
|
|
1231
|
+
sage: solve(sin(x)==1/2,x,to_poly_solve=True)
|
|
1232
|
+
[x == 1/6*pi]
|
|
1233
|
+
|
|
1234
|
+
::
|
|
1235
|
+
|
|
1236
|
+
sage: solve(sin(x)==1/2, x, to_poly_solve='force')
|
|
1237
|
+
[x == 5/6*pi + 2*pi*z..., x == 1/6*pi + 2*pi*z...]
|
|
1238
|
+
|
|
1239
|
+
:issue:`11618` fixed::
|
|
1240
|
+
|
|
1241
|
+
sage: g(x)=0
|
|
1242
|
+
sage: solve(g(x)==0,x,solution_dict=True)
|
|
1243
|
+
[{x: r1}]
|
|
1244
|
+
|
|
1245
|
+
:issue:`17128`: fixed::
|
|
1246
|
+
|
|
1247
|
+
sage: var('x,y')
|
|
1248
|
+
(x, y)
|
|
1249
|
+
sage: f = x+y
|
|
1250
|
+
sage: sol = f.solve([x, y], solution_dict=True)
|
|
1251
|
+
sage: sol[0].get(x) + sol[0].get(y)
|
|
1252
|
+
0
|
|
1253
|
+
|
|
1254
|
+
:issue:`16651` fixed::
|
|
1255
|
+
|
|
1256
|
+
sage: (x^7-x-1).solve(x, to_poly_solve=True) # abs tol 1e-6
|
|
1257
|
+
[x == 1.11277569705,
|
|
1258
|
+
x == (-0.363623519329 - 0.952561195261*I),
|
|
1259
|
+
x == (0.617093477784 - 0.900864951949*I),
|
|
1260
|
+
x == (-0.809857800594 - 0.262869645851*I),
|
|
1261
|
+
x == (-0.809857800594 + 0.262869645851*I),
|
|
1262
|
+
x == (0.617093477784 + 0.900864951949*I),
|
|
1263
|
+
x == (-0.363623519329 + 0.952561195261*I)]
|
|
1264
|
+
|
|
1265
|
+
:issue:`31452` fixed::
|
|
1266
|
+
|
|
1267
|
+
sage: solve([x==3], [x], solution_dict=True)
|
|
1268
|
+
[{x: 3}]
|
|
1269
|
+
sage: solve([x==3], [x], solution_dict=True, algorithm='sympy')
|
|
1270
|
+
[{x: 3}]
|
|
1271
|
+
"""
|
|
1272
|
+
from sage.structure.element import Expression
|
|
1273
|
+
|
|
1274
|
+
if f.is_relational():
|
|
1275
|
+
if f.operator() is not operator.eq:
|
|
1276
|
+
if algorithm == 'sympy':
|
|
1277
|
+
from sympy import S, solveset
|
|
1278
|
+
from sage.interfaces.sympy import sympy_set_to_list
|
|
1279
|
+
if isinstance(x, Expression) and x.is_symbol():
|
|
1280
|
+
sympy_vars = (x._sympy_(),)
|
|
1281
|
+
else:
|
|
1282
|
+
sympy_vars = tuple([v._sympy_() for v in x])
|
|
1283
|
+
ret = solveset(f._sympy_(), sympy_vars[0], S.Reals)
|
|
1284
|
+
return sympy_set_to_list(ret, sympy_vars)
|
|
1285
|
+
elif algorithm == 'giac':
|
|
1286
|
+
return _giac_solver(f, x, solution_dict)
|
|
1287
|
+
else:
|
|
1288
|
+
try:
|
|
1289
|
+
return solve_ineq(f) # trying solve_ineq_univar
|
|
1290
|
+
except Exception:
|
|
1291
|
+
pass
|
|
1292
|
+
try:
|
|
1293
|
+
return solve_ineq([f]) # trying solve_ineq_fourier
|
|
1294
|
+
except Exception:
|
|
1295
|
+
raise NotImplementedError("solving only implemented for equalities and few special inequalities, see solve_ineq")
|
|
1296
|
+
ex = f
|
|
1297
|
+
else:
|
|
1298
|
+
ex = (f == 0)
|
|
1299
|
+
|
|
1300
|
+
if multiplicities and to_poly_solve:
|
|
1301
|
+
raise NotImplementedError("to_poly_solve does not return multiplicities")
|
|
1302
|
+
# check if all variables are assumed integer;
|
|
1303
|
+
# if so, we have a Diophantine
|
|
1304
|
+
|
|
1305
|
+
def has_integer_assumption(v) -> bool:
|
|
1306
|
+
from sage.symbolic.assumptions import assumptions, GenericDeclaration
|
|
1307
|
+
alist = assumptions()
|
|
1308
|
+
return any(isinstance(a, GenericDeclaration) and a.has(v) and
|
|
1309
|
+
a._assumption in ['even', 'odd', 'integer', 'integervalued']
|
|
1310
|
+
for a in alist)
|
|
1311
|
+
if len(ex.variables()) and all(has_integer_assumption(var) for var in ex.variables()):
|
|
1312
|
+
return f.solve_diophantine(x, solution_dict=solution_dict)
|
|
1313
|
+
|
|
1314
|
+
if algorithm == 'sympy':
|
|
1315
|
+
from sympy import S, solveset
|
|
1316
|
+
from sage.interfaces.sympy import sympy_set_to_list
|
|
1317
|
+
if isinstance(x, Expression) and x.is_symbol():
|
|
1318
|
+
sympy_vars = (x._sympy_(),)
|
|
1319
|
+
else:
|
|
1320
|
+
sympy_vars = tuple([v._sympy_() for v in x])
|
|
1321
|
+
if domain == 'real':
|
|
1322
|
+
ret = solveset(ex._sympy_(), sympy_vars[0], S.Reals)
|
|
1323
|
+
else:
|
|
1324
|
+
ret = solveset(ex._sympy_(), sympy_vars[0])
|
|
1325
|
+
ret = sympy_set_to_list(ret, sympy_vars)
|
|
1326
|
+
if solution_dict:
|
|
1327
|
+
ret = [{sol.left(): sol.right()} for sol in ret]
|
|
1328
|
+
return ret
|
|
1329
|
+
|
|
1330
|
+
if algorithm == 'giac':
|
|
1331
|
+
return _giac_solver(f, x, solution_dict)
|
|
1332
|
+
|
|
1333
|
+
# from here on, maxima is used for solution
|
|
1334
|
+
m = ex._maxima_()
|
|
1335
|
+
P = m.parent()
|
|
1336
|
+
if explicit_solutions:
|
|
1337
|
+
P.eval('solveexplicit: true') # switches Maxima to looking for only explicit solutions
|
|
1338
|
+
try:
|
|
1339
|
+
if to_poly_solve != 'force':
|
|
1340
|
+
s = m.solve(x).str()
|
|
1341
|
+
else: # omit Maxima's solve command
|
|
1342
|
+
s = str([])
|
|
1343
|
+
except TypeError as mess: # if Maxima's solve has an error, we catch it
|
|
1344
|
+
if "Error executing code in Maxima" in str(mess):
|
|
1345
|
+
s = str([])
|
|
1346
|
+
else:
|
|
1347
|
+
raise
|
|
1348
|
+
if explicit_solutions:
|
|
1349
|
+
P.eval('solveexplicit: false') # switches Maxima back to default
|
|
1350
|
+
|
|
1351
|
+
if s == 'all':
|
|
1352
|
+
if solution_dict:
|
|
1353
|
+
ans = [{x: f.parent().var('r1')}]
|
|
1354
|
+
else:
|
|
1355
|
+
ans = [x == f.parent().var('r1')]
|
|
1356
|
+
if multiplicities:
|
|
1357
|
+
return ans, []
|
|
1358
|
+
else:
|
|
1359
|
+
return ans
|
|
1360
|
+
|
|
1361
|
+
X = string_to_list_of_solutions(s) # our initial list of solutions
|
|
1362
|
+
|
|
1363
|
+
if multiplicities: # to_poly_solve does not return multiplicities, so in this case we end here
|
|
1364
|
+
if len(X) == 0:
|
|
1365
|
+
return X, []
|
|
1366
|
+
else:
|
|
1367
|
+
ret_multiplicities = [int(e) for e in str(P.get('multiplicities'))[1:-1].split(',')]
|
|
1368
|
+
|
|
1369
|
+
########################################################
|
|
1370
|
+
# Maxima's to_poly_solver package converts difficult #
|
|
1371
|
+
# equations to (quasi)-polynomial systems and uses #
|
|
1372
|
+
# Maxima's algsys function to try to solve them. #
|
|
1373
|
+
# This allows a much larger range of solved equations, #
|
|
1374
|
+
# but also allows for the possibility of approximate #
|
|
1375
|
+
# solutions being returned. #
|
|
1376
|
+
########################################################
|
|
1377
|
+
if to_poly_solve:
|
|
1378
|
+
if len(X) == 0:
|
|
1379
|
+
# Maxima's solve gave no solutions
|
|
1380
|
+
solutions_so_far = [ex]
|
|
1381
|
+
ignore_exceptions = True
|
|
1382
|
+
else:
|
|
1383
|
+
solutions_so_far = X
|
|
1384
|
+
ignore_exceptions = False
|
|
1385
|
+
X = []
|
|
1386
|
+
for eq in solutions_so_far:
|
|
1387
|
+
if eq.lhs().is_symbol() and (eq.lhs() == x) and (x not in eq.rhs().variables()):
|
|
1388
|
+
X.append(eq)
|
|
1389
|
+
continue
|
|
1390
|
+
try:
|
|
1391
|
+
m = eq._maxima_()
|
|
1392
|
+
s = m.to_poly_solve(x, options='algexact:true')
|
|
1393
|
+
T = string_to_list_of_solutions(repr(s))
|
|
1394
|
+
X.extend([t[0] for t in T])
|
|
1395
|
+
except TypeError as mess:
|
|
1396
|
+
if ignore_exceptions:
|
|
1397
|
+
continue
|
|
1398
|
+
elif "Error executing code in Maxima" in str(mess) or \
|
|
1399
|
+
"unable to make sense of Maxima expression" in \
|
|
1400
|
+
str(mess):
|
|
1401
|
+
if not explicit_solutions:
|
|
1402
|
+
X.append(eq) # we keep this implicit solution
|
|
1403
|
+
else:
|
|
1404
|
+
raise
|
|
1405
|
+
|
|
1406
|
+
# make sure all the assumptions are satisfied
|
|
1407
|
+
from sage.symbolic.assumptions import assumptions
|
|
1408
|
+
to_check = assumptions()
|
|
1409
|
+
if to_check:
|
|
1410
|
+
for ix, soln in reversed(list(enumerate(X))):
|
|
1411
|
+
if soln.lhs().is_symbol():
|
|
1412
|
+
if any(a.contradicts(soln) for a in to_check):
|
|
1413
|
+
del X[ix]
|
|
1414
|
+
if multiplicities:
|
|
1415
|
+
del ret_multiplicities[ix]
|
|
1416
|
+
continue
|
|
1417
|
+
|
|
1418
|
+
if solution_dict:
|
|
1419
|
+
if isinstance(x, (list, tuple)) and len(x) > 1:
|
|
1420
|
+
X = [{sol.left(): sol.right() for sol in b} for b in X]
|
|
1421
|
+
else:
|
|
1422
|
+
X = [{sol.left(): sol.right()} for sol in X]
|
|
1423
|
+
|
|
1424
|
+
if multiplicities:
|
|
1425
|
+
return X, ret_multiplicities
|
|
1426
|
+
else:
|
|
1427
|
+
return X
|
|
1428
|
+
|
|
1429
|
+
|
|
1430
|
+
def _giac_solver(f, x, solution_dict=False):
|
|
1431
|
+
"""
|
|
1432
|
+
Solve a system of equations using libgiac.
|
|
1433
|
+
|
|
1434
|
+
INPUT:
|
|
1435
|
+
|
|
1436
|
+
- ``f`` -- equation or list of equations
|
|
1437
|
+
- ``x`` -- variable or list of variables
|
|
1438
|
+
- ``solution_dict`` -- boolean (default: ``False``)
|
|
1439
|
+
|
|
1440
|
+
EXAMPLES::
|
|
1441
|
+
|
|
1442
|
+
sage: # needs sage.libs.giac
|
|
1443
|
+
sage: solve([(2/3)^x-2], [x], algorithm='giac')
|
|
1444
|
+
...[[-log(2)/(log(3) - log(2))]]
|
|
1445
|
+
sage: solve([(2/3)^x-2], [x], algorithm='giac', solution_dict=True)
|
|
1446
|
+
...[{x: -log(2)/(log(3) - log(2))}]
|
|
1447
|
+
|
|
1448
|
+
sage: # needs sage.libs.giac
|
|
1449
|
+
sage: f = (sin(x) - 8*cos(x)*sin(x))*(sin(x)^2 + cos(x)) - (2*cos(x)*sin(x) - sin(x))*(-2*sin(x)^2 + 2*cos(x)^2 - cos(x))
|
|
1450
|
+
sage: solve(f, x, algorithm='giac')
|
|
1451
|
+
...[-2*arctan(sqrt(2)), 0, 2*arctan(sqrt(2)), pi]
|
|
1452
|
+
sage: solve(f, x, algorithm='giac', solution_dict=True)
|
|
1453
|
+
...[{x: -2*arctan(sqrt(2))}, {x: 0}, {x: 2*arctan(sqrt(2))}, {x: pi}]
|
|
1454
|
+
|
|
1455
|
+
sage: # needs sage.libs.giac
|
|
1456
|
+
sage: x, y = SR.var('x,y')
|
|
1457
|
+
sage: solve([x+y-7,x*y-10],[x,y],algorithm='giac')
|
|
1458
|
+
[[2, 5], [5, 2]]
|
|
1459
|
+
"""
|
|
1460
|
+
from sage.libs.giac.giac import libgiac
|
|
1461
|
+
giac_f = libgiac(f)
|
|
1462
|
+
giac_vars = libgiac(x)
|
|
1463
|
+
ret = giac_f.solve(giac_vars)
|
|
1464
|
+
sols = ret.sage()
|
|
1465
|
+
if solution_dict:
|
|
1466
|
+
if not sols:
|
|
1467
|
+
return []
|
|
1468
|
+
if isinstance(sols[0], list):
|
|
1469
|
+
return [dict(zip(x, solution)) for solution in sols]
|
|
1470
|
+
return [{x: sx} for sx in sols]
|
|
1471
|
+
return sols
|
|
1472
|
+
|
|
1473
|
+
|
|
1474
|
+
def solve_mod(eqns, modulus, solution_dict=False):
|
|
1475
|
+
r"""
|
|
1476
|
+
Return all solutions to an equation or list of equations modulo the
|
|
1477
|
+
given integer modulus. Each equation must involve only polynomials
|
|
1478
|
+
in 1 or many variables.
|
|
1479
|
+
|
|
1480
|
+
By default the solutions are returned as `n`-tuples, where `n`
|
|
1481
|
+
is the number of variables appearing anywhere in the given
|
|
1482
|
+
equations. The variables are in alphabetical order.
|
|
1483
|
+
|
|
1484
|
+
INPUT:
|
|
1485
|
+
|
|
1486
|
+
- ``eqns`` -- equation or list of equations
|
|
1487
|
+
|
|
1488
|
+
- ``modulus`` -- integer
|
|
1489
|
+
|
|
1490
|
+
- ``solution_dict`` -- boolean (default: ``False``); if ``True`` or nonzero,
|
|
1491
|
+
return a list of dictionaries containing the solutions. If there
|
|
1492
|
+
are no solutions, return an empty list (rather than a list containing
|
|
1493
|
+
an empty dictionary). Likewise, if there's only a single solution,
|
|
1494
|
+
return a list containing one dictionary with that solution.
|
|
1495
|
+
|
|
1496
|
+
EXAMPLES::
|
|
1497
|
+
|
|
1498
|
+
sage: var('x,y')
|
|
1499
|
+
(x, y)
|
|
1500
|
+
sage: solve_mod([x^2 + 2 == x, x^2 + y == y^2], 14)
|
|
1501
|
+
[(4, 2), (4, 6), (4, 9), (4, 13)]
|
|
1502
|
+
sage: solve_mod([x^2 == 1, 4*x == 11], 15)
|
|
1503
|
+
[(14,)]
|
|
1504
|
+
|
|
1505
|
+
Fermat's equation modulo 3 with exponent 5::
|
|
1506
|
+
|
|
1507
|
+
sage: var('x,y,z')
|
|
1508
|
+
(x, y, z)
|
|
1509
|
+
sage: solve_mod([x^5 + y^5 == z^5], 3)
|
|
1510
|
+
[(0, 0, 0), (0, 1, 1), (0, 2, 2), (1, 0, 1), (1, 1, 2), (1, 2, 0), (2, 0, 2), (2, 1, 0), (2, 2, 1)]
|
|
1511
|
+
|
|
1512
|
+
We can solve with respect to a bigger modulus if it consists only of small prime factors::
|
|
1513
|
+
|
|
1514
|
+
sage: # needs sage.libs.pari
|
|
1515
|
+
sage: [d] = solve_mod([5*x + y == 3, 2*x - 3*y == 9], 3*5*7*11*19*23*29, solution_dict=True)
|
|
1516
|
+
sage: d[x]
|
|
1517
|
+
12915279
|
|
1518
|
+
sage: d[y]
|
|
1519
|
+
8610183
|
|
1520
|
+
|
|
1521
|
+
For cases where there are relatively few solutions and the prime
|
|
1522
|
+
factors are small, this can be efficient even if the modulus itself
|
|
1523
|
+
is large::
|
|
1524
|
+
|
|
1525
|
+
sage: sorted(solve_mod([x^2 == 41], 10^20)) # needs sage.libs.pari
|
|
1526
|
+
[(4538602480526452429,), (11445932736758703821,), (38554067263241296179,),
|
|
1527
|
+
(45461397519473547571,), (54538602480526452429,), (61445932736758703821,),
|
|
1528
|
+
(88554067263241296179,), (95461397519473547571,)]
|
|
1529
|
+
|
|
1530
|
+
We solve a simple equation modulo 2::
|
|
1531
|
+
|
|
1532
|
+
sage: x,y = var('x,y')
|
|
1533
|
+
sage: solve_mod([x == y], 2) # needs sage.libs.pari
|
|
1534
|
+
[(0, 0), (1, 1)]
|
|
1535
|
+
|
|
1536
|
+
.. warning::
|
|
1537
|
+
|
|
1538
|
+
The current implementation splits the modulus into prime
|
|
1539
|
+
powers, then naively enumerates all possible solutions
|
|
1540
|
+
(starting modulo primes and then working up through prime
|
|
1541
|
+
powers), and finally combines the solution using the Chinese
|
|
1542
|
+
Remainder Theorem. The interface is good, but the algorithm is
|
|
1543
|
+
very inefficient if the modulus has some larger prime factors! Sage
|
|
1544
|
+
*does* have the ability to do something much faster in certain
|
|
1545
|
+
cases at least by using Groebner basis, linear algebra
|
|
1546
|
+
techniques, etc. But for a lot of toy problems this function as
|
|
1547
|
+
is might be useful. At least it establishes an interface.
|
|
1548
|
+
|
|
1549
|
+
TESTS:
|
|
1550
|
+
|
|
1551
|
+
Make sure that we short-circuit in at least some cases::
|
|
1552
|
+
|
|
1553
|
+
sage: solve_mod([2*x==1], 2*next_prime(10^50)) # needs sage.libs.pari
|
|
1554
|
+
[]
|
|
1555
|
+
|
|
1556
|
+
Try multi-equation cases::
|
|
1557
|
+
|
|
1558
|
+
sage: x, y, z = var("x y z")
|
|
1559
|
+
sage: solve_mod([2*x^2 + x*y, -x*y+2*y^2+x-2*y, -2*x^2+2*x*y-y^2-x-y], 12) # needs sage.libs.pari
|
|
1560
|
+
[(0, 0), (4, 4), (0, 3), (4, 7)]
|
|
1561
|
+
sage: eqs = [-y^2+z^2, -x^2+y^2-3*z^2-z-1, -y*z-z^2-x-y+2, -x^2-12*z^2-y+z]
|
|
1562
|
+
sage: solve_mod(eqs, 11) # needs sage.libs.pari
|
|
1563
|
+
[(8, 5, 6)]
|
|
1564
|
+
|
|
1565
|
+
Confirm that modulus 1 now behaves as it should::
|
|
1566
|
+
|
|
1567
|
+
sage: x, y = var("x y")
|
|
1568
|
+
sage: solve_mod([x==1], 1) # needs sage.libs.pari
|
|
1569
|
+
[(0,)]
|
|
1570
|
+
sage: solve_mod([2*x^2+x*y, -x*y+2*y^2+x-2*y, -2*x^2+2*x*y-y^2-x-y], 1) # needs sage.libs.pari
|
|
1571
|
+
[(0, 0)]
|
|
1572
|
+
"""
|
|
1573
|
+
from sage.rings.finite_rings.integer_mod_ring import Integers
|
|
1574
|
+
from sage.rings.integer import Integer
|
|
1575
|
+
from sage.rings.integer_ring import crt_basis
|
|
1576
|
+
from sage.structure.element import Expression
|
|
1577
|
+
from sage.modules.free_module_element import vector
|
|
1578
|
+
from sage.matrix.constructor import matrix
|
|
1579
|
+
|
|
1580
|
+
if not isinstance(eqns, (list, tuple)):
|
|
1581
|
+
eqns = [eqns]
|
|
1582
|
+
eqns = [eq if isinstance(eq, Expression) else (eq.lhs() - eq.rhs()) for eq in eqns]
|
|
1583
|
+
modulus = Integer(modulus)
|
|
1584
|
+
if modulus < 1:
|
|
1585
|
+
raise ValueError("the modulus must be a positive integer")
|
|
1586
|
+
vars = list(set(sum([list(e.variables()) for e in eqns], [])))
|
|
1587
|
+
vars.sort(key=repr)
|
|
1588
|
+
|
|
1589
|
+
if modulus == 1: # degenerate case
|
|
1590
|
+
ans = [tuple(Integers(1)(0) for v in vars)]
|
|
1591
|
+
return ans
|
|
1592
|
+
|
|
1593
|
+
factors = modulus.factor()
|
|
1594
|
+
crt_basis = vector(Integers(modulus), crt_basis([p**i for p, i in factors]))
|
|
1595
|
+
solutions = []
|
|
1596
|
+
|
|
1597
|
+
has_solution = True
|
|
1598
|
+
for p, i in factors:
|
|
1599
|
+
solution = _solve_mod_prime_power(eqns, p, i, vars)
|
|
1600
|
+
if len(solution) > 0:
|
|
1601
|
+
solutions.append(solution)
|
|
1602
|
+
else:
|
|
1603
|
+
has_solution = False
|
|
1604
|
+
break
|
|
1605
|
+
|
|
1606
|
+
ans = []
|
|
1607
|
+
if has_solution:
|
|
1608
|
+
for solution in product(*solutions):
|
|
1609
|
+
solution_mat = matrix(Integers(modulus), solution)
|
|
1610
|
+
ans.append(tuple(c.dot_product(crt_basis) for c in solution_mat.columns()))
|
|
1611
|
+
|
|
1612
|
+
# if solution_dict == True:
|
|
1613
|
+
# Relaxed form suggested by Mike Hansen (#8553):
|
|
1614
|
+
if solution_dict:
|
|
1615
|
+
return [dict(zip(vars, solution)) for solution in ans]
|
|
1616
|
+
return ans
|
|
1617
|
+
|
|
1618
|
+
|
|
1619
|
+
def _solve_mod_prime_power(eqns, p, m, vars):
|
|
1620
|
+
r"""
|
|
1621
|
+
Internal help function for solve_mod, does little checking since it expects
|
|
1622
|
+
solve_mod to do that
|
|
1623
|
+
|
|
1624
|
+
Return all solutions to an equation or list of equations modulo p^m.
|
|
1625
|
+
Each equation must involve only polynomials
|
|
1626
|
+
in 1 or many variables.
|
|
1627
|
+
|
|
1628
|
+
The solutions are returned as `n`-tuples, where `n`
|
|
1629
|
+
is the number of variables in vars.
|
|
1630
|
+
|
|
1631
|
+
INPUT:
|
|
1632
|
+
|
|
1633
|
+
- ``eqns`` -- equation or list of equations
|
|
1634
|
+
|
|
1635
|
+
- ``p`` -- a prime
|
|
1636
|
+
|
|
1637
|
+
- ``i`` -- integer > 0
|
|
1638
|
+
|
|
1639
|
+
- ``vars`` -- list of variables to solve for
|
|
1640
|
+
|
|
1641
|
+
EXAMPLES::
|
|
1642
|
+
|
|
1643
|
+
sage: var('x,y')
|
|
1644
|
+
(x, y)
|
|
1645
|
+
sage: solve_mod([x^2 + 2 == x, x^2 + y == y^2], 14)
|
|
1646
|
+
[(4, 2), (4, 6), (4, 9), (4, 13)]
|
|
1647
|
+
sage: solve_mod([x^2 == 1, 4*x == 11], 15)
|
|
1648
|
+
[(14,)]
|
|
1649
|
+
|
|
1650
|
+
Fermat's equation modulo 3 with exponent 5::
|
|
1651
|
+
|
|
1652
|
+
sage: var('x,y,z')
|
|
1653
|
+
(x, y, z)
|
|
1654
|
+
sage: solve_mod([x^5 + y^5 == z^5], 3)
|
|
1655
|
+
[(0, 0, 0), (0, 1, 1), (0, 2, 2), (1, 0, 1), (1, 1, 2), (1, 2, 0), (2, 0, 2), (2, 1, 0), (2, 2, 1)]
|
|
1656
|
+
|
|
1657
|
+
We solve a simple equation modulo 2::
|
|
1658
|
+
|
|
1659
|
+
sage: x,y = var('x,y')
|
|
1660
|
+
sage: solve_mod([x == y], 2)
|
|
1661
|
+
[(0, 0), (1, 1)]
|
|
1662
|
+
|
|
1663
|
+
|
|
1664
|
+
.. warning::
|
|
1665
|
+
|
|
1666
|
+
Currently this constructs possible solutions by building up
|
|
1667
|
+
from the smallest prime factor of the modulus. The interface
|
|
1668
|
+
is good, but the algorithm is horrible if the modulus is not the
|
|
1669
|
+
product of many small primes! Sage *does* have the ability to
|
|
1670
|
+
do something much faster in certain cases at least by using the
|
|
1671
|
+
Chinese Remainder Theorem, Groebner basis, linear algebra
|
|
1672
|
+
techniques, etc. But for a lot of toy problems this function as
|
|
1673
|
+
is might be useful. At the very least, it establishes an
|
|
1674
|
+
interface.
|
|
1675
|
+
|
|
1676
|
+
TESTS:
|
|
1677
|
+
|
|
1678
|
+
Confirm we can reproduce the first few terms of :oeis:`A187719`::
|
|
1679
|
+
|
|
1680
|
+
sage: from sage.symbolic.relation import _solve_mod_prime_power
|
|
1681
|
+
sage: [sorted(_solve_mod_prime_power([x^2==41], 10, i, [x]))[0][0] for i in [1..13]]
|
|
1682
|
+
[1, 21, 71, 1179, 2429, 47571, 1296179, 8703821, 26452429, 526452429,
|
|
1683
|
+
13241296179, 19473547571, 2263241296179]
|
|
1684
|
+
"""
|
|
1685
|
+
from sage.rings.finite_rings.integer_mod_ring import Integers
|
|
1686
|
+
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
|
|
1687
|
+
from sage.modules.free_module_element import vector
|
|
1688
|
+
|
|
1689
|
+
mrunning = 1
|
|
1690
|
+
ans = []
|
|
1691
|
+
for mi in range(m):
|
|
1692
|
+
mrunning *= p
|
|
1693
|
+
R = Integers(mrunning)
|
|
1694
|
+
S = PolynomialRing(R, len(vars), vars)
|
|
1695
|
+
eqns_mod = [S(eq) for eq in eqns]
|
|
1696
|
+
if mi == 0:
|
|
1697
|
+
possibles = product(*[range(len(R)) for _ in range(len(vars))])
|
|
1698
|
+
else:
|
|
1699
|
+
shifts = product(*[range(p) for _ in range(len(vars))])
|
|
1700
|
+
pairs = product(shifts, ans)
|
|
1701
|
+
possibles = (tuple(vector(t) + vector(shift) * (mrunning // p))
|
|
1702
|
+
for shift, t in pairs)
|
|
1703
|
+
ans = [t for t in possibles if all(e(*t) == 0 for e in eqns_mod)]
|
|
1704
|
+
if not ans:
|
|
1705
|
+
return ans
|
|
1706
|
+
|
|
1707
|
+
return ans
|
|
1708
|
+
|
|
1709
|
+
|
|
1710
|
+
def solve_ineq_univar(ineq):
|
|
1711
|
+
"""
|
|
1712
|
+
Function solves rational inequality in one variable.
|
|
1713
|
+
|
|
1714
|
+
INPUT:
|
|
1715
|
+
|
|
1716
|
+
- ``ineq`` -- inequality in one variable
|
|
1717
|
+
|
|
1718
|
+
OUTPUT:
|
|
1719
|
+
|
|
1720
|
+
- ``list`` -- output is list of solutions as a list of simple inequalities
|
|
1721
|
+
output [A,B,C] means (A or B or C) each A, B, C is again a list and
|
|
1722
|
+
if A=[a,b], then A means (a and b). The list is empty if there is no
|
|
1723
|
+
solution.
|
|
1724
|
+
|
|
1725
|
+
EXAMPLES::
|
|
1726
|
+
|
|
1727
|
+
sage: from sage.symbolic.relation import solve_ineq_univar
|
|
1728
|
+
sage: solve_ineq_univar(x-1/x>0)
|
|
1729
|
+
[[x > -1, x < 0], [x > 1]]
|
|
1730
|
+
|
|
1731
|
+
sage: solve_ineq_univar(x^2-1/x>0)
|
|
1732
|
+
[[x < 0], [x > 1]]
|
|
1733
|
+
|
|
1734
|
+
sage: solve_ineq_univar((x^3-1)*x<=0)
|
|
1735
|
+
[[x >= 0, x <= 1]]
|
|
1736
|
+
|
|
1737
|
+
ALGORITHM:
|
|
1738
|
+
|
|
1739
|
+
Calls Maxima command ``solve_rat_ineq``
|
|
1740
|
+
|
|
1741
|
+
AUTHORS:
|
|
1742
|
+
|
|
1743
|
+
- Robert Marik (01-2010)
|
|
1744
|
+
"""
|
|
1745
|
+
ineqvar = ineq.variables()
|
|
1746
|
+
if len(ineqvar) != 1:
|
|
1747
|
+
raise NotImplementedError("The command solve_ineq_univar accepts univariate inequalities only. Your variables are " + ineqvar)
|
|
1748
|
+
ineq0 = ineq._maxima_()
|
|
1749
|
+
ineq0.parent().eval("if solve_rat_ineq_loaded#true then (solve_rat_ineq_loaded:true,load(\"solve_rat_ineq.mac\")) ")
|
|
1750
|
+
sol = ineq0.solve_rat_ineq().sage()
|
|
1751
|
+
if repr(sol) == "all":
|
|
1752
|
+
from sage.rings.infinity import Infinity
|
|
1753
|
+
sol = [ineqvar[0] < Infinity]
|
|
1754
|
+
return sol
|
|
1755
|
+
|
|
1756
|
+
|
|
1757
|
+
def solve_ineq_fourier(ineq, vars=None):
|
|
1758
|
+
"""
|
|
1759
|
+
Solve system of inequalities using Maxima and Fourier elimination.
|
|
1760
|
+
|
|
1761
|
+
Can be used for system of linear inequalities and for some types
|
|
1762
|
+
of nonlinear inequalities. For examples, see the example section
|
|
1763
|
+
below and http://maxima.cvs.sourceforge.net/viewvc/maxima/maxima/share/contrib/fourier_elim/rtest_fourier_elim.mac
|
|
1764
|
+
|
|
1765
|
+
|
|
1766
|
+
INPUT:
|
|
1767
|
+
|
|
1768
|
+
- ``ineq`` -- list with system of inequalities
|
|
1769
|
+
|
|
1770
|
+
- ``vars`` -- optionally list with variables for Fourier elimination
|
|
1771
|
+
|
|
1772
|
+
OUTPUT:
|
|
1773
|
+
|
|
1774
|
+
- ``list`` -- output is list of solutions as a list of simple inequalities
|
|
1775
|
+
output [A,B,C] means (A or B or C) each A, B, C is again a list and
|
|
1776
|
+
if A=[a,b], then A means (a and b). The list is empty if there is no
|
|
1777
|
+
solution.
|
|
1778
|
+
|
|
1779
|
+
EXAMPLES::
|
|
1780
|
+
|
|
1781
|
+
sage: from sage.symbolic.relation import solve_ineq_fourier
|
|
1782
|
+
sage: y = var('y')
|
|
1783
|
+
sage: solve_ineq_fourier([x+y<9,x-y>4],[x,y])
|
|
1784
|
+
[[y + 4 < x, x < -y + 9, y < (5/2)]]
|
|
1785
|
+
sage: solve_ineq_fourier([x+y<9,x-y>4],[y,x])[0][0](x=42)
|
|
1786
|
+
y < -33
|
|
1787
|
+
|
|
1788
|
+
sage: solve_ineq_fourier([x^2>=0])
|
|
1789
|
+
[[x < +Infinity]]
|
|
1790
|
+
|
|
1791
|
+
sage: solve_ineq_fourier([log(x)>log(y)],[x,y])
|
|
1792
|
+
[[y < x, 0 < y]]
|
|
1793
|
+
sage: solve_ineq_fourier([log(x)>log(y)],[y,x])
|
|
1794
|
+
[[0 < y, y < x, 0 < x]]
|
|
1795
|
+
|
|
1796
|
+
Note that different systems will find default variables in different
|
|
1797
|
+
orders, so the following is not tested::
|
|
1798
|
+
|
|
1799
|
+
sage: solve_ineq_fourier([log(x)>log(y)]) # random (one of the following appears)
|
|
1800
|
+
[[0 < y, y < x, 0 < x]]
|
|
1801
|
+
[[y < x, 0 < y]]
|
|
1802
|
+
|
|
1803
|
+
ALGORITHM:
|
|
1804
|
+
|
|
1805
|
+
Calls Maxima command ``fourier_elim``
|
|
1806
|
+
|
|
1807
|
+
AUTHORS:
|
|
1808
|
+
|
|
1809
|
+
- Robert Marik (01-2010)
|
|
1810
|
+
"""
|
|
1811
|
+
if vars is None:
|
|
1812
|
+
setvars = set()
|
|
1813
|
+
for i in (ineq):
|
|
1814
|
+
setvars = setvars.union(set(i.variables()))
|
|
1815
|
+
vars = list(setvars)
|
|
1816
|
+
ineq0 = [i._maxima_() for i in ineq]
|
|
1817
|
+
ineq0[0].parent().eval("if fourier_elim_loaded#true then (fourier_elim_loaded:true,load(\"fourier_elim\"))")
|
|
1818
|
+
sol = ineq0[0].parent().fourier_elim(ineq0, vars)
|
|
1819
|
+
ineq0[0].parent().eval("or_to_list(x):=\
|
|
1820
|
+
if not atom(x) and op(x)=\"or\" then args(x) \
|
|
1821
|
+
else [x]")
|
|
1822
|
+
sol = sol.or_to_list().sage()
|
|
1823
|
+
if repr(sol) == "[emptyset]":
|
|
1824
|
+
sol = []
|
|
1825
|
+
if repr(sol) == "[universalset]":
|
|
1826
|
+
from sage.rings.infinity import Infinity
|
|
1827
|
+
sol = [[i < Infinity for i in vars]]
|
|
1828
|
+
return sol
|
|
1829
|
+
|
|
1830
|
+
|
|
1831
|
+
def solve_ineq(ineq, vars=None):
|
|
1832
|
+
"""
|
|
1833
|
+
Solve inequalities and systems of inequalities using Maxima.
|
|
1834
|
+
Switches between rational inequalities
|
|
1835
|
+
(sage.symbolic.relation.solve_ineq_rational)
|
|
1836
|
+
and Fourier elimination (sage.symbolic.relation.solve_ineq_fouried).
|
|
1837
|
+
See the documentation of these functions for more details.
|
|
1838
|
+
|
|
1839
|
+
INPUT:
|
|
1840
|
+
|
|
1841
|
+
- ``ineq`` -- one inequality or a list of inequalities
|
|
1842
|
+
|
|
1843
|
+
Case1: If ``ineq`` is one equality, then it should be rational
|
|
1844
|
+
expression in one variable. This input is passed to
|
|
1845
|
+
sage.symbolic.relation.solve_ineq_univar function.
|
|
1846
|
+
|
|
1847
|
+
Case2: If ``ineq`` is a list involving one or more
|
|
1848
|
+
inequalities, than the input is passed to
|
|
1849
|
+
sage.symbolic.relation.solve_ineq_fourier function. This
|
|
1850
|
+
function can be used for system of linear inequalities and
|
|
1851
|
+
for some types of nonlinear inequalities. See
|
|
1852
|
+
http://maxima.cvs.sourceforge.net/viewvc/maxima/maxima/share/contrib/fourier_elim/rtest_fourier_elim.mac
|
|
1853
|
+
for a big gallery of problems covered by this algorithm.
|
|
1854
|
+
|
|
1855
|
+
- ``vars`` -- (optional) parameter with list of variables. This list
|
|
1856
|
+
is used only if Fourier elimination is used. If omitted or if
|
|
1857
|
+
rational inequality is solved, then variables are determined
|
|
1858
|
+
automatically.
|
|
1859
|
+
|
|
1860
|
+
OUTPUT:
|
|
1861
|
+
|
|
1862
|
+
- ``list`` -- output is list of solutions as a list of simple inequalities
|
|
1863
|
+
output [A,B,C] means (A or B or C) each A, B, C is again a list and
|
|
1864
|
+
if A=[a,b], then A means (a and b).
|
|
1865
|
+
|
|
1866
|
+
EXAMPLES::
|
|
1867
|
+
|
|
1868
|
+
sage: from sage.symbolic.relation import solve_ineq
|
|
1869
|
+
|
|
1870
|
+
Inequalities in one variable. The variable is detected automatically::
|
|
1871
|
+
|
|
1872
|
+
sage: solve_ineq(x^2-1>3)
|
|
1873
|
+
[[x < -2], [x > 2]]
|
|
1874
|
+
|
|
1875
|
+
sage: solve_ineq(1/(x-1)<=8)
|
|
1876
|
+
[[x < 1], [x >= (9/8)]]
|
|
1877
|
+
|
|
1878
|
+
System of inequalities with automatically detected inequalities::
|
|
1879
|
+
|
|
1880
|
+
sage: y = var('y')
|
|
1881
|
+
sage: solve_ineq([x-y<0,x+y-3<0],[y,x])
|
|
1882
|
+
[[x < y, y < -x + 3, x < (3/2)]]
|
|
1883
|
+
sage: solve_ineq([x-y<0,x+y-3<0],[x,y])
|
|
1884
|
+
[[x < min(-y + 3, y)]]
|
|
1885
|
+
|
|
1886
|
+
Note that although Sage will detect the variables automatically,
|
|
1887
|
+
the order it puts them in may depend on the system, so the following
|
|
1888
|
+
command is only guaranteed to give you one of the above answers::
|
|
1889
|
+
|
|
1890
|
+
sage: solve_ineq([x-y<0,x+y-3<0]) # random
|
|
1891
|
+
[[x < y, y < -x + 3, x < (3/2)]]
|
|
1892
|
+
|
|
1893
|
+
ALGORITHM:
|
|
1894
|
+
|
|
1895
|
+
Calls ``solve_ineq_fourier`` if inequalities are list and
|
|
1896
|
+
``solve_ineq_univar`` of the inequality is symbolic expression. See
|
|
1897
|
+
the description of these commands for more details related to the
|
|
1898
|
+
set of inequalities which can be solved. The list is empty if
|
|
1899
|
+
there is no solution.
|
|
1900
|
+
|
|
1901
|
+
AUTHORS:
|
|
1902
|
+
|
|
1903
|
+
- Robert Marik (01-2010)
|
|
1904
|
+
"""
|
|
1905
|
+
if isinstance(ineq, list):
|
|
1906
|
+
return solve_ineq_fourier(ineq, vars)
|
|
1907
|
+
return solve_ineq_univar(ineq)
|