Skip to content

Commit b6be627

Browse files
committed
doctests -> pytest for layout and optimization
fix maximize/minimize
1 parent 863d8bb commit b6be627

File tree

5 files changed

+92
-41
lines changed

5 files changed

+92
-41
lines changed

mathics/builtin/layout.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -177,12 +177,6 @@ class Infix(Builtin):
177177
178178
>> Infix[{a, b, c}, {"+", "-"}]
179179
= a + b - c
180-
181-
#> Format[r[items___]] := Infix[If[Length[{items}] > 1, {items}, {ab}], "~"]
182-
#> r[1, 2, 3]
183-
= 1 ~ 2 ~ 3
184-
#> r[1]
185-
= ab
186180
"""
187181

188182
messages = {

mathics/builtin/optimization.py

Lines changed: 23 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,6 @@ class Maximize(Builtin):
4646
4747
>> Maximize[-2 x^2 - 3 x + 5, x]
4848
= {{49 / 8, {x -> -3 / 4}}}
49-
50-
#>> Maximize[1 - (x y - 3)^2, {x, y}]
51-
= {{1, {x -> 3, y -> 1}}}
52-
53-
#>> Maximize[{x - 2 y, x^2 + y^2 <= 1}, {x, y}]
54-
= {{Sqrt[5], {x -> Sqrt[5] / 5, y -> -2 Sqrt[5] / 5}}}
5549
"""
5650

5751
attributes = A_PROTECTED | A_READ_PROTECTED
@@ -79,11 +73,12 @@ def eval_constraints(self, f, vars, evaluation: Evaluation):
7973
"Maximize[f_List, vars_]"
8074

8175
constraints = [function for function in f.elements]
82-
constraints[0] = from_sympy(constraints[0].to_sympy() * IntegerM1)
83-
84-
dual_solutions = (
85-
Expression(SymbolMinimize, constraints, vars).evaluate(evaluation).elements
76+
constraints[0] = from_sympy(-(constraints[0].to_sympy()))
77+
constraints = ListExpression(*constraints)
78+
minimize_expr = Expression(SymbolMinimize, constraints, vars).evaluate(
79+
evaluation
8680
)
81+
dual_solutions = minimize_expr.evaluate(evaluation).elements
8782

8883
solutions = []
8984
for dual_solution in dual_solutions:
@@ -107,20 +102,13 @@ class Minimize(Builtin):
107102
108103
>> Minimize[2 x^2 - 3 x + 5, x]
109104
= {{31 / 8, {x -> 3 / 4}}}
110-
111-
#>> Minimize[(x y - 3)^2 + 1, {x, y}]
112-
= {{1, {x -> 3, y -> 1}}}
113-
114-
#>> Minimize[{x - 2 y, x^2 + y^2 <= 1}, {x, y}]
115-
= {{-Sqrt[5], {x -> -Sqrt[5] / 5, y -> 2 Sqrt[5] / 5}}}
116105
"""
117106

118107
attributes = A_PROTECTED | A_READ_PROTECTED
119108
summary_text = "compute the minimum of a function"
120109

121110
def eval_onevariable(self, f, x, evaluation: Evaluation):
122111
"Minimize[f_?NotListQ, x_?NotListQ]"
123-
124112
sympy_x = x.to_sympy()
125113
sympy_f = f.to_sympy()
126114

@@ -129,7 +117,6 @@ def eval_onevariable(self, f, x, evaluation: Evaluation):
129117
candidates = sympy.solve(derivative, sympy_x, real=True, dict=True)
130118

131119
minimum_list = []
132-
133120
for candidate in candidates:
134121
value = second_derivative.subs(candidate)
135122
if value.is_real and value > 0:
@@ -190,7 +177,6 @@ def eval_multiplevariable(self, f, vars, evaluation: Evaluation):
190177
candidates.append(candidate)
191178

192179
minimum_list = []
193-
194180
for candidate in candidates:
195181
eigenvals = hessian.subs(candidate).eigenvals()
196182

@@ -214,14 +200,16 @@ def eval_multiplevariable(self, f, vars, evaluation: Evaluation):
214200
*(
215201
ListExpression(
216202
from_sympy(sympy_f.subs(minimum).simplify()),
217-
[
218-
Expression(
219-
SymbolRule,
220-
from_sympy(list(minimum.keys())[i]),
221-
from_sympy(list(minimum.values())[i]),
203+
ListExpression(
204+
*(
205+
Expression(
206+
SymbolRule,
207+
from_sympy(list(minimum.keys())[i]),
208+
from_sympy(list(minimum.values())[i]),
209+
)
210+
for i in range(len(vars_sympy))
222211
)
223-
for i in range(len(vars_sympy))
224-
],
212+
),
225213
)
226214
for minimum in minimum_list
227215
)
@@ -407,14 +395,16 @@ def eval_constraints(self, f, vars, evaluation: Evaluation):
407395
*(
408396
ListExpression(
409397
from_sympy(objective_function.subs(minimum).simplify()),
410-
[
411-
Expression(
412-
SymbolRule,
413-
from_sympy(list(minimum.keys())[i]),
414-
from_sympy(list(minimum.values())[i]),
398+
ListExpression(
399+
*(
400+
Expression(
401+
SymbolRule,
402+
from_sympy(list(minimum.keys())[i]),
403+
from_sympy(list(minimum.values())[i]),
404+
)
405+
for i in range(len(vars_sympy))
415406
)
416-
for i in range(len(vars_sympy))
417-
],
407+
),
418408
)
419409
for minimum in minimum_list
420410
)

test/builtin/numbers/test_calculus.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,3 +193,36 @@ def test_Solve(str_expr: str, str_expected: str, expected_messages):
193193
str_expected=str_expected,
194194
expected_messages=expected_messages,
195195
)
196+
197+
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+
)

test/builtin/test_strings.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -530,7 +530,6 @@ def test_private_doctests_patterns(str_expr, msgs, str_expected, fail_msg):
530530
"FromCharacterCode[{{97, 98, x}, {100, 101, x}}]",
531531
None,
532532
),
533-
534533
# These tests are commented out due to the bug reported in issue #906
535534
# Octal and hexadecimal notation works alone, but fails
536535
# as a part of another expression. For example,
@@ -561,14 +560,20 @@ def test_private_doctests_characters(str_expr, msgs, str_expected, fail_msg):
561560
expected_messages=msgs,
562561
)
563562

563+
564564
# These tests are separated due to the bug reported in issue #906
565565

566+
566567
@pytest.mark.parametrize(
567568
("str_expr", "str_expected", "fail_msg"),
568569
[
569570
(r"\.78\.79\.7A", "xyz", "variable name using hexadecimal characters"),
570571
(r"\:0078\:0079\:007A", "xyz", "variable name using hexadecimal characters"),
571-
(r"\101\102\103\061\062\063", "ABC123", "variable name using hexadecimal characters"),
572+
(
573+
r"\101\102\103\061\062\063",
574+
"ABC123",
575+
"variable name using hexadecimal characters",
576+
),
572577
],
573578
)
574579
def test_private_doctests_characters(str_expr, str_expected, fail_msg):

test/format/test_format.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -977,3 +977,32 @@ def test_format_private_doctests(str_expr, str_expected, msg):
977977
hold_expected=True,
978978
failure_message=msg,
979979
)
980+
981+
982+
@pytest.mark.parametrize(
983+
("str_expr", "msgs", "str_expected", "fail_msg"),
984+
[
985+
(
986+
(
987+
'Format[r[items___]] := Infix[If[Length[{items}] > 1, {items}, {ab}], "~"];'
988+
"r[1, 2, 3]"
989+
),
990+
None,
991+
"1 ~ 2 ~ 3",
992+
None,
993+
),
994+
("r[1]", None, "ab", None),
995+
(None, None, None, None),
996+
],
997+
)
998+
def test_private_doctests_layout(str_expr, msgs, str_expected, fail_msg):
999+
""" """
1000+
check_evaluation(
1001+
str_expr,
1002+
str_expected,
1003+
to_string_expr=True,
1004+
to_string_expected=True,
1005+
hold_expected=True,
1006+
failure_message=fail_msg,
1007+
expected_messages=msgs,
1008+
)

0 commit comments

Comments
 (0)