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

handling TimeConstrained[] in SymPy evaluation #1160

Merged
merged 7 commits into from
Nov 13, 2024
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 35 additions & 15 deletions mathics/eval/sympy.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,34 +12,47 @@
from mathics.core.convert.sympy import from_sympy, to_numeric_sympy_args


def eval_sympy(self, z, evaluation):
def eval_sympy_unconstrained(self, z, evaluation):
rocky marked this conversation as resolved.
Show resolved Hide resolved
"""
Evaluate expr using `Sympy`
Evaluate an expression converting it to Sympy
and back to Mathics.
"""
sympy_args = to_numeric_sympy_args(z, evaluation)
if self.sympy_name is None:
return
sympy_fn = getattr(sympy, self.sympy_name)
try:
return from_sympy(tracing.run_sympy(sympy_fn, *sympy_args))
except Exception:
return

def evaluate():
sympy_args = to_numeric_sympy_args(z, evaluation)
if self.sympy_name is None:
return
sympy_fn = getattr(sympy, self.sympy_name)
try:
return from_sympy(tracing.run_sympy(sympy_fn, *sympy_args))
except Exception:
return

def eval_sympy_with_timeout(self, z, evaluation):
"""
Evaluate an expression converting it to Sympy,
and back to Mathics.
This version put the evaluation in a thread,
and check each some time if the evaluation
reached a timeout.
"""

if evaluation.timeout is None:
return evaluate()
return eval_sympy_unconstrained(self, z, evaluation)

def _thread_target(request, queue) -> None:
def _thread_target(queue) -> None:
try:
result = evaluate()
result = eval_sympy_unconstrained(self, z, evaluation)
queue.put((True, result))
except BaseException:
exc_info = sys.exc_info()
queue.put((False, exc_info))

queue = Queue(maxsize=1) # stores the result or exception
thread = Thread(target=_thread_target, args=(evaluate, queue))

def evaluate():
rocky marked this conversation as resolved.
Show resolved Hide resolved
return

thread = Thread(target=_thread_target, args=(queue,))
thread.start()
while thread.is_alive():
thread.join(0.001)
Expand All @@ -54,3 +67,10 @@ def _thread_target(request, queue) -> None:
return result
else:
raise result[0].with_traceback(result[1], result[2])


eval_sympy = (
eval_sympy_unconstrained
if sys.platform in ("emscripten",)
else eval_sympy_with_timeout
)