Skip to content

Commit

Permalink
Expression constants (#831)
Browse files Browse the repository at this point in the history
This comes from #828. Here a new module is added to contain the
expression constants of the form `DirectedInfinity[...]`.
  • Loading branch information
mmatera authored Apr 6, 2023
1 parent 83d78f1 commit 586e5bb
Show file tree
Hide file tree
Showing 12 changed files with 138 additions and 98 deletions.
35 changes: 28 additions & 7 deletions mathics/builtin/arithmetic.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
from mathics.builtin.inference import evaluate_predicate, get_assumptions_list
from mathics.builtin.scoping import dynamic_scoping
from mathics.core.atoms import (
MATHICS3_COMPLEX_I,
MATHICS3_COMPLEX_I_NEG,
Complex,
Integer,
Integer0,
Expand All @@ -43,9 +45,17 @@
)
from mathics.core.convert.expression import to_expression
from mathics.core.convert.sympy import SympyExpression, from_sympy, sympy_symbol_prefix
from mathics.core.element import BaseElement, ElementsProperties
from mathics.core.element import BaseElement
from mathics.core.evaluation import Evaluation
from mathics.core.expression import Expression
from mathics.core.expression_predefined import (
MATHICS3_COMPLEX_INFINITY,
MATHICS3_I_INFINITY,
MATHICS3_I_NEG_INFINITY,
MATHICS3_INFINITY,
MATHICS3_NEG_INFINITY,
PredefinedExpression,
)
from mathics.core.list import ListExpression
from mathics.core.number import dps, min_prec
from mathics.core.symbols import (
Expand Down Expand Up @@ -73,7 +83,13 @@
# This tells documentation how to sort this module
sort_order = "mathics.builtin.mathematical-functions"

ExpressionComplexInfinity = Expression(SymbolDirectedInfinity)

map_direction_infinity = {
Integer1: MATHICS3_INFINITY,
IntegerM1: MATHICS3_NEG_INFINITY,
MATHICS3_COMPLEX_I: MATHICS3_I_INFINITY,
MATHICS3_COMPLEX_I_NEG: MATHICS3_I_NEG_INFINITY,
}


class _MPMathFunction(SympyFunction):
Expand Down Expand Up @@ -647,12 +663,18 @@ class DirectedInfinity(SympyFunction):
"DirectedInfinity[z_?NumericQ]": "HoldForm[z Infinity]",
}

def eval_complex_infinity(self, evaluation: Evaluation):
"""DirectedInfinity[]"""
return MATHICS3_COMPLEX_INFINITY

def eval_directed_infinity(self, direction, evaluation: Evaluation):
"""DirectedInfinity[direction_]"""
if direction in (Integer1, IntegerM1):
return None
result = map_direction_infinity.get(direction, None)
if result:
return result

if direction.is_zero:
return ExpressionComplexInfinity
return MATHICS3_COMPLEX_INFINITY

normalized_direction = eval_Sign(direction)
# TODO: improve eval_Sign, to avoid the need of the
Expand All @@ -677,10 +699,9 @@ def eval_directed_infinity(self, direction, evaluation: Evaluation):

if normalized_direction is None:
return None
return Expression(
return PredefinedExpression(
SymbolDirectedInfinity,
normalized_direction.evaluate(evaluation),
elements_properties=ElementsProperties(True, False, False),
)

def to_sympy(self, expr, **kwargs):
Expand Down
4 changes: 2 additions & 2 deletions mathics/builtin/atomic/strings.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@
from mathics.core.convert.python import from_bool
from mathics.core.evaluation import Evaluation
from mathics.core.expression import Expression
from mathics.core.expression_predefined import MATHICS3_INFINITY
from mathics.core.list import ListExpression
from mathics.core.parser import MathicsFileLineFeeder, parse
from mathics.core.symbols import Symbol, SymbolTrue
from mathics.core.systemsymbols import (
SymbolBlank,
SymbolDirectedInfinity,
SymbolFailed,
SymbolInputForm,
SymbolOutputForm,
Expand Down Expand Up @@ -800,7 +800,7 @@ def convert_rule(r):
# convert n
if n is None:
py_n = 0
elif n == Expression(SymbolDirectedInfinity, Integer1):
elif n.sameQ(MATHICS3_INFINITY):
py_n = 0
else:
py_n = n.get_int_value()
Expand Down
34 changes: 15 additions & 19 deletions mathics/builtin/binary/io.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,16 @@
from mathics.core.convert.expression import to_expression, to_mathics_list
from mathics.core.convert.mpmath import from_mpmath
from mathics.core.expression import Expression
from mathics.core.expression_predefined import (
MATHICS3_I_INFINITY,
MATHICS3_I_NEG_INFINITY,
MATHICS3_INFINITY,
MATHICS3_NEG_INFINITY,
)
from mathics.core.read import SymbolEndOfFile
from mathics.core.streams import stream_manager
from mathics.core.symbols import Symbol
from mathics.core.systemsymbols import (
SymbolComplex,
SymbolDirectedInfinity,
SymbolIndeterminate,
)
from mathics.core.systemsymbols import SymbolIndeterminate
from mathics.eval.nevaluator import eval_N

SymbolBinaryWrite = Symbol("BinaryWrite")
Expand All @@ -38,27 +40,21 @@ def _IEEE_real(real):
if math.isnan(real):
return SymbolIndeterminate
elif math.isinf(real):
return Expression(SymbolDirectedInfinity, Integer((-1) ** (real < 0)))
return MATHICS3_NEG_INFINITY if real < 0 else MATHICS3_INFINITY
else:
return Real(real)

@staticmethod
def _IEEE_cmplx(real, imag):
if math.isnan(real) or math.isnan(imag):
return SymbolIndeterminate
elif math.isinf(real) or math.isinf(imag):
if math.isinf(real) and math.isinf(imag):
if math.isinf(real):
if math.isinf(imag):
return SymbolIndeterminate
return Expression(
SymbolDirectedInfinity,
to_expression(
SymbolComplex,
(-1) ** (real < 0) if math.isinf(real) else 0,
(-1) ** (imag < 0) if math.isinf(imag) else 0,
),
)
else:
return Complex(MachineReal(real), MachineReal(imag))
return MATHICS3_NEG_INFINITY if real < 0 else MATHICS3_INFINITY
if math.isinf(imag):
return MATHICS3_I_NEG_INFINITY if imag < 0 else MATHICS3_I_INFINITY
return Complex(MachineReal(real), MachineReal(imag))

@classmethod
def get_readers(cls):
Expand Down Expand Up @@ -172,7 +168,7 @@ def _Real128_reader(s):
return Real(sympy.Float(0, 4965))
elif expbits == 0x7FFF:
if fracbits == 0:
return Expression(SymbolDirectedInfinity, Integer((-1) ** signbit))
return MATHICS3_NEG_INFINITY if signbit else MATHICS3_INFINITY
else:
return SymbolIndeterminate

Expand Down
6 changes: 3 additions & 3 deletions mathics/builtin/functional/functional_iteration.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
from mathics.core.convert.python import from_python
from mathics.core.evaluation import Evaluation
from mathics.core.expression import Expression
from mathics.core.expression_predefined import MATHICS3_INFINITY
from mathics.core.symbols import Symbol, SymbolTrue
from mathics.core.systemsymbols import SymbolDirectedInfinity

# This tells documentation how to sort this module
sort_order = "mathics.builtin.iteratively-applying-functions"
Expand Down Expand Up @@ -51,7 +51,7 @@ class FixedPoint(Builtin):

def eval(self, f, expr, n, evaluation: Evaluation, options: dict):
"FixedPoint[f_, expr_, n_:DirectedInfinity[1], OptionsPattern[FixedPoint]]"
if n == Expression(SymbolDirectedInfinity, Integer1):
if n.sameQ(MATHICS3_INFINITY):
count = None
else:
count = n.get_int_value()
Expand Down Expand Up @@ -131,7 +131,7 @@ class FixedPointList(Builtin):
def eval(self, f, expr, n, evaluation: Evaluation):
"FixedPointList[f_, expr_, n_:DirectedInfinity[1]]"

if n == Expression(SymbolDirectedInfinity, Integer1):
if n.sameQ(MATHICS3_INFINITY):
count = None
else:
count = n.get_int_value()
Expand Down
12 changes: 4 additions & 8 deletions mathics/builtin/list/rearrange.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,14 @@
from typing import Callable

from mathics.builtin.base import Builtin, MessageException
from mathics.core.atoms import Integer, Integer0, Integer1
from mathics.core.atoms import Integer, Integer0
from mathics.core.attributes import A_FLAT, A_ONE_IDENTITY, A_PROTECTED
from mathics.core.evaluation import Evaluation
from mathics.core.expression import Expression, structure
from mathics.core.expression_predefined import MATHICS3_INFINITY
from mathics.core.list import ListExpression
from mathics.core.symbols import Atom, Symbol, SymbolTrue
from mathics.core.systemsymbols import (
SymbolDirectedInfinity,
SymbolMap,
SymbolReverse,
SymbolSplit,
)
from mathics.core.systemsymbols import SymbolMap, SymbolReverse, SymbolSplit
from mathics.eval.parts import walk_levels


Expand Down Expand Up @@ -813,7 +809,7 @@ def insert_element(elements):
def eval(self, expr, n, h, evaluation):
"Flatten[expr_, n_, h_]"

if n == Expression(SymbolDirectedInfinity, Integer1):
if n.sameQ(MATHICS3_INFINITY):
n = -1 # a negative number indicates an unbounded level
else:
n_int = n.get_int_value()
Expand Down
10 changes: 6 additions & 4 deletions mathics/builtin/numbers/algebra.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@
from mathics.core.element import BaseElement
from mathics.core.evaluation import Evaluation
from mathics.core.expression import Expression
from mathics.core.expression_predefined import (
MATHICS3_COMPLEX_INFINITY,
MATHICS3_NEG_INFINITY,
)
from mathics.core.list import ListExpression
from mathics.core.rules import Pattern
from mathics.core.symbols import (
Expand All @@ -46,12 +50,10 @@
SymbolAlternatives,
SymbolAssumptions,
SymbolAutomatic,
SymbolComplexInfinity,
SymbolCos,
SymbolCosh,
SymbolCot,
SymbolCoth,
SymbolDirectedInfinity,
SymbolEqual,
SymbolIndeterminate,
SymbolLess,
Expand Down Expand Up @@ -1377,7 +1379,7 @@ def eval_novar(self, expr, evaluation):
def eval(self, expr, form, h, evaluation):
"Exponent[expr_, form_, h_]"
if expr == Integer0:
return Expression(SymbolDirectedInfinity, Integer(-1))
return MATHICS3_NEG_INFINITY

if not form.has_form("List", None):
# TODO: add ElementProperties in Expression interface refactor branch:
Expand Down Expand Up @@ -1647,7 +1649,7 @@ def eval_power_of_zero(self, b, evaluation):
if self.eval(Expression(SymbolLess, Integer0, b), evaluation) is SymbolTrue:
return Integer0
if self.eval(Expression(SymbolLess, b, Integer0), evaluation) is SymbolTrue:
return Symbol(SymbolComplexInfinity)
return MATHICS3_COMPLEX_INFINITY
if self.eval(Expression(SymbolEqual, b, Integer0), evaluation) is SymbolTrue:
return Symbol(SymbolIndeterminate)
return Expression(SymbolPower, Integer0, b)
Expand Down
4 changes: 2 additions & 2 deletions mathics/builtin/string/operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@
from mathics.core.convert.python import from_python
from mathics.core.evaluation import Evaluation
from mathics.core.expression import BoxError, Expression, string_list
from mathics.core.expression_predefined import MATHICS3_INFINITY
from mathics.core.list import ListExpression
from mathics.core.symbols import SymbolFalse, SymbolFullForm, SymbolList, SymbolTrue
from mathics.core.systemsymbols import (
SymbolAll,
SymbolDirectedInfinity,
SymbolOutputForm,
SymbolStringInsert,
SymbolStringJoin,
Expand Down Expand Up @@ -521,7 +521,7 @@ def eval(self, string, patt, evaluation: Evaluation, options: dict):
return self.eval_n(
string,
patt,
Expression(SymbolDirectedInfinity, Integer1),
MATHICS3_INFINITY,
evaluation,
options,
)
Expand Down
55 changes: 25 additions & 30 deletions mathics/builtin/testing_expressions/equality_inequality.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,15 @@
)
from mathics.core.convert.expression import to_expression, to_numeric_args
from mathics.core.expression import Expression
from mathics.core.expression_predefined import (
MATHICS3_COMPLEX_INFINITY,
MATHICS3_INFINITY,
MATHICS3_NEG_INFINITY,
)
from mathics.core.number import dps
from mathics.core.symbols import Atom, Symbol, SymbolFalse, SymbolList, SymbolTrue
from mathics.core.systemsymbols import (
SymbolAnd,
SymbolComplexInfinity,
SymbolDirectedInfinity,
SymbolExactNumberQ,
SymbolInequality,
Expand Down Expand Up @@ -110,6 +114,8 @@ def get_pairs(args):
yield (args[i], args[j])

def expr_equal(self, lhs, rhs, max_extra_prec=None) -> Optional[bool]:
if rhs is lhs:
return True
if isinstance(rhs, Expression):
lhs, rhs = rhs, lhs
if not isinstance(lhs, Expression):
Expand All @@ -129,34 +135,23 @@ def expr_equal(self, lhs, rhs, max_extra_prec=None) -> Optional[bool]:
return True

def infty_equal(self, lhs, rhs, max_extra_prec=None) -> Optional[bool]:
if rhs.get_head().sameQ(SymbolDirectedInfinity):
lhs, rhs = rhs, lhs
if not lhs.get_head().sameQ(SymbolDirectedInfinity):
if (
lhs.get_head() is not SymbolDirectedInfinity
or rhs.get_head() is not SymbolDirectedInfinity
):
return None
if rhs.sameQ(SymbolInfinity) or rhs.sameQ(SymbolComplexInfinity):
if len(lhs.elements) == 0:
return True
else:
return self.equal2(
to_expression(SymbolSign, lhs.elements[0]), Integer1, max_extra_prec
)
if rhs.is_numeric():
return False
elif isinstance(rhs, Atom):
lhs_elements, rhs_elements = lhs.elements, rhs.elements

if len(lhs_elements) != len(rhs_elements):
return None
if rhs.get_head().sameQ(lhs.get_head()):
dir1 = dir2 = Integer1
if len(lhs.elements) == 1:
dir1 = lhs.elements[0]
if len(rhs.elements) == 1:
dir2 = rhs.elements[0]
if self.equal2(dir1, dir2, max_extra_prec):
return True
# Now, compare the signs:
dir1_sign = Expression(SymbolSign, dir1)
dir2_sign = Expression(SymbolSign, dir2)
return self.equal2(dir1_sign, dir2_sign, max_extra_prec)
return
# Both are complex infinity?
if len(lhs_elements) == 0:
return True
if len(lhs_elements) == 1:
# Check directions: Notice that they are already normalized...
return self.equal2(lhs_elements[0], rhs_elements[0], max_extra_prec)
# DirectedInfinity with more than two elements cannot be compared here...
return None

def sympy_equal(self, lhs, rhs, max_extra_prec=None) -> Optional[bool]:
try:
Expand Down Expand Up @@ -200,12 +195,12 @@ def equal2(self, lhs: Any, rhs: Any, max_extra_prec=None) -> Optional[bool]:
"""
Two-argument Equal[]
"""
if lhs is rhs or lhs.sameQ(rhs):
return True
if hasattr(lhs, "equal2"):
result = lhs.equal2(rhs)
if result is not None:
return result
elif lhs.sameQ(rhs):
return True
# TODO: Check $Assumptions
# Still we didn't have a result. Try with the following
# tests
Expand Down Expand Up @@ -294,7 +289,7 @@ def eval(self, items, evaluation):
results.append(element)

if not results:
return Expression(SymbolDirectedInfinity, Integer(-self.sense))
return MATHICS3_INFINITY if self.sense < 0 else MATHICS3_NEG_INFINITY
if len(results) == 1:
return results.pop()
if len(results) < len(items):
Expand Down
3 changes: 3 additions & 0 deletions mathics/core/atoms.py
Original file line number Diff line number Diff line change
Expand Up @@ -942,6 +942,9 @@ def is_zero(self) -> bool:


RationalOneHalf = Rational(1, 2)
RationalMinusOneHalf = Rational(-1, 2)
MATHICS3_COMPLEX_I = Complex(Integer0, Integer1)
MATHICS3_COMPLEX_I_NEG = Complex(Integer0, IntegerM1)


class String(Atom, BoxElementMixin):
Expand Down
Loading

0 comments on commit 586e5bb

Please sign in to comment.