Skip to content

Commit

Permalink
Select errors more compliant with WMA
Browse files Browse the repository at this point in the history
Also, broaden infinity tests on counts
  • Loading branch information
rocky committed Dec 5, 2024
1 parent 90f29d9 commit d1a9939
Show file tree
Hide file tree
Showing 11 changed files with 60 additions and 34 deletions.
3 changes: 0 additions & 3 deletions mathics/builtin/atomic/strings.py
Original file line number Diff line number Diff line change
Expand Up @@ -616,9 +616,6 @@ class _StringFind(Builtin, ABC):

messages = {
"srep": "`1` is not a valid string replacement rule.",
"innf": (
"Non-negative integer or Infinity expected at " "position `1` in `2`."
),
}

def _find(py_stri, py_rules, py_n, flags):
Expand Down
38 changes: 27 additions & 11 deletions mathics/builtin/list/eol.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,9 @@
"""

from itertools import chain
from typing import Optional

from mathics.builtin.box.layout import RowBox
from mathics.core.atoms import Integer, Integer0, Integer1, String
from mathics.core.atoms import Integer, Integer0, Integer1, Integer3, Integer4, String
from mathics.core.attributes import (
A_HOLD_FIRST,
A_HOLD_REST,
Expand All @@ -30,7 +29,7 @@
PartError,
PartRangeError,
)
from mathics.core.expression import Expression
from mathics.core.expression import Expression, ExpressionInfinity
from mathics.core.list import ListExpression
from mathics.core.rules import Rule
from mathics.core.symbols import Atom, Symbol, SymbolNull, SymbolTrue
Expand All @@ -42,6 +41,7 @@
SymbolKey,
SymbolMakeBoxes,
SymbolMissing,
SymbolSelect,
SymbolSequence,
SymbolSet,
)
Expand Down Expand Up @@ -437,7 +437,6 @@ class DeleteCases(Builtin):

messages = {
"level": "Level specification `1` is not of the form n, {n}, or {m, n}.",
"innf": "Non-negative integer or Infinity expected at position 4 in `1`",
}
summary_text = "delete all occurrences of a pattern"

Expand All @@ -455,14 +454,15 @@ def eval_ls_n(self, items, pattern, levelspec, n, evaluation):

levelspec = python_levelspec(levelspec)

if n is SymbolInfinity:
if n is SymbolInfinity or ExpressionInfinity == n:
n = -1
elif n.get_head_name() == "System`Integer":
n = n.get_int_value()
elif isinstance(n, Integer):
n = n.value
if n < 0:
evaluation.message(
"DeleteCases",
"innf",
Integer4,
Expression(SymbolDeleteCases, items, pattern, levelspec, n),
)
else:
Expand Down Expand Up @@ -1533,10 +1533,26 @@ class Select(Builtin):
def eval(self, items, expr, evaluation: Evaluation):
"Select[items_, expr_]"

return self.eval_with_n(items, expr, None, evaluation)
return self.eval_with_n(items, expr, SymbolInfinity, evaluation)

def eval_with_n(self, items, expr, n: Optional[Integer], evaluation: Evaluation):
"Select[items_, expr_, n_Integer]"
def eval_with_n(self, items, expr, n, evaluation: Evaluation):
"Select[items_, expr_, n_]"

count_is_valid = True
if n is SymbolInfinity or ExpressionInfinity == n:
count = None
elif isinstance(n, Integer):
count = n.value
if count < 0:
count_is_valid = False
else:
count_is_valid = False

if not count_is_valid:
evaluation.message(
"Select", "innf", Integer3, Expression(SymbolSelect, items, expr, n)
)
return

if isinstance(items, Atom):
evaluation.message("Select", "normal")
Expand All @@ -1546,7 +1562,6 @@ def cond(element):
test = Expression(expr, element)
return test.evaluate(evaluation) is SymbolTrue

count = n.value if n is not None else None
return items.filter(items.head, cond, evaluation, count=count)


Expand Down Expand Up @@ -1633,6 +1648,7 @@ class UpTo(Builtin):
</dl>
"""

# TODO: is there as way we can use general's innf?
messages = {
"innf": "Expected non-negative integer or infinity at position 1 in ``.",
"argx": "UpTo expects 1 argument, `1` arguments were given.",
Expand Down
2 changes: 1 addition & 1 deletion mathics/builtin/messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ class General(Builtin):
"Single or list of non-negative integers expected at " "position `1`."
),
"indet": "Indeterminate expression `1` encountered.",
"innf": "Non-negative integer or Infinity expected at position `1`.",
"innf": "Non-negative integer or Infinity expected at position `1` in `2`",
"int": "Integer expected.",
"intp": "Positive integer expected.",
"intnn": "Non-negative integer expected.",
Expand Down
23 changes: 15 additions & 8 deletions mathics/builtin/patterns/rules.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,16 +69,21 @@

from typing import Optional as OptionalType

from mathics.core.atoms import Integer, Integer0, Integer2, Number
from mathics.core.atoms import Integer, Integer0, Integer2, Integer3, Number
from mathics.core.attributes import A_HOLD_REST, A_PROTECTED, A_SEQUENCE_HOLD
from mathics.core.builtin import AtomBuiltin, Builtin, InfixOperator, PatternError
from mathics.core.element import BaseElement
from mathics.core.evaluation import Evaluation
from mathics.core.exceptions import InvalidLevelspecError
from mathics.core.expression import Expression
from mathics.core.expression import Expression, ExpressionInfinity
from mathics.core.list import ListExpression
from mathics.core.symbols import SymbolTrue
from mathics.core.systemsymbols import SymbolInfinity, SymbolRule, SymbolRuleDelayed
from mathics.core.systemsymbols import (
SymbolInfinity,
SymbolReplaceList,
SymbolRule,
SymbolRuleDelayed,
)
from mathics.eval.rules import (
Dispatch,
create_rules,
Expand Down Expand Up @@ -341,9 +346,6 @@ class ReplaceList(Builtin):
Like in 'ReplaceAll', $rules$ can be a nested list:
>> ReplaceList[{a, b, c}, {{{___, x__, ___} -> {x}}, {{a, b, c} -> t}}, 2]
= {{{a}, {a, b}}, {t}}
>> ReplaceList[expr, {}, -1]
: Non-negative integer or Infinity expected at position 3.
= ReplaceList[expr, {}, -1]
Possible matches for a sum:
>> ReplaceList[a + b + c, x_ + y_ -> {x, y}]
Expand All @@ -369,12 +371,17 @@ def eval(
# default argument, when it is passed explictly, e.g.
# ReplaceList[expr, {}, Infinity], then Infinity
# comes in as DirectedInfinity[1].
if maxidx == SymbolInfinity:
if maxidx == SymbolInfinity or ExpressionInfinity == maxidx:
max_count = None
else:
max_count = maxidx.get_int_value()
if max_count is None or max_count < 0:
evaluation.message("ReplaceList", "innf", 3)
evaluation.message(
"ReplaceList",
"innf",
Integer3,
Expression(SymbolReplaceList, expr, rules, maxidx),
)
return None
try:
rules, ret = create_rules(
Expand Down
8 changes: 4 additions & 4 deletions mathics/builtin/scipy_utils/optimizers.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
from mathics.core.convert.function import expression_to_callable_and_args
from mathics.core.element import BaseElement
from mathics.core.evaluation import Evaluation
from mathics.core.expression import Expression
from mathics.core.systemsymbols import SymbolAutomatic, SymbolFailed, SymbolInfinity
from mathics.core.expression import Expression, ExpressionInfinity
from mathics.core.systemsymbols import SymbolAutomatic, SymbolFailed
from mathics.eval.nevaluator import eval_N

if not check_requires_list(["scipy", "numpy"]):
Expand All @@ -30,7 +30,7 @@ def get_tolerance_and_maxit(opts: dict, scale: float, evaluation: Evaluation):
acc_goal = eval_N(acc_goal, evaluation)
if acc_goal is SymbolAutomatic:
acc_goal = Real(12.0)
elif acc_goal is SymbolInfinity:
elif ExpressionInfinity == acc_goal:
acc_goal = None
elif not isinstance(acc_goal, Number):
acc_goal = None
Expand All @@ -40,7 +40,7 @@ def get_tolerance_and_maxit(opts: dict, scale: float, evaluation: Evaluation):
prec_goal = eval_N(prec_goal, evaluation)
if prec_goal is SymbolAutomatic:
prec_goal = Real(12.0)
elif prec_goal is SymbolInfinity:
elif ExpressionInfinity == prec_goal:
prec_goal = None
elif not isinstance(prec_goal, Number):
prec_goal = None
Expand Down
4 changes: 2 additions & 2 deletions mathics/builtin/string/operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
mathics_split,
to_regex,
)
from mathics.core.atoms import Integer, Integer1, String
from mathics.core.atoms import Integer, Integer1, Integer3, String
from mathics.core.attributes import (
A_FLAT,
A_LISTABLE,
Expand Down Expand Up @@ -437,7 +437,7 @@ def eval_n(self, string, patt, n, evaluation: Evaluation, options: dict):
else:
py_n = n.get_int_value()
if py_n is None or py_n < 0:
evaluation.message("StringPosition", "innf", expr, Integer(3))
evaluation.message("StringPosition", "innf", expr, Integer3)
return

# check options
Expand Down
1 change: 1 addition & 0 deletions mathics/core/atoms.py
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,7 @@ def is_zero(self) -> bool:
Integer1 = Integer(1)
Integer2 = Integer(2)
Integer3 = Integer(3)
Integer4 = Integer(4)
Integer310 = Integer(310)
Integer10 = Integer(10)
IntegerM1 = Integer(-1)
Expand Down
5 changes: 4 additions & 1 deletion mathics/core/expression.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

import sympy

from mathics.core.atoms import Integer, String
from mathics.core.atoms import Integer, Integer1, String
from mathics.core.attributes import (
A_FLAT,
A_HOLD_ALL,
Expand Down Expand Up @@ -2068,3 +2068,6 @@ def convert_expression_elements(

def string_list(head, elements, evaluation):
return atom_list_constructor(evaluation, head, "String")(elements)


ExpressionInfinity = Expression(SymbolDirectedInfinity, Integer1)
2 changes: 2 additions & 0 deletions mathics/core/systemsymbols.py
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@
SymbolRealSign = Symbol("System`RealSign")
SymbolRepeated = Symbol("System`Repeated")
SymbolRepeatedNull = Symbol("System`RepeatedNull")
SymbolReplaceList = Symbol("System`ReplaceList")
SymbolReturn = Symbol("System`Return")
SymbolReverse = Symbol("System`Reverse")
SymbolRight = Symbol("System`Right")
Expand All @@ -225,6 +226,7 @@
SymbolRule = Symbol("System`Rule")
SymbolRuleDelayed = Symbol("System`RuleDelayed")
SymbolSameQ = Symbol("System`SameQ")
SymbolSelect = Symbol("System`Select")
SymbolSequence = Symbol("System`Sequence")
SymbolSeries = Symbol("System`Series")
SymbolSeriesData = Symbol("System`SeriesData")
Expand Down
6 changes: 3 additions & 3 deletions mathics/eval/numbers/calculus/optimizers.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
)
from mathics.core.convert.python import from_python
from mathics.core.evaluation import Evaluation
from mathics.core.expression import Expression
from mathics.core.expression import Expression, ExpressionInfinity
from mathics.core.symbols import BaseElement, SymbolPlus, SymbolTimes, SymbolTrue
from mathics.core.systemsymbols import (
SymbolAutomatic,
Expand Down Expand Up @@ -431,7 +431,7 @@ def to_real_or_none(value) -> Optional[Real]:
value = eval_N(value, evaluation)
if value is SymbolAutomatic:
value = Real(12.0)
elif value is SymbolInfinity:
elif value is SymbolInfinity or ExpressionInfinity == value:
value = None
elif not isinstance(value, Number):
value = None
Expand All @@ -442,7 +442,7 @@ def to_integer_or_none(value) -> Optional[Integer]:
value = eval_N(value, evaluation)
if value is SymbolAutomatic:
value = Integer(100)
elif value is SymbolInfinity:
elif value is SymbolInfinity or ExpressionInfinity == value:
value = None
elif not isinstance(value, Number):
value = None
Expand Down
2 changes: 1 addition & 1 deletion test/builtin/list/test_eol.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,14 +226,14 @@
## Formatting
("a ;; b ;; c", None, "a ;; b ;; c", None),
("a ;; b", None, "a ;; b", None),
# TODO: Rework this test
("{a ;; b ;; c ;; d}", None, "{a ;; b ;; c, 1 ;; d}", ";; association"),
(
"Select[a, True]",
("Nonatomic expression expected.",),
"Select[a, True]",
None,
),
# TODO: Rework this test
("Take[Range[10], {8, 2, -1}]", None, "{8, 7, 6, 5, 4, 3, 2}", None),
("Take[Range[10], {-3, -7, -2}]", None, "{8, 6, 4}", None),
(
Expand Down

0 comments on commit d1a9939

Please sign in to comment.