44Converts expressions from SymPy to Mathics expressions.
55Conversion to SymPy is handled directly in BaseElement descendants.
66"""
7- from typing import Optional , Type , Union
7+ from typing import TYPE_CHECKING , Dict , List , Optional , Sequence , Tuple , Union , cast
88
99import sympy
1010from sympy import Symbol as Sympy_Symbol , false as SympyFalse , true as SympyTrue
6666 SymbolUnequal ,
6767)
6868
69+ if TYPE_CHECKING :
70+ from mathics .core .builtin import SympyObject
71+
6972BasicSympy = sympy .Expr
7073
7174
7477SymbolRootSum = Symbol ("RootSum" )
7578
7679
77- mathics_to_sympy = {} # here we have: name -> sympy object
78- sympy_to_mathics = {}
80+ mathics_to_sympy : Dict [ str , "SympyObject" ] = {} # here we have: name -> sympy object
81+ sympy_to_mathics : Dict [ str , "SympyObject" ] = {}
7982
8083
8184sympy_singleton_to_mathics = {
104107}
105108
106109
107- def is_Cn_expr (name ) -> bool :
110+ def is_Cn_expr (name : str ) -> bool :
108111 """Check if name is of the form {prefix}Cnnn"""
109112 if name .startswith (sympy_symbol_prefix ) or name .startswith (sympy_slot_prefix ):
110113 return False
111114 if not name .startswith ("C" ):
112115 return False
113116 number = name [1 :]
114- return number and number .isdigit ()
117+ return number != "" and number .isdigit ()
115118
116119
117120def to_sympy_matrix (data , ** kwargs ) -> Optional [sympy .MutableDenseMatrix ]:
@@ -131,6 +134,7 @@ class SympyExpression(BasicSympy):
131134
132135 is_Function = True
133136 nargs = None
137+ expr : Expression
134138
135139 def __new__ (cls , * exprs ):
136140 # sympy simplify may also recreate the object if simplification occurred
@@ -167,7 +171,11 @@ def __new__(cls, *args):
167171
168172 def has_any_symbols (self , * syms ) -> bool :
169173 """Check if any of the symbols in syms appears in the expression."""
170- result = any (arg .has_any_symbols (* syms ) for arg in self .args )
174+ result = any (
175+ arg .has_any_symbols (* syms )
176+ for arg in self .args
177+ if isinstance (arg , SympyExpression )
178+ )
171179 return result
172180
173181 def _eval_subs (self , old , new ):
@@ -185,10 +193,14 @@ def _eval_rewrite(self, rule, args, **hints):
185193 return self
186194
187195 @property
188- def is_commutative (self ) -> bool :
196+ def is_commutative (self ) -> Optional [ bool ] :
189197 """Check if the arguments are commutative."""
190198 return all (getattr (t , "is_commutative" , False ) for t in self .args )
191199
200+ @is_commutative .setter
201+ def is_commutative (self , value : bool ) -> None :
202+ return
203+
192204 def __str__ (self ) -> str :
193205 return f"{ super ().__str__ ()} [{ self .expr } ])"
194206
@@ -257,7 +269,7 @@ def symbol_to_sympy(symbol: Symbol, **kwargs) -> Sympy_Symbol:
257269 return builtin .to_sympy (symbol , ** kwargs )
258270
259271
260- def to_numeric_sympy_args (mathics_args : Type [ BaseElement ] , evaluation ) -> list :
272+ def to_numeric_sympy_args (mathics_args : BaseElement , evaluation ) -> list :
261273 """
262274 Convert Mathics arguments, such as the arguments in an evaluation
263275 method a Python list that is sutiable for feeding as arguments
@@ -268,6 +280,7 @@ def to_numeric_sympy_args(mathics_args: Type[BaseElement], evaluation) -> list:
268280 from mathics .eval .numerify import numerify
269281
270282 if mathics_args .is_literal :
283+ assert hasattr (mathics_args , "value" )
271284 sympy_args = [mathics_args .value ]
272285 else :
273286 args = numerify (mathics_args , evaluation ).get_sequence ()
@@ -352,16 +365,16 @@ def old_from_sympy(expr) -> BaseElement:
352365 if expr .is_Symbol :
353366 name = str (expr )
354367 if isinstance (expr , sympy .Dummy ):
355- name = name + (f"__Dummy_{ expr .dummy_index } " )
368+ name = name + (f"__Dummy_{ expr .dummy_index } " ) # type: ignore[attr-defined]
356369 # Probably, this should be the value attribute
357370 return Symbol (name , sympy_dummy = expr )
358371 if is_Cn_expr (name ):
359372 return Expression (SymbolC , Integer (int (name [1 :])))
360373 if name .startswith (sympy_symbol_prefix ):
361374 name = name [len (sympy_symbol_prefix ) :]
362375 if name .startswith (sympy_slot_prefix ):
363- index = name [len (sympy_slot_prefix ) :]
364- return Expression (SymbolSlot , Integer (int ( index ) ))
376+ index = int ( name [len (sympy_slot_prefix ) :])
377+ return Expression (SymbolSlot , Integer (index ))
365378 elif expr .is_NumberSymbol :
366379 name = str (expr )
367380 if name is not None :
@@ -427,25 +440,26 @@ def old_from_sympy(expr) -> BaseElement:
427440 return expr .expr
428441
429442 if isinstance (expr , sympy .Piecewise ):
430- args = expr .args
431443 return Expression (
432444 SymbolPiecewise ,
433445 ListExpression (
434446 * [
435447 to_mathics_list (from_sympy (case ), from_sympy (cond ))
436- for case , cond in args
448+ for case , cond in cast (
449+ Sequence [Tuple [sympy .Basic , sympy .Basic ]], expr .args
450+ )
437451 ]
438452 ),
439453 )
440454
441455 if isinstance (expr , SympyPrime ):
442456 return Expression (SymbolPrime , from_sympy (expr .args [0 ]))
443457 if isinstance (expr , sympy .RootSum ):
444- return Expression (SymbolRootSum , from_sympy (expr .poly ), from_sympy (expr .fun ))
458+ return Expression (SymbolRootSum , from_sympy (expr .poly ), from_sympy (expr .fun )) # type: ignore[attr-defined]
445459 if isinstance (expr , sympy .PurePoly ):
446460 coeffs = expr .coeffs ()
447461 monoms = expr .monoms ()
448- result = []
462+ result : List [ BaseElement ] = []
449463 for coeff , monom in zip (coeffs , monoms ):
450464 factors = []
451465 if coeff != 1 :
@@ -500,12 +514,14 @@ def old_from_sympy(expr) -> BaseElement:
500514 else :
501515 margs .append (from_sympy (arg ))
502516 builtin = sympy_to_mathics .get (name )
503- return builtin .from_sympy (margs )
517+ assert builtin is not None
518+ return builtin .from_sympy (tuple (margs ))
504519
505520 elif isinstance (expr , sympy .sign ):
506521 name = "Sign"
507522 else :
508523 name = expr .func .__name__
524+ assert name is not None
509525 if is_Cn_expr (name ):
510526 return Expression (
511527 Expression (Symbol ("C" ), Integer (int (name [1 :]))),
@@ -516,7 +532,7 @@ def old_from_sympy(expr) -> BaseElement:
516532 args = [from_sympy (arg ) for arg in expr .args ]
517533 builtin = sympy_to_mathics .get (name )
518534 if builtin is not None :
519- return builtin .from_sympy (args )
535+ return builtin .from_sympy (tuple ( args ) )
520536 return Expression (Symbol (name ), * args )
521537
522538 if isinstance (expr , sympy .Tuple ):
0 commit comments