Skip to content

Commit a25025a

Browse files
committed
use underscore as context mark in sympy symbols and function names
1 parent 9329419 commit a25025a

File tree

5 files changed

+51
-42
lines changed

5 files changed

+51
-42
lines changed

mathics/builtin/numbers/calculus.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
SymbolPower,
5858
SymbolTimes,
5959
SymbolTrue,
60+
sympy_name,
6061
)
6162
from mathics.core.systemsymbols import (
6263
SymbolAnd,
@@ -528,7 +529,7 @@ def to_sympy(self, expr, **kwargs):
528529
return
529530

530531
func = exprs[1].elements[0]
531-
sym_func = sympy.Function(str(SYMPY_SYMBOL_PREFIX + func.__str__()))(*sym_args)
532+
sym_func = sympy.Function(sympy_name(func))(*sym_args)
532533

533534
counts = [element.get_int_value() for element in exprs[2].elements]
534535
if None in counts:

mathics/core/convert/sympy.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,6 @@ def expression_to_sympy(expr: Expression, **kwargs):
236236
"""
237237
Convert `expr` to its sympy form.
238238
"""
239-
240239
if len(expr.elements) > 0:
241240
head_name = expr.get_head_name()
242241
if head_name.startswith("Global`"):
@@ -250,6 +249,7 @@ def expression_to_sympy(expr: Expression, **kwargs):
250249

251250
lookup_name = expr.get_lookup_name()
252251
builtin = mathics_to_sympy.get(lookup_name)
252+
253253
if builtin is not None:
254254
sympy_expr = builtin.to_sympy(expr, **kwargs)
255255
if sympy_expr is not None:
@@ -346,7 +346,6 @@ def old_from_sympy(expr) -> BaseElement:
346346
"""
347347
converts a SymPy object to a Mathics3 element.
348348
"""
349-
350349
if isinstance(expr, (tuple, list)):
351350
return to_mathics_list(*expr, elements_conversion_fn=from_sympy)
352351
if isinstance(expr, int):
@@ -371,16 +370,16 @@ def old_from_sympy(expr) -> BaseElement:
371370
name = str(expr)
372371
if isinstance(expr, sympy.Dummy):
373372
name = name[1:]
374-
if "`" not in name:
373+
if "_" not in name:
375374
name = f"sympy`dummy`Dummy${expr.dummy_index}" # type: ignore[attr-defined]
376375
else:
377-
name = name[len(SYMPY_SYMBOL_PREFIX) :]
376+
name = name[len(SYMPY_SYMBOL_PREFIX) :].replace("_", "`")
378377
# Probably, this should be the value attribute
379378
return Symbol(name)
380379
if is_Cn_expr(name):
381380
return Expression(SymbolC, Integer(int(name[1:])))
382381
if name.startswith(SYMPY_SYMBOL_PREFIX):
383-
name = name[len(SYMPY_SYMBOL_PREFIX) :]
382+
name = name[len(SYMPY_SYMBOL_PREFIX) :].replace("_", "`")
384383
if name.startswith(SYMPY_SLOT_PREFIX):
385384
index = int(name[len(SYMPY_SLOT_PREFIX) :])
386385
return Expression(SymbolSlot, Integer(index))
@@ -419,7 +418,8 @@ def old_from_sympy(expr) -> BaseElement:
419418
if isinstance(expr, sympy.core.numbers.NaN):
420419
return SymbolIndeterminate
421420
if isinstance(expr, sympy.core.function.FunctionClass):
422-
return Symbol(str(expr))
421+
name = str(expr).replace("_", "`")
422+
return Symbol(name)
423423
if expr is sympy.true:
424424
return SymbolTrue
425425
if expr is sympy.false:
@@ -546,7 +546,7 @@ def old_from_sympy(expr) -> BaseElement:
546546
*[from_sympy(arg) for arg in expr.args],
547547
)
548548
if name.startswith(SYMPY_SYMBOL_PREFIX):
549-
name = name[len(SYMPY_SYMBOL_PREFIX) :]
549+
name = name[len(SYMPY_SYMBOL_PREFIX) :].replace("_", "`")
550550
args = [from_sympy(arg) for arg in expr.args]
551551
builtin = sympy_to_mathics.get(name)
552552
if builtin is not None:

mathics/core/symbols.py

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ def sympy_strip_context(name) -> str:
126126
produce invalid code. In a next round, we would like
127127
to use another character for split contexts in sympy variables.
128128
"""
129-
return strip_context(name)
129+
return name.split("_")[-1]
130130

131131

132132
# system_symbols_dict({'SomeSymbol': ...}) -> {Symbol('System`SomeSymbol'): ...}
@@ -342,6 +342,7 @@ class Symbol(Atom, NumericOperators, EvalMixin):
342342

343343
name: str
344344
hash: int
345+
sympy_dummy: Any
345346
_short_name: str
346347

347348
# Dictionary of Symbols defined so far.
@@ -354,7 +355,7 @@ class Symbol(Atom, NumericOperators, EvalMixin):
354355

355356
# __new__ instead of __init__ is used here because we want
356357
# to return the same object for a given "name" value.
357-
def __new__(cls, name: str):
358+
def __new__(cls, name: str, sympy_dummy=None):
358359
"""
359360
Allocate an object ensuring that for a given ``name`` and ``cls`` we get back the same object,
360361
id(object) is the same and its object.__hash__() is the same.
@@ -384,6 +385,18 @@ def __new__(cls, name: str):
384385
# For example, this can happen with String constants.
385386

386387
self.hash = hash((cls, name))
388+
389+
# TODO: revise how we convert sympy.Dummy
390+
# symbols.
391+
#
392+
# In some cases, SymPy returns a sympy.Dummy
393+
# object. It is converted to Mathics as a
394+
# Symbol. However, we probably should have
395+
# a different class for this kind of symbols.
396+
# Also, sympy_dummy should be stored as the
397+
# value attribute.
398+
self.sympy_dummy = sympy_dummy
399+
387400
self._short_name = strip_context(name)
388401

389402
return self
@@ -392,7 +405,7 @@ def __eq__(self, other) -> bool:
392405
return self is other
393406

394407
def __getnewargs__(self):
395-
return (self.name,)
408+
return (self.name, self.sympy_dummy)
396409

397410
def __hash__(self) -> int:
398411
"""
@@ -690,12 +703,6 @@ def __new__(cls, name, value):
690703
self.hash = hash((cls, name))
691704
return self
692705

693-
def __getnewargs__(self):
694-
return (
695-
self.name,
696-
self._value,
697-
)
698-
699706
@property
700707
def is_literal(self) -> bool:
701708
"""
@@ -754,7 +761,7 @@ def symbol_set(*symbols: Symbol) -> FrozenSet[Symbol]:
754761

755762
def sympy_name(mathics_symbol: Symbol):
756763
"""Convert a mathics symbol name into a sympy symbol name"""
757-
return SYMPY_SYMBOL_PREFIX + mathics_symbol.name
764+
return SYMPY_SYMBOL_PREFIX + mathics_symbol.name.replace("`", "_")
758765

759766

760767
# Symbols used in this module.

mathics/eval/drawing/plot_compile.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
import sympy
2020

2121
from mathics.core.convert.sympy import SympyExpression, mathics_to_sympy
22-
from mathics.core.symbols import strip_context
22+
from mathics.core.symbols import sympy_strip_context
2323
from mathics.core.util import print_expression_tree, print_sympy_tree
2424

2525

@@ -82,7 +82,8 @@ def plot_compile(evaluation, expr, names, debug=0):
8282

8383
# Strip symbols in sympy expression of context.
8484
subs = {
85-
sym: sympy.Symbol(strip_context(str(sym))) for sym in sympy_expr.free_symbols
85+
sym: sympy.Symbol(sympy_strip_context(str(sym)))
86+
for sym in sympy_expr.free_symbols
8687
}
8788
sympy_expr = sympy_expr.subs(subs)
8889

test/core/test_sympy_python_convert.py

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,10 @@ def compare(self, mathics_expr, sympy_expr, **kwargs):
4949
self.compare_to_mathics(mathics_expr, sympy_expr)
5050

5151
def testSymbol(self):
52-
self.compare(Symbol("Global`x"), sympy.Symbol(f"{SYMPY_SYMBOL_PREFIX}Global`x"))
52+
self.compare(Symbol("Global`x"), sympy.Symbol(f"{SYMPY_SYMBOL_PREFIX}Global_x"))
5353
self.compare(
54-
Symbol("_Mathics_User_x"),
55-
sympy.Symbol(f"{SYMPY_SYMBOL_PREFIX}System`_Mathics_User_x"),
54+
Symbol("Mathics`User`x"),
55+
sympy.Symbol(f"{SYMPY_SYMBOL_PREFIX}Mathics_User_x"),
5656
)
5757

5858
def testReal(self):
@@ -88,24 +88,24 @@ def testString(self):
8888
def testAdd(self):
8989
self.compare(
9090
Expression(SymbolPlus, Integer1, Symbol("Global`x")),
91-
sympy.Add(sympy.Integer(1), sympy.Symbol(f"{SYMPY_SYMBOL_PREFIX}Global`x")),
91+
sympy.Add(sympy.Integer(1), sympy.Symbol(f"{SYMPY_SYMBOL_PREFIX}Global_x")),
9292
)
9393

9494
def testIntegrate(self):
9595
self.compare(
9696
Expression(SymbolIntegrate, Symbol("Global`x"), Symbol("Global`y")),
9797
sympy.Integral(
98-
sympy.Symbol(f"{SYMPY_SYMBOL_PREFIX}Global`x"),
99-
sympy.Symbol(f"{SYMPY_SYMBOL_PREFIX}Global`y"),
98+
sympy.Symbol(f"{SYMPY_SYMBOL_PREFIX}Global_x"),
99+
sympy.Symbol(f"{SYMPY_SYMBOL_PREFIX}Global_y"),
100100
),
101101
)
102102

103103
def testDerivative(self):
104104
self.compare(
105105
Expression(SymbolD, Symbol("Global`x"), Symbol("Global`y")),
106106
sympy.Derivative(
107-
sympy.Symbol(f"{SYMPY_SYMBOL_PREFIX}Global`x"),
108-
sympy.Symbol(f"{SYMPY_SYMBOL_PREFIX}Global`y"),
107+
sympy.Symbol(f"{SYMPY_SYMBOL_PREFIX}Global_x"),
108+
sympy.Symbol(f"{SYMPY_SYMBOL_PREFIX}Global_y"),
109109
),
110110
)
111111

@@ -118,12 +118,12 @@ def testDerivative2(self):
118118
)
119119
expr = Expression(head, Symbol("Global`x"), Symbol("Global`y"))
120120

121-
sfxy = sympy.Function(str(f"{SYMPY_SYMBOL_PREFIX}Global`f"))(
122-
sympy.Symbol(f"{SYMPY_SYMBOL_PREFIX}Global`x"),
123-
sympy.Symbol(f"{SYMPY_SYMBOL_PREFIX}Global`y"),
121+
sfxy = sympy.Function(str(f"{SYMPY_SYMBOL_PREFIX}Global_f"))(
122+
sympy.Symbol(f"{SYMPY_SYMBOL_PREFIX}Global_x"),
123+
sympy.Symbol(f"{SYMPY_SYMBOL_PREFIX}Global_y"),
124124
)
125125
sym_expr = sympy.Derivative(
126-
sfxy, sympy.Symbol(f"{SYMPY_SYMBOL_PREFIX}Global`x")
126+
sfxy, sympy.Symbol(f"{SYMPY_SYMBOL_PREFIX}Global_x")
127127
)
128128

129129
self.compare_to_sympy(expr, sym_expr, **kwargs)
@@ -133,28 +133,28 @@ def testConvertedFunctions(self):
133133
kwargs = {"converted_functions": set(["Global`f"])}
134134

135135
marg1 = Expression(Symbol("Global`f"), Symbol("Global`x"))
136-
sarg1 = sympy.Function(str(f"{SYMPY_SYMBOL_PREFIX}Global`f"))(
137-
sympy.Symbol(f"{SYMPY_SYMBOL_PREFIX}Global`x")
136+
sarg1 = sympy.Function(str(f"{SYMPY_SYMBOL_PREFIX}Global_f"))(
137+
sympy.Symbol(f"{SYMPY_SYMBOL_PREFIX}Global_x")
138138
)
139139
self.compare(marg1, sarg1, **kwargs)
140140

141141
marg2 = Expression(Symbol("Global`f"), Symbol("Global`x"), Symbol("Global`y"))
142-
sarg2 = sympy.Function(str(f"{SYMPY_SYMBOL_PREFIX}Global`f"))(
143-
sympy.Symbol(f"{SYMPY_SYMBOL_PREFIX}Global`x"),
144-
sympy.Symbol(f"{SYMPY_SYMBOL_PREFIX}Global`y"),
142+
sarg2 = sympy.Function(str(f"{SYMPY_SYMBOL_PREFIX}Global_f"))(
143+
sympy.Symbol(f"{SYMPY_SYMBOL_PREFIX}Global_x"),
144+
sympy.Symbol(f"{SYMPY_SYMBOL_PREFIX}Global_y"),
145145
)
146146
self.compare(marg2, sarg2, **kwargs)
147147

148148
self.compare(
149149
Expression(SymbolD, marg2, Symbol("Global`x")),
150-
sympy.Derivative(sarg2, sympy.Symbol(f"{SYMPY_SYMBOL_PREFIX}Global`x")),
150+
sympy.Derivative(sarg2, sympy.Symbol(f"{SYMPY_SYMBOL_PREFIX}Global_x")),
151151
**kwargs,
152152
)
153153

154154
def testExpression(self):
155155
self.compare(
156156
Expression(SymbolSin, Symbol("Global`x")),
157-
sympy.sin(sympy.Symbol(f"{SYMPY_SYMBOL_PREFIX}Global`x")),
157+
sympy.sin(sympy.Symbol(f"{SYMPY_SYMBOL_PREFIX}Global_x")),
158158
)
159159

160160
def testConstant(self):
@@ -164,13 +164,13 @@ def testConstant(self):
164164
def testGamma(self):
165165
self.compare(
166166
Expression(SymbolGamma, Symbol("Global`z")),
167-
sympy.gamma(sympy.Symbol(f"{SYMPY_SYMBOL_PREFIX}Global`z")),
167+
sympy.gamma(sympy.Symbol(f"{SYMPY_SYMBOL_PREFIX}Global_z")),
168168
)
169169
self.compare(
170170
Expression(SymbolGamma, Symbol("Global`z"), Symbol("Global`x")),
171171
sympy.uppergamma(
172-
sympy.Symbol(f"{SYMPY_SYMBOL_PREFIX}Global`z"),
173-
sympy.Symbol(f"{SYMPY_SYMBOL_PREFIX}Global`x"),
172+
sympy.Symbol(f"{SYMPY_SYMBOL_PREFIX}Global_z"),
173+
sympy.Symbol(f"{SYMPY_SYMBOL_PREFIX}Global_x"),
174174
),
175175
)
176176

0 commit comments

Comments
 (0)