Skip to content

Commit

Permalink
Add event handler (#1074)
Browse files Browse the repository at this point in the history
Code in support of event tracing debugging. 

Used b y Mathics3 Module pymtathics.debugger in repository
Mathics3/mathics-debugger.
  • Loading branch information
rocky committed Sep 1, 2024
1 parent c300409 commit 10d9e04
Show file tree
Hide file tree
Showing 9 changed files with 178 additions and 39 deletions.
20 changes: 11 additions & 9 deletions mathics/builtin/numbers/calculus.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import numpy as np
import sympy

import mathics.eval.tracing as tracing
from mathics.builtin.scoping import dynamic_scoping
from mathics.core.atoms import (
Atom,
Expand Down Expand Up @@ -529,7 +530,7 @@ def to_sympy(self, expr, **kwargs):
sym_d_args.append(count)

try:
return sympy.Derivative(sym_func, *sym_d_args)
return tracing.run_sympy(sympy.Derivative, sym_func, *sym_d_args)
except ValueError:
return

Expand Down Expand Up @@ -999,6 +1000,7 @@ class Integrate(SympyFunction):
>> N[Integrate[Sin[Exp[-x^2 /2 ]],{x,1,2}]]
= 0.330804
"""

# Reinstate as a unit test or describe why it should be an example and fix.
# >> Integrate[x/Exp[x^2/t], {x, 0, Infinity}]
# = ConditionalExpression[t / 2, Abs[Arg[t]] < Pi / 2]
Expand Down Expand Up @@ -1088,7 +1090,7 @@ def eval(self, f, xs, evaluation: Evaluation, options: dict):
else:
vars.append((x, a, b))
try:
sympy_result = sympy.integrate(f_sympy, *vars)
sympy_result = tracing.run_sympy(sympy.integrate, f_sympy, *vars)
pass
except sympy.PolynomialError:
return
Expand All @@ -1097,7 +1099,7 @@ def eval(self, f, xs, evaluation: Evaluation, options: dict):
return
except NotImplementedError:
# e.g. NotImplementedError: Result depends on the sign of
# -sign(_Mathics_User_j)*sign(_Mathics_User_w)
# -sign(_u`j)*sign(_u`w)
return
if prec is not None and isinstance(sympy_result, sympy.Integral):
# TODO MaxExtraPrecision -> maxn
Expand Down Expand Up @@ -1245,7 +1247,7 @@ def eval(self, expr, x, x0, evaluation: Evaluation, options={}):
return

try:
result = sympy.limit(expr, x, x0, dir_sympy)
result = tracing.run_sympy(sympy.limit, expr, x, x0, dir_sympy)
except sympy.PoleError:
pass
except RuntimeError:
Expand Down Expand Up @@ -1630,7 +1632,7 @@ def eval(self, f, i, evaluation: Evaluation):
evaluation.message("Root", "iidx", i)
return

r = sympy.CRootOf(poly.to_sympy(), idx)
r = tracing.run_sympy(sympy.CRootOf, poly.to_sympy(), idx)
except sympy.PolynomialError:
evaluation.message("Root", "nuni", f)
return
Expand Down Expand Up @@ -1661,7 +1663,7 @@ def to_sympy(self, expr, **kwargs):
if i is None:
return None

return sympy.CRootOf(poly, i)
return tracing.run_sympy(sympy.CRootOf, poly, i)
except Exception:
return None

Expand Down Expand Up @@ -2243,8 +2245,8 @@ def eval(self, eqs, vars, evaluation: Evaluation):
if left is None or right is None:
return
eq = left - right
eq = sympy.together(eq)
eq = sympy.cancel(eq)
eq = tracing.run_sympy(sympy.together, eq)
eq = tracing.run_sympy(sympy.cancel, eq)
sympy_eqs.append(eq)
_, denom = eq.as_numer_denom()
sympy_denoms.append(denom)
Expand Down Expand Up @@ -2302,7 +2304,7 @@ def transform_solution(sol):
if isinstance(sympy_eqs, bool):
result = sympy_eqs
else:
result = sympy.solve(sympy_eqs, vars_sympy)
result = tracing.run_sympy(sympy.solve, sympy_eqs, vars_sympy)
if not isinstance(result, list):
result = [result]
if isinstance(result, list) and len(result) == 1 and result[0] is True:
Expand Down
6 changes: 3 additions & 3 deletions mathics/builtin/specialfns/gamma.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
from mathics.core.number import FP_MANTISA_BINARY_DIGITS, dps, min_prec
from mathics.core.symbols import Symbol, SymbolSequence
from mathics.core.systemsymbols import SymbolAutomatic, SymbolGamma
from mathics.eval.arithmetic import call_mpmath
from mathics.eval.arithmetic import run_mpmath
from mathics.eval.nevaluator import eval_N
from mathics.eval.numerify import numerify

Expand Down Expand Up @@ -110,7 +110,7 @@ def eval_with_z(self, z, a, b, evaluation):
if None in float_args:
return

result = call_mpmath(
result = run_mpmath(
mpmath_function, tuple(float_args), FP_MANTISA_BINARY_DIGITS
)
else:
Expand All @@ -121,7 +121,7 @@ def eval_with_z(self, z, a, b, evaluation):
mpmath_args = [x.to_mpmath() for x in args]
if None in mpmath_args:
return
result = call_mpmath(mpmath_function, tuple(mpmath_args), prec)
result = run_mpmath(mpmath_function, tuple(mpmath_args), prec)
return result


Expand Down
24 changes: 11 additions & 13 deletions mathics/core/builtin.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,22 @@
import os.path as osp
import re
from abc import ABC
from functools import lru_cache, total_ordering
from functools import total_ordering
from itertools import chain
from typing import Any, Callable, Dict, Iterable, List, Optional, Tuple, Union, cast

import mpmath
import pkg_resources
import sympy

# Note: it is important *not* to use:
# from mathics.eval.tracing import run_sympy
# but, instead, import the module, as below, and then
# access ``run_sympy`` using ``tracing.run_sympy.``
#
# This allows us to change where ``tracing.run_sympy`` points to at
# run time.
import mathics.eval.tracing as tracing
from mathics.core.atoms import (
Integer,
Integer0,
Expand Down Expand Up @@ -530,7 +538,7 @@ def eval(self, z, evaluation: Evaluation):
sympy_args = to_numeric_sympy_args(z, evaluation)
sympy_fn = getattr(sympy, self.sympy_name)
try:
return from_sympy(run_sympy(sympy_fn, *sympy_args))
return from_sympy(tracing.run_sympy(sympy_fn, *sympy_args))
except Exception:
return

Expand Down Expand Up @@ -564,7 +572,7 @@ def to_sympy(self, expr, **kwargs):
return None
sympy_function = self.get_sympy_function(elements)
if sympy_function is not None:
return sympy_function(*sympy_args)
return tracing.run_sympy(sympy_function, *sympy_args)
except TypeError:
pass

Expand All @@ -590,7 +598,6 @@ class MPMathFunction(SympyFunction):
mpmath_name = None
nargs = {1}

@lru_cache(maxsize=1024)
def get_mpmath_function(self, args):
if self.mpmath_name is None or len(args) not in self.nargs:
return None
Expand Down Expand Up @@ -1111,15 +1118,6 @@ def test(self, expr) -> bool:
raise NotImplementedError


@lru_cache()
def run_sympy(sympy_fn: Callable, *sympy_args) -> Any:
"""
Wrapper to run a SymPy function with a cache.
TODO: hook into SymPyTracing -> True
"""
return sympy_fn(*sympy_args)


class PatternError(Exception):
def __init__(self, name, tag, *args):
super().__init__()
Expand Down
8 changes: 6 additions & 2 deletions mathics/core/symbols.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,12 @@
# I put this constants here instead of inside `mathics.core.convert.sympy`
# to avoid a circular reference. Maybe they should be in its own module.

sympy_symbol_prefix = "_mu_"
sympy_slot_prefix = "_ms_"
# Prefix used for Sympy variables. We want prefixes to be short to
# keep variable names short. In tracing values, long names makes
# output messy and harder to follow, since it detracts from the
# important information
sympy_symbol_prefix = "_u"
sympy_slot_prefix = "_#"


# FIXME: This is repeated below
Expand Down
2 changes: 1 addition & 1 deletion mathics/doc/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
documentation tests is done elsewhere.
FIXME: This code should be replaced by Sphinx and autodoc.
Things are such a mess, that it is too difficult to contemplate this right now.
Things are such a mess, that it is too difficult to contemplate this right now.
Also there higher-priority flaws that are more more pressing.
In the shorter, we might we move code for extracting printing to a
separate package.
Expand Down
14 changes: 8 additions & 6 deletions mathics/eval/arithmetic.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,15 @@
used just as a last resource.
"""

from functools import lru_cache
from typing import Callable, List, Optional, Tuple

import mpmath
import sympy

# Note: it is important *not* use: from mathics.eval.tracing import run_sympy
# but instead import the module and access below as tracing.run_sympy.
# This allows us change where tracing.run_sympy points at runtime.
import mathics.eval.tracing as tracing
from mathics.core.atoms import (
NUMERICAL_CONSTANTS,
Complex,
Expand Down Expand Up @@ -50,8 +53,7 @@


# This cache might not be used that much.
@lru_cache()
def call_mpmath(
def run_mpmath(
mpmath_function: Callable, mpmath_args: tuple, precision: int
) -> Optional[BaseElement]:
"""
Expand All @@ -63,7 +65,7 @@ def call_mpmath(
"""
with mpmath.workprec(precision):
try:
result_mp = mpmath_function(*mpmath_args)
result_mp = tracing.run_mpmath(mpmath_function, *mpmath_args)
if precision != FP_MANTISA_BINARY_DIGITS:
return from_mpmath(result_mp, precision)
return from_mpmath(result_mp)
Expand Down Expand Up @@ -337,12 +339,12 @@ def eval_mpmath_function(
if None in float_args:
return

return call_mpmath(mpmath_function, tuple(float_args), FP_MANTISA_BINARY_DIGITS)
return run_mpmath(mpmath_function, tuple(float_args), FP_MANTISA_BINARY_DIGITS)
else:
mpmath_args = [x.to_mpmath(prec) for x in args]
if None in mpmath_args:
return
return call_mpmath(mpmath_function, tuple(mpmath_args), prec)
return run_mpmath(mpmath_function, tuple(mpmath_args), prec)


def eval_Plus(*items: BaseElement) -> BaseElement:
Expand Down
25 changes: 25 additions & 0 deletions mathics/eval/numbers/numbers.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@
import mpmath
import sympy

# Note: it is important *not* use: from mathics.eval.tracing import run_sympy
# but instead import the module and access below as tracing.run_sympy.
# This allows us change where tracing.run_sympy points at runtime.
import mathics.eval.tracing as tracing
from mathics.core.atoms import Complex, MachineReal, PrecisionReal
from mathics.core.convert.sympy import from_sympy
from mathics.core.element import BaseElement
Expand Down Expand Up @@ -136,6 +140,27 @@ def cancel(expr):
return expr


def cancel(expr):
if expr.has_form("Plus", None):
return Expression(SymbolPlus, *[cancel(element) for element in expr.elements])
else:
try:
result = expr.to_sympy()
if result is None:
return None

# result = sympy.powsimp(result, deep=True)
result = tracing.run_sympy(sympy.cancel, result)

# cancel factors out rationals, so we factor them again
result = sympy_factor(result)

return from_sympy(result)
except sympy.PolynomialError:
# e.g. for non-commutative expressions
return expr


def sympy_factor(expr_sympy):
try:
result = sympy.together(expr_sympy)
Expand Down
Loading

0 comments on commit 10d9e04

Please sign in to comment.