Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
11 changes: 8 additions & 3 deletions mathics/core/builtin.py
Original file line number Diff line number Diff line change
Expand Up @@ -1209,7 +1209,14 @@ def eval_iter_nostep(self, expr, i, imin, imax, evaluation):
def eval_iter(self, expr, i, imin, imax, di, evaluation):
"%(name)s[expr_, {i_Symbol, imin_, imax_, di_}]"

if isinstance(self, SympyFunction) and di.int_value == 1:
imin = imin.evaluate(evaluation)
imax = imax.evaluate(evaluation)
# With integer bounds the terms are just evaluated and combined below, as
# in Table; SymPy is needed only for symbolic bounds. Going through SymPy
# (summand and result converted there and back, then Together) costs far
# more than the sum itself when the terms are large symbolic expressions.
integer_bounds = isinstance(imin, Integer) and isinstance(imax, Integer)
if isinstance(self, SympyFunction) and di.int_value == 1 and not integer_bounds:
whole_expr = to_expression(
self.get_name(), expr, ListExpression(i, imin, imax)
)
Expand All @@ -1227,8 +1234,6 @@ def eval_iter(self, expr, i, imin, imax, di, evaluation):
return

index = Integer0
imin = imin.evaluate(evaluation)
imax = imax.evaluate(evaluation)
di = di.evaluate(evaluation)

# (imax - imin) / di
Expand Down
29 changes: 28 additions & 1 deletion test/builtin/test_arithmetic.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
Unit tests from mathics.builtin.arithmetic
"""

from test.helper import check_arg_counts
from test.helper import check_arg_counts, check_evaluation

import pytest

Expand Down Expand Up @@ -60,3 +60,30 @@
def test_arithmetic_arg_errors(function_name, msg_fragment):
""" """
check_arg_counts(function_name, msg_fragment)


@pytest.mark.parametrize(
("str_expr", "str_expected", "fail_msg"),
[
("Sum[i, {i, 1, 10}]", "55", None),
("Sum[f[i], {i, 0, 3}]", "f[0] + f[1] + f[2] + f[3]", None),
("Sum[x^i, {i, 0, 3}]", "1 + x + x ^ 2 + x ^ 3", None),
(
"Sum[1/(x + i), {i, 1, 2}]",
"1 / (1 + x) + 1 / (2 + x)",
"With integer bounds the terms are added, not put over a common denominator",
),
("Sum[i, {i, 1, 0}]", "0", "Empty range"),
("Product[x + i, {i, 1, 3}]", "(1 + x) (2 + x) (3 + x)", None),
("Product[i, {i, 1, 0}]", "1", "Empty range"),
(
"Sum[k, {k, 1, n}]",
"n (1 + n) / 2",
"Symbolic bounds still go through SymPy",
),
("Sum[1/k^2, {k, 1, Infinity}]", "Pi ^ 2 / 6", None),
],
)
def test_sum_product_bounds(str_expr, str_expected, fail_msg):
"""Sum and Product with integer and with symbolic bounds"""
check_evaluation(str_expr, str_expected, failure_message=fail_msg)
Loading