10
10
"""
11
11
12
12
from itertools import product
13
- from typing import Optional , Union
13
+ from typing import Optional
14
14
15
15
import numpy as np
16
16
import sympy
59
59
from mathics .core .systemsymbols import (
60
60
SymbolAnd ,
61
61
SymbolAutomatic ,
62
+ SymbolComplex ,
62
63
SymbolConditionalExpression ,
63
64
SymbolD ,
64
65
SymbolDerivative ,
65
66
SymbolInfinity ,
66
67
SymbolInfix ,
68
+ SymbolInteger ,
67
69
SymbolIntegrate ,
68
70
SymbolLeft ,
69
71
SymbolLog ,
70
72
SymbolNIntegrate ,
71
73
SymbolO ,
74
+ SymbolReal ,
72
75
SymbolRule ,
73
76
SymbolSequence ,
74
77
SymbolSeries ,
75
78
SymbolSeriesData ,
76
79
SymbolSimplify ,
77
80
SymbolUndefined ,
78
81
)
82
+ from mathics .eval .calculus import solve_sympy
79
83
from mathics .eval .makeboxes import format_element
80
84
from mathics .eval .nevaluator import eval_N
81
85
from mathics .eval .numbers .calculus .integrators import (
@@ -2210,105 +2214,38 @@ class Solve(Builtin):
2210
2214
messages = {
2211
2215
"eqf" : "`1` is not a well-formed equation." ,
2212
2216
"svars" : 'Equations may not give solutions for all "solve" variables.' ,
2217
+ "fulldim" : "The solution set contains a full-dimensional component; use Reduce for complete solution information." ,
2213
2218
}
2214
2219
2215
- # FIXME: the problem with removing the domain parameter from the outside
2216
- # is that the we can't make use of this information inside
2217
- # the evaluation method where it is may be needed.
2218
2220
rules = {
2219
- "Solve[eqs_, vars_, Complexes]" : "Solve[eqs, vars]" ,
2220
- "Solve[eqs_, vars_, Reals]" : (
2221
- "Cases[Solve[eqs, vars], {Rule[x_,y_?RealValuedNumberQ]}]"
2222
- ),
2223
- "Solve[eqs_, vars_, Integers]" : (
2224
- "Cases[Solve[eqs, vars], {Rule[x_,y_Integer]}]"
2225
- ),
2221
+ "Solve[eqs_, vars_]" : "Solve[eqs, vars, Complexes]"
2226
2222
}
2227
2223
summary_text = "find generic solutions for variables"
2228
2224
2229
- def eval (self , eqs , vars , evaluation : Evaluation ):
2230
- "Solve[eqs_, vars_]"
2225
+ def eval (self , eqs , vars , domain , evaluation : Evaluation ):
2226
+ "Solve[eqs_, vars_, domain_ ]"
2231
2227
2232
- vars_original = vars
2233
- head_name = vars .get_head_name ()
2228
+ variables = vars
2229
+ head_name = variables .get_head_name ()
2234
2230
if head_name == "System`List" :
2235
- vars = vars .elements
2231
+ variables = variables .elements
2236
2232
else :
2237
- vars = [vars ]
2238
- for var in vars :
2233
+ variables = [variables ]
2234
+ for var in variables :
2239
2235
if (
2240
2236
(isinstance (var , Atom ) and not isinstance (var , Symbol )) or
2241
2237
head_name in ("System`Plus" , "System`Times" , "System`Power" ) or # noqa
2242
2238
A_CONSTANT & var .get_attributes (evaluation .definitions )
2243
2239
):
2244
2240
2245
- evaluation .message ("Solve" , "ivar" , vars_original )
2241
+ evaluation .message ("Solve" , "ivar" , vars )
2246
2242
return
2247
2243
2248
- vars_sympy = [var .to_sympy () for var in vars ]
2249
- if None in vars_sympy :
2244
+ sympy_variables = [var .to_sympy () for var in variables ]
2245
+ if None in sympy_variables :
2250
2246
evaluation .message ("Solve" , "ivar" )
2251
2247
return
2252
- all_var_tuples = list (zip (vars , vars_sympy ))
2253
-
2254
- def cut_var_dimension (expressions : Union [Expression , list [Expression ]]):
2255
- '''delete unused variables to avoid SymPy's PolynomialError
2256
- : Not a zero-dimensional system in e.g. Solve[x^2==1&&z^2==-1,{x,y,z}]'''
2257
- if not isinstance (expressions , list ):
2258
- expressions = [expressions ]
2259
- subset_vars = set ()
2260
- subset_vars_sympy = set ()
2261
- for var , var_sympy in all_var_tuples :
2262
- pattern = Pattern .create (var )
2263
- for equation in expressions :
2264
- if not equation .is_free (pattern , evaluation ):
2265
- subset_vars .add (var )
2266
- subset_vars_sympy .add (var_sympy )
2267
- return subset_vars , subset_vars_sympy
2268
-
2269
- def solve_sympy (equations : Union [Expression , list [Expression ]]):
2270
- if not isinstance (equations , list ):
2271
- equations = [equations ]
2272
- equations_sympy = []
2273
- denoms_sympy = []
2274
- subset_vars , subset_vars_sympy = cut_var_dimension (equations )
2275
- for equation in equations :
2276
- if equation is SymbolTrue :
2277
- continue
2278
- elif equation is SymbolFalse :
2279
- return []
2280
- elements = equation .elements
2281
- for left , right in [(elements [index ], elements [index + 1 ]) for index in range (len (elements ) - 1 )]:
2282
- # ↑ to deal with things like a==b==c==d
2283
- left = left .to_sympy ()
2284
- right = right .to_sympy ()
2285
- if left is None or right is None :
2286
- return []
2287
- equation_sympy = left - right
2288
- equation_sympy = sympy .together (equation_sympy )
2289
- equation_sympy = sympy .cancel (equation_sympy )
2290
- equations_sympy .append (equation_sympy )
2291
- numer , denom = equation_sympy .as_numer_denom ()
2292
- denoms_sympy .append (denom )
2293
- try :
2294
- results = sympy .solve (equations_sympy , subset_vars_sympy , dict = True ) # no transform_dict needed with dict=True
2295
- # Filter out results for which denominator is 0
2296
- # (SymPy should actually do that itself, but it doesn't!)
2297
- results = [
2298
- sol
2299
- for sol in results
2300
- if all (sympy .simplify (denom .subs (sol )) != 0 for denom in denoms_sympy )
2301
- ]
2302
- return results
2303
- except sympy .PolynomialError :
2304
- # raised for e.g. Solve[x^2==1&&z^2==-1,{x,y,z}] when not deleting
2305
- # unused variables beforehand
2306
- return []
2307
- except NotImplementedError :
2308
- return []
2309
- except TypeError as exc :
2310
- if str (exc ).startswith ("expected Symbol, Function or Derivative" ):
2311
- evaluation .message ("Solve" , "ivar" , vars_original )
2248
+ variable_tuples = list (zip (variables , sympy_variables ))
2312
2249
2313
2250
def solve_recur (expression : Expression ):
2314
2251
'''solve And, Or and List within the scope of sympy,
@@ -2336,7 +2273,7 @@ def solve_recur(expression: Expression):
2336
2273
inequations .append (sub_condition )
2337
2274
else :
2338
2275
inequations .append (child .to_sympy ())
2339
- solutions .extend (solve_sympy (equations ))
2276
+ solutions .extend (solve_sympy (evaluation , equations , variables , domain ))
2340
2277
conditions = sympy .And (* inequations )
2341
2278
result = [sol for sol in solutions if conditions .subs (sol )]
2342
2279
return result , None if solutions else conditions
@@ -2346,7 +2283,7 @@ def solve_recur(expression: Expression):
2346
2283
conditions = []
2347
2284
for child in expression .elements :
2348
2285
if child .has_form ("Equal" , 2 ):
2349
- solutions .extend (solve_sympy (child ))
2286
+ solutions .extend (solve_sympy (evaluation , child , variables , domain ))
2350
2287
elif child .get_head_name () in ('System`And' , 'System`Or' ): # I don't believe List would be in here
2351
2288
sub_solution , sub_condition = solve_recur (child )
2352
2289
solutions .extend (sub_solution )
@@ -2365,8 +2302,8 @@ def solve_recur(expression: Expression):
2365
2302
if conditions is not None :
2366
2303
evaluation .message ("Solve" , "fulldim" )
2367
2304
else :
2368
- if eqs .has_form ( " Equal", 2 ) :
2369
- solutions = solve_sympy (eqs )
2305
+ if eqs .get_head_name () == "System` Equal" :
2306
+ solutions = solve_sympy (evaluation , eqs , variables , domain )
2370
2307
else :
2371
2308
evaluation .message ("Solve" , "fulldim" )
2372
2309
return ListExpression (ListExpression ())
@@ -2376,7 +2313,7 @@ def solve_recur(expression: Expression):
2376
2313
return ListExpression (ListExpression ())
2377
2314
2378
2315
if any (
2379
- sol and any (var not in sol for var in vars_sympy ) for sol in solutions
2316
+ sol and any (var not in sol for var in sympy_variables ) for sol in solutions
2380
2317
):
2381
2318
evaluation .message ("Solve" , "svars" )
2382
2319
@@ -2385,7 +2322,7 @@ def solve_recur(expression: Expression):
2385
2322
ListExpression (
2386
2323
* (
2387
2324
Expression (SymbolRule , var , from_sympy (sol [var_sympy ]))
2388
- for var , var_sympy in all_var_tuples
2325
+ for var , var_sympy in variable_tuples
2389
2326
if var_sympy in sol
2390
2327
),
2391
2328
)
0 commit comments