Skip to content

Commit dce5300

Browse files
authored
Allow SymPy 1.14 and greater (#1499)
Allow Sympy 1.14 and greater. Also, separate `mathics.builtin.optimization` tests out of calculus testing. See also: Issue #1498.
1 parent 7e2484e commit dce5300

File tree

5 files changed

+84
-56
lines changed

5 files changed

+84
-56
lines changed

mathics/builtin/numbers/calculus.py

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -585,14 +585,18 @@ class DiscreteLimit(Builtin):
585585
def eval(self, f, n, n0, evaluation: Evaluation, options: dict = {}):
586586
"DiscreteLimit[f_, n_->n0_, OptionsPattern[DiscreteLimit]]"
587587

588-
f = f.to_sympy(convert_all_global_functions=True)
589-
n = n.to_sympy()
590-
n0 = n0.to_sympy()
588+
sympy_f = f.to_sympy(convert_all_global_functions=True)
589+
if sympy_f is None:
590+
return None
591591

592-
if n0 != sympy.oo:
593-
return
592+
sympy_n = n.to_sympy()
593+
594+
if sympy_f is None:
595+
return None
594596

595-
if f is None or n is None:
597+
sympy_n0 = n0.to_sympy()
598+
599+
if sympy_n0 != sympy.oo:
596600
return
597601

598602
trials = options["System`Trials"].get_int_value()
@@ -602,9 +606,15 @@ def eval(self, f, n, n0, evaluation: Evaluation, options: dict = {}):
602606
trials = 5
603607

604608
try:
605-
return from_sympy(sympy.limit_seq(f, n, trials))
609+
result = sympy.limit_seq(sympy_f, sympy_n, trials)
606610
except Exception:
607-
pass
611+
return None
612+
613+
# Think about: should we put more tests on result above
614+
# sympy.Limit? The code before this (implicitly) did not.
615+
if isinstance(result, sympy.Limit):
616+
return f.replace_vars({str(n): n0})
617+
return from_sympy(result)
608618

609619

610620
class _BaseFinder(Builtin):

mathics/core/convert/sympy.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,7 @@ def from_sympy_matrix(
343343

344344
def old_from_sympy(expr) -> BaseElement:
345345
"""
346-
converts a SymPy object to a Mathics element.
346+
converts a SymPy object to a Mathics3 element.
347347
"""
348348

349349
if isinstance(expr, (tuple, list)):
@@ -503,7 +503,13 @@ def old_from_sympy(expr) -> BaseElement:
503503
return Expression(SymbolFunction, from_sympy(expr(*variables)))
504504

505505
if expr.is_Function or isinstance(
506-
expr, (sympy.Integral, sympy.Derivative, sympy.Sum, sympy.Product)
506+
expr,
507+
(
508+
sympy.Derivative,
509+
sympy.Integral,
510+
sympy.Product,
511+
sympy.Sum,
512+
),
507513
):
508514
if isinstance(expr, sympy.Integral):
509515
name = "Integral"

pyproject.toml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,7 @@ dependencies = [
3030
"setuptools",
3131
# stopit is needed in TimeRemaining[]
3232
"stopit; platform_system != 'Emscripten'",
33-
# Sympy >= 1.14 is probably okay, but test computations
34-
# change a little
35-
"sympy>=1.13,<1.14",
33+
"sympy>=1.13",
3634
]
3735
license = "GPL-3.0-or-later"
3836
name = "Mathics3"

test/builtin/numbers/test_calculus.py

Lines changed: 10 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -195,39 +195,6 @@ def test_Solve(str_expr: str, str_expected: str, expected_messages):
195195
)
196196

197197

198-
@pytest.mark.parametrize(
199-
("str_expr", "msgs", "str_expected", "fail_msg"),
200-
[
201-
(None, None, None, None),
202-
("Maximize[1 - (x y - 3)^2, {x, y}]", None, "{{1, {x -> 3, y -> 1}}}", None),
203-
(
204-
"Maximize[{x - 2 y, x^2 + y^2 <= 1}, {x, y}]",
205-
None,
206-
"{{Sqrt[5], {x -> Sqrt[5] / 5, y -> -2 Sqrt[5] / 5}}}",
207-
None,
208-
),
209-
("Minimize[(x y - 3)^2 + 1, {x, y}]", None, "{{1, {x -> 3, y -> 1}}}", None),
210-
(
211-
"Minimize[{x - 2 y, x^2 + y^2 <= 1}, {x, y}]",
212-
None,
213-
"{{-Sqrt[5], {x -> -Sqrt[5] / 5, y -> 2 Sqrt[5] / 5}}}",
214-
None,
215-
),
216-
],
217-
)
218-
def test_private_doctests_optimization(str_expr, msgs, str_expected, fail_msg):
219-
""" """
220-
check_evaluation(
221-
str_expr,
222-
str_expected,
223-
to_string_expr=True,
224-
to_string_expected=True,
225-
hold_expected=True,
226-
failure_message=fail_msg,
227-
expected_messages=msgs,
228-
)
229-
230-
231198
@pytest.mark.parametrize(
232199
("str_expr", "msgs", "str_expected", "fail_msg"),
233200
[
@@ -241,8 +208,12 @@ def test_private_doctests_optimization(str_expr, msgs, str_expected, fail_msg):
241208
("D[(#1&)[t],{t,4}]", None, "0", None),
242209
("Attributes[f] ={HoldAll}; Apart[f''[x + x]]", None, "f''[2 x]", None),
243210
("Attributes[f] = {}; Apart[f''[x + x]]", None, "f''[2 x]", None),
244-
## Issue #375
245-
("D[{#^2}, #]", None, "{2 #1}", None),
211+
(
212+
"D[{#^2}, #]",
213+
None,
214+
"{2 #1}",
215+
"Issue #375: avoid slots in rule handling D[{...}",
216+
),
246217
("FindRoot[2.5==x,{x,0}]", None, "{x -> 2.5}", None),
247218
("DownValues[Integrate]", None, "{}", None),
248219
(
@@ -263,12 +234,6 @@ def test_private_doctests_optimization(str_expr, msgs, str_expected, fail_msg):
263234
),
264235
("Integrate[sin[x], x]", None, "Integrate[sin[x], x]", None),
265236
("Integrate[x ^ 3.5 + x, x]", None, "x ^ 2 / 2 + 0.222222 x ^ 4.5", None),
266-
(
267-
"Integrate[1/(x^5+1), x]",
268-
None,
269-
"RootSum[1 + 5 #1 + 25 #1 ^ 2 + 125 #1 ^ 3 + 625 #1 ^ 4&, Log[x + 5 #1] #1&] + Log[1 + x] / 5",
270-
None,
271-
),
272237
("Integrate[ArcTan(x), x]", None, "x ^ 2 ArcTan / 2", None),
273238
("Integrate[E[x], x]", None, "Integrate[E[x], x]", None),
274239
("Integrate[Exp[-(x/2)^2],{x,-Infinity,+Infinity}]", None, "2 Sqrt[Pi]", None),
@@ -288,8 +253,10 @@ def test_private_doctests_optimization(str_expr, msgs, str_expected, fail_msg):
288253
("Derivative[0,0,1][List]", None, "{0, 0, 1}&", None),
289254
],
290255
)
291-
def test_private_doctests_calculus(str_expr, msgs, str_expected, fail_msg):
292-
""" """
256+
def test_calculus(str_expr, msgs, str_expected, fail_msg):
257+
"""
258+
Tests of mathics.builtin.numbers.calculus module.
259+
"""
293260
check_evaluation(
294261
str_expr,
295262
str_expected,

test/builtin/test-optimization.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
"""
2+
Unit tests for mathics.builtins.optimization
3+
4+
In particular:
5+
6+
Maximize[] and Minimize[]
7+
8+
9+
"""
10+
from test.helper import check_evaluation
11+
12+
import pytest
13+
14+
15+
@pytest.mark.parametrize(
16+
("str_expr", "msgs", "str_expected", "fail_msg"),
17+
[
18+
(None, None, None, None),
19+
("Maximize[1 - (x y - 3)^2, {x, y}]", None, "{{1, {x -> 3, y -> 1}}}", None),
20+
(
21+
"Maximize[{x - 2 y, x^2 + y^2 <= 1}, {x, y}]",
22+
None,
23+
"{{Sqrt[5], {x -> Sqrt[5] / 5, y -> -2 Sqrt[5] / 5}}}",
24+
None,
25+
),
26+
("Minimize[(x y - 3)^2 + 1, {x, y}]", None, "{{1, {x -> 3, y -> 1}}}", None),
27+
(
28+
"Minimize[{x - 2 y, x^2 + y^2 <= 1}, {x, y}]",
29+
None,
30+
"{{-Sqrt[5], {x -> -Sqrt[5] / 5, y -> 2 Sqrt[5] / 5}}}",
31+
None,
32+
),
33+
],
34+
)
35+
def test_optimization(str_expr, msgs, str_expected, fail_msg):
36+
"""
37+
Tests of mathics.builtin.optimization.
38+
"""
39+
check_evaluation(
40+
str_expr,
41+
str_expected,
42+
to_string_expr=True,
43+
to_string_expected=True,
44+
hold_expected=True,
45+
failure_message=fail_msg,
46+
expected_messages=msgs,
47+
)

0 commit comments

Comments
 (0)