Skip to content

Commit e107dd3

Browse files
committed
Improve/regularize constant andling
* Split off segratage Mathemathical constants to its own file. * Add Settings`$PreferredBackendMethod do indicate which kind of constant is preferred.
1 parent b5b9e25 commit e107dd3

1 file changed

Lines changed: 47 additions & 53 deletions

File tree

mathics/builtin/constants.py

Lines changed: 47 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,13 @@
2121
)
2222
from mathics.core.numbers import get_precision, PrecisionValueError
2323

24+
def mp_constant(fn, d=None):
25+
if d is None:
26+
return getattr(mpmath, fn)()
27+
else:
28+
mpmath.mp.dps = int_d = int(d)
29+
return getattr(mpmath, fn)(prec=int_d)
30+
2431
def mp_convert_constant(obj, **kwargs):
2532
if isinstance(obj, mpmath.ctx_mp_python._constant):
2633
prec = kwargs.get("prec", None)
@@ -29,22 +36,46 @@ def mp_convert_constant(obj, **kwargs):
2936
return sympy.Float(obj)
3037
return obj
3138

39+
def numpy_constant(name, d=None):
40+
return getattr(numpy, name)
3241

33-
def mp_fn(fn, d=None):
34-
if d is None:
35-
return getattr(mpmath, fn)()
36-
else:
37-
mpmath.mp.dps = int_d = int(d)
38-
return getattr(mpmath, fn)(prec=int_d)
42+
def sympy_constant(fn, d=None):
43+
return getattr(sympy, fn).evalf(n=d)
3944

4045
class _Constant_Common(Predefined):
4146

4247
attributes = ("Constant", "ReadProtected")
48+
nargs = 0
4349

4450
def is_constant(self) -> bool:
45-
# free Symbol will be converted to corresponding SymPy symbol
4651
return True
4752

53+
def get_constant(self, precision, evaluation, preference=None):
54+
## print("XXX", self, preference)
55+
if preference is None:
56+
preference = evaluation.parse("Settings`$PreferredBackendMethod").evaluate(evaluation).get_string_value()
57+
# TODO: validate PreferredBackendMethod is in "mpmath", "numpy", "sympy"
58+
try:
59+
d = get_precision(precision, evaluation)
60+
except PrecisionValueError:
61+
d = None
62+
## print("XXX1", self, preference)
63+
64+
if preference == "sympy" and hasattr(self, "sympy_name"):
65+
value = sympy_constant(self.sympy_name, d)
66+
elif preference == "mathmp" and hasattr(self, "mpmath_name"):
67+
value = mp_constant(self.mpmath_name, d)
68+
elif preference == "numpy_name" and hasattr(self, "numpy_name"):
69+
value = numpy_constant(self.numpy_name)
70+
elif hasattr(self, "mpmath_name"):
71+
value = mp_constant(self.mpmath_name, d)
72+
elif hasattr(self, "sympy_name"):
73+
value = sympy_constant(self.sympy_name, d)
74+
elif hasattr(self, "numpy_name"):
75+
value = numpy_constant(self.numpy_name)
76+
return PrecisionReal(value)
77+
78+
4879
class MPMathConstant(_Constant_Common):
4980
"""Representation of a constant in mpmath, e.g. Pi, E, I, etc."""
5081

@@ -59,25 +90,8 @@ def __init__(self, *args, **kwargs):
5990
self.mpmath_name = strip_context(self.get_name()).lower()
6091
self.mathics_to_mpmath[self.__class__.__name__] = self.mpmath_name
6192

62-
def get_constant(self, precision, evaluation, preference="mpmath"):
63-
try:
64-
d = get_precision(precision, evaluation)
65-
except PrecisionValueError:
66-
return
67-
68-
mpmath_name = self.mpmath_name
69-
if d is None:
70-
return MachineReal(mp_fn(mpmath_name))
71-
elif preference == "mpmath":
72-
result = mp_fn(mpmath_name, d)
73-
else:
74-
sympy_fn = self.to_sympy()
75-
result = sympy_fn.n(d)
76-
return PrecisionReal(result)
77-
78-
7993
def to_mpmath(self, args):
80-
if self.mpmath_name is None or len(args) != self.nargs:
94+
if self.mpmath_name is None or len(args) != 0:
8195
return None
8296
return getattr(mpmath, self.mpmath_name)
8397

@@ -97,9 +111,9 @@ def __init__(self, *args, **kwargs):
97111
self.mathics_to_numpy[self.__class__.__name__] = self.numpy_name
98112

99113
def to_numpy(self, args):
100-
if self.numpy_name is None or len(args) != self.nargs:
114+
if self.numpy_name is None or len(args) != 0:
101115
return None
102-
return getattr(numpy, self.numpy_name)
116+
return self.get_constant()
103117

104118

105119
class SympyConstant(_Constant_Common, SympyObject):
@@ -108,28 +122,6 @@ class SympyConstant(_Constant_Common, SympyObject):
108122
# Subclasses should define this.
109123
sympy_name = None
110124

111-
def get_constant(self, precision, evaluation, preference="sympy"):
112-
try:
113-
d = get_precision(precision, evaluation)
114-
except PrecisionValueError:
115-
return
116-
117-
sympy_fn = self.to_sympy()
118-
if d is None:
119-
if hasattr(self, "mpmath_name"):
120-
# Prefer mpmath when precision is not given.
121-
result = mp_fn(self.mpmath_name)
122-
else:
123-
result = sympy_fn()
124-
return MachineReal(result)
125-
126-
if preference == "sympy":
127-
result = sympy_fn_n(d)
128-
elif hasattr(self, "mpmath_name"):
129-
result = mp_fn(self.mpmath_name, d)
130-
131-
return PrecisionReal(result)
132-
133125
def to_sympy(self, expr=None, **kwargs):
134126
if expr is None or expr.is_atom():
135127
result = getattr(sympy, self.sympy_name)
@@ -269,7 +261,7 @@ class E(MPMathConstant, SympyConstant):
269261

270262
def apply_N(self, precision, evaluation):
271263
"N[E, precision_]"
272-
return self.get_constant(precision, evaluation, preference="sympy")
264+
return self.get_constant(precision, evaluation)
273265

274266
class EulerGamma(MPMathConstant, NumpyConstant, SympyConstant):
275267
"""
@@ -291,7 +283,7 @@ class EulerGamma(MPMathConstant, NumpyConstant, SympyConstant):
291283

292284
def apply_N(self, precision, evaluation):
293285
"N[EulerGamma, precision_]"
294-
return self.get_constant(precision, evaluation, preference="sympy")
286+
return self.get_constant(precision, evaluation)
295287

296288

297289
class GoldenRatio(MPMathConstant, SympyConstant):
@@ -312,7 +304,7 @@ class GoldenRatio(MPMathConstant, SympyConstant):
312304

313305
def apply_N(self, precision, evaluation):
314306
"N[GoldenRatio, precision_]"
315-
return self.get_constant(precision, evaluation, preference="sympy")
307+
return self.get_constant(precision, evaluation)
316308

317309

318310
class Indeterminate(SympyConstant):
@@ -361,6 +353,8 @@ class Infinity(SympyConstant):
361353
"""
362354

363355
sympy_name = "oo"
356+
numpy_name = "Inf"
357+
mpmath_name = "inf"
364358
python_equivalent = math.inf
365359

366360
rules = {
@@ -390,4 +384,4 @@ class Pi(MPMathConstant, SympyConstant):
390384

391385
def apply_N(self, precision, evaluation):
392386
"N[Pi, precision_]"
393-
return self.get_constant(precision, evaluation, preference="sympy")
387+
return self.get_constant(precision, evaluation)

0 commit comments

Comments
 (0)