Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

session.parse #858

Merged
merged 11 commits into from
May 27, 2023
6 changes: 5 additions & 1 deletion mathics/builtin/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -799,10 +799,14 @@ def get_operator_display(self) -> Optional[str]:


class Predefined(Builtin):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.symbol = Symbol(self.get_name())

def get_functions(self, prefix="eval", is_pymodule=False) -> List[Callable]:
functions = list(super().get_functions(prefix))
if prefix == "eval" and hasattr(self, "evaluate"):
functions.append((Symbol(self.get_name()), self.evaluate))
functions.append((self.symbol, self.evaluate))
return functions


Expand Down
81 changes: 48 additions & 33 deletions mathics/builtin/numbers/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,19 @@
# This tells documentation how to sort this module
sort_order = "mathics.builtin.mathematical-constants"


import math
from typing import Optional

import mpmath
import numpy
import sympy

from mathics.builtin.base import Builtin, Predefined, SympyObject
from mathics.core.atoms import MachineReal, PrecisionReal
from mathics.core.atoms import NUMERICAL_CONSTANTS, MachineReal, PrecisionReal
from mathics.core.attributes import A_CONSTANT, A_PROTECTED, A_READ_PROTECTED
from mathics.core.element import BaseElement
from mathics.core.evaluation import Evaluation
from mathics.core.number import (
MACHINE_DIGITS,
MAX_MACHINE_NUMBER,
MIN_MACHINE_NUMBER,
PrecisionValueError,
get_precision,
prec,
)
from mathics.core.number import MACHINE_DIGITS, PrecisionValueError, get_precision, prec
from mathics.core.symbols import Atom, Symbol, strip_context
from mathics.core.systemsymbols import SymbolIndeterminate

Expand Down Expand Up @@ -89,28 +83,33 @@ def eval_N(self, precision, evaluation):
def is_constant(self) -> bool:
return True

def get_constant(self, precision, evaluation):
def get_constant(
self,
precision: Optional[BaseElement] = None,
evaluation: Optional[Evaluation] = None,
):
# first, determine the precision
d = None
if precision:
try:
d = get_precision(precision, evaluation)
except PrecisionValueError:
pass
preference = None
if evaluation:
if precision:
try:
d = get_precision(precision, evaluation)
except PrecisionValueError:
pass

preflist = evaluation._preferred_n_method.copy()
while preflist:
pref_method = preflist.pop()
if pref_method in ("numpy", "mpmath", "sympy"):
preference = pref_method
break

if d is None:
d = MACHINE_DIGITS

# If preference not especified, determine it
# from the precision.
preference = None
preflist = evaluation._preferred_n_method.copy()
while preflist:
pref_method = preflist.pop()
if pref_method in ("numpy", "mpmath", "sympy"):
preference = pref_method
break

if preference is None:
if d <= MACHINE_DIGITS:
preference = "numpy"
Expand All @@ -131,10 +130,16 @@ def get_constant(self, precision, evaluation):
preference = "mpmath"
else:
preference = ""

if preference == "numpy":
value = numpy_constant(self.numpy_name)
if d == MACHINE_DIGITS:
return MachineReal(value)
try:
return NUMERICAL_CONSTANTS[self.symbol]
except KeyError:
value = MachineReal(numpy_constant(self.numpy_name))
NUMERICAL_CONSTANTS[self.symbol] = value
return value
value = numpy_constant(self.numpy_name)
if preference == "sympy":
value = sympy_constant(self.sympy_name, d + 2)
if preference == "mpmath":
Expand Down Expand Up @@ -177,13 +182,16 @@ class _NumpyConstant(_Constant_Common):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if self.numpy_name is None:
self.numpy_name = strip_context(self.get_name()).lower()
self.numpy_name = strip_context(self.symbol.name).lower()
self.mathics_to_numpy[self.__class__.__name__] = self.numpy_name
try:
value_float = numpy_constant(self.numpy_name)
except AttributeError:
value_float = self.to_numpy(self.symbol)
NUMERICAL_CONSTANTS[self.symbol] = MachineReal(value_float)

def to_numpy(self, args):
if self.numpy_name is None or len(args) != 0:
return None
return self.get_constant()
return NUMERICAL_CONSTANTS[self.symbol]


class _SympyConstant(_Constant_Common, SympyObject):
Expand Down Expand Up @@ -608,7 +616,7 @@ class MaxMachineNumber(Predefined):
summary_text = "largest normalized positive machine number"

def evaluate(self, evaluation: Evaluation) -> MachineReal:
return MachineReal(MAX_MACHINE_NUMBER)
return NUMERICAL_CONSTANTS[self.symbol]


class MinMachineNumber(Predefined):
Expand All @@ -635,10 +643,10 @@ class MinMachineNumber(Predefined):
summary_text = "smallest normalized positive machine number"

def evaluate(self, evaluation: Evaluation) -> MachineReal:
return MachineReal(MIN_MACHINE_NUMBER)
return NUMERICAL_CONSTANTS[self.symbol]


class Pi(_MPMathConstant, _SympyConstant):
class Pi(_MPMathConstant, _NumpyConstant, _SympyConstant):
"""
<url>
:Pi, \u03c0: https://en.wikipedia.org/wiki/Pi</url> (<url>
Expand Down Expand Up @@ -740,3 +748,10 @@ class Underflow(Builtin):
"Underflow[] * x_Real": "0.",
}
summary_text = "underflow in numeric evaluation"


# Constants that are not numpy constants,
for cls in (Catalan, Degree, Glaisher, GoldenRatio, Khinchin):
instance = cls(expression=False)
val = instance.get_constant()
NUMERICAL_CONSTANTS[instance.symbol] = MachineReal(val.value)
5 changes: 5 additions & 0 deletions mathics/builtin/testing_expressions/numerical_properties.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from mathics.core.expression import Expression
from mathics.core.symbols import BooleanType, SymbolFalse, SymbolTrue
from mathics.core.systemsymbols import SymbolExpandAll, SymbolSimplify
from mathics.eval.arithmetic import test_zero_arithmetic_expr
from mathics.eval.nevaluator import eval_N


Expand Down Expand Up @@ -460,6 +461,10 @@ def eval(self, expr, evaluation):
"%(name)s[expr_]"
from sympy.matrices.utilities import _iszero

# This handles most of the arithmetic cases
if test_zero_arithmetic_expr(expr):
return SymbolTrue

sympy_expr = expr.to_sympy()
result = _iszero(sympy_expr)
if result is None:
Expand Down
10 changes: 10 additions & 0 deletions mathics/core/atoms.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
from mathics.core.number import (
FP_MANTISA_BINARY_DIGITS,
MACHINE_PRECISION_VALUE,
MAX_MACHINE_NUMBER,
MIN_MACHINE_NUMBER,
dps,
min_prec,
prec,
Expand Down Expand Up @@ -946,6 +948,14 @@ def is_zero(self) -> bool:
MATHICS3_COMPLEX_I = Complex(Integer0, Integer1)
MATHICS3_COMPLEX_I_NEG = Complex(Integer0, IntegerM1)

# Numerical constants
# These constants are populated by the `Predefined`
# classes. See `mathics.builtin.numbers.constants`
NUMERICAL_CONSTANTS = {
Symbol("System`$MaxMachineNumber"): MachineReal(MAX_MACHINE_NUMBER),
Symbol("System`$MinMachineNumber"): MachineReal(MIN_MACHINE_NUMBER),
}


class String(Atom, BoxElementMixin):
value: str
Expand Down
4 changes: 3 additions & 1 deletion mathics/core/number.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,9 @@ def _get_float_inf(value, evaluation) -> Optional[float]:
return value.round_to_float(evaluation)


def get_precision(value, evaluation, show_messages=True) -> Optional[float]:
def get_precision(
value: BaseElement, evaluation, show_messages: bool = True
) -> Optional[float]:
"""
Returns the ``float`` in the interval [``$MinPrecision``, ``$MaxPrecision``] closest to ``value``.
If ``value`` does not belongs to that interval, and ``show_messages`` is True, a Message warning is shown.
Expand Down
6 changes: 6 additions & 0 deletions mathics/core/systemsymbols.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

# This list is sorted in alphabetic order.
SymbolAborted = Symbol("System`$Aborted")
SymbolAbs = Symbol("System`Abs")
SymbolAccuracy = Symbol("System`Accuracy")
SymbolAll = Symbol("System`All")
SymbolAlternatives = Symbol("System`Alternatives")
Expand Down Expand Up @@ -84,6 +85,7 @@
SymbolEquivalent = Symbol("System`Equivalent")
SymbolEulerGamma = Symbol("System`EulerGamma")
SymbolExactNumberQ = Symbol("System`ExactNumberQ")
SymbolExp = Symbol("System`Exp")
SymbolExpandAll = Symbol("System`ExpandAll")
SymbolExport = Symbol("System`Export")
SymbolExportString = Symbol("System`ExportString")
Expand All @@ -109,6 +111,7 @@
SymbolHoldForm = Symbol("System`HoldForm")
SymbolHoldPattern = Symbol("System`HoldPattern")
SymbolHue = Symbol("System`Hue")
SymbolI = Symbol("System`I")
SymbolIf = Symbol("System`If")
SymbolIm = Symbol("System`Im")
SymbolImage = Symbol("System`Image")
Expand All @@ -126,6 +129,7 @@
SymbolLess = Symbol("System`Less")
SymbolLessEqual = Symbol("System`LessEqual")
SymbolKey = Symbol("System`Key")
SymbolKhinchin = Symbol("System`Khinchin")
SymbolLetterCharacter = Symbol("System`LetterCharacter")
SymbolLine = Symbol("System`Line")
SymbolLog = Symbol("System`Log")
Expand Down Expand Up @@ -179,6 +183,7 @@
SymbolPi = Symbol("System`Pi")
SymbolPiecewise = Symbol("System`Piecewise")
SymbolPlot = Symbol("System`Plot")
SymbolPlus = Symbol("System`Plus")
SymbolPoint = Symbol("System`Point")
SymbolPower = Symbol("System`Power")
SymbolPolygon = Symbol("System`Polygon")
Expand Down Expand Up @@ -242,6 +247,7 @@
SymbolTan = Symbol("System`Tan")
SymbolTanh = Symbol("System`Tanh")
SymbolTeXForm = Symbol("System`TeXForm")
SymbolTimes = Symbol("System`Times")
SymbolThrow = Symbol("System`Throw")
SymbolThreshold = Symbol("System`Threshold")
SymbolToString = Symbol("System`ToString")
Expand Down
Loading