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

Revise MapAt[] part 1 #1238

Merged
merged 3 commits into from
Dec 21, 2024
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
51 changes: 7 additions & 44 deletions mathics/builtin/functional/apply_fns_to_lists.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,16 @@

from typing import Iterable

from mathics.builtin.list.constructing import List
from mathics.core.atoms import Integer, Integer3
from mathics.core.builtin import Builtin, InfixOperator
from mathics.core.convert.expression import to_mathics_list
from mathics.core.evaluation import Evaluation
from mathics.core.exceptions import (
InvalidLevelspecError,
MessageException,
PartRangeError,
)
from mathics.core.exceptions import InvalidLevelspecError, MessageException
from mathics.core.expression import Expression
from mathics.core.list import ListExpression
from mathics.core.symbols import Atom, Symbol, SymbolNull, SymbolTrue
from mathics.core.systemsymbols import SymbolMapThread, SymbolRule
from mathics.core.symbols import Atom, SymbolNull, SymbolTrue
from mathics.core.systemsymbols import SymbolMapThread
from mathics.eval.functional.apply_fns_to_lists import eval_MapAt
from mathics.eval.parts import python_levelspec, walk_levels

# This tells documentation how to sort this module
Expand Down Expand Up @@ -97,7 +93,7 @@ def callback(level):
return Expression(f, *level.elements)

heads = self.get_option(options, "Heads", evaluation) is SymbolTrue
result, depth = walk_levels(expr, start, stop, heads=heads, callback=callback)
result, _ = walk_levels(expr, start, stop, heads=heads, callback=callback)

return result

Expand Down Expand Up @@ -152,7 +148,7 @@ def callback(level):
return Expression(f, level)

heads = self.get_option(options, "Heads", evaluation) is SymbolTrue
result, depth = walk_levels(expr, start, stop, heads=heads, callback=callback)
result, _ = walk_levels(expr, start, stop, heads=heads, callback=callback)

return result

Expand Down Expand Up @@ -202,40 +198,7 @@ class MapAt(Builtin):

def eval(self, f, expr, args, evaluation: Evaluation):
"MapAt[f_, expr_, args_]"

m = len(expr.elements)

def map_at_one(i):
if 1 <= i <= m:
j = i - 1
elif -m <= i <= -1:
j = m + i
else:
raise PartRangeError
replace_element = new_elements[j]
if hasattr(replace_element, "head") and replace_element.head is Symbol(
"System`Rule"
):
new_elements[j] = Expression(
SymbolRule,
replace_element.elements[0],
Expression(f, replace_element.elements[1]),
)
else:
new_elements[j] = Expression(f, replace_element)
return new_elements

a = args.to_python()
if isinstance(a, int):
new_elements = list(expr.elements)
new_elements = map_at_one(a)
return List(*new_elements)
elif isinstance(a, list):
new_elements = list(expr.elements)
for item in a:
if len(item) == 1 and isinstance(item[0], int):
new_elements = map_at_one(item[0])
return List(*new_elements)
return eval_MapAt(f, expr, args, evaluation)


class MapIndexed(Builtin):
Expand Down
23 changes: 12 additions & 11 deletions mathics/builtin/list/eol.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@
from mathics.core.symbols import Atom, Symbol, SymbolNull, SymbolTrue
from mathics.core.systemsymbols import (
SymbolAppend,
SymbolAppendTo,
SymbolByteArray,
SymbolDrop,
SymbolFailed,
SymbolInfinity,
SymbolKey,
Expand All @@ -44,26 +46,26 @@
SymbolSelect,
SymbolSequence,
SymbolSet,
SymbolTake,
)
from mathics.eval.list.eol import (
drop_span_selector,
eval_Part,
parts,
take_span_selector,
)
from mathics.eval.lists import delete_one, delete_rec, list_boxes
from mathics.eval.parts import (
_drop_span_selector,
_take_span_selector,
deletecases_with_levelspec,
parts,
python_levelspec,
set_part,
walk_levels,
walk_parts,
)
from mathics.eval.patterns import Matcher

SymbolAppendTo = Symbol("System`AppendTo")
SymbolDeleteCases = Symbol("System`DeleteCases")
SymbolDrop = Symbol("System`Drop")
SymbolPrepend = Symbol("System`Prepend")
SymbolPrependTo = Symbol("System`PrependTo")
SymbolTake = Symbol("System`Take")


class Append(Builtin):
Expand Down Expand Up @@ -340,7 +342,6 @@ class Delete(Builtin):
# Delete *can* take more than 2 arguments.
"argr": "Delete called with 1 argument; 2 arguments are expected.",
"argt": "Delete called with `1` arguments; 2 arguments are expected.",
"psl": "Position specification `1` in `2` is not a machine-sized integer or a list of machine-sized integers.",
"pkspec": "The expression `1` cannot be used as a part specification. Use `2` instead.",
}
summary_text = "delete elements from a list at given positions"
Expand Down Expand Up @@ -586,7 +587,7 @@ def eval(self, items, seqs, evaluation: Evaluation):

try:
return parts(
items, [_drop_span_selector(seq) for seq in seq_tuple], evaluation
items, [drop_span_selector(seq) for seq in seq_tuple], evaluation
)
except MessageException as e:
e.message(evaluation)
Expand Down Expand Up @@ -1183,7 +1184,7 @@ def eval(self, list, i, evaluation):
return

# Otherwise...
result = walk_parts([list], indices, evaluation)
result = eval_Part([list], indices, evaluation)
if result:
return result

Expand Down Expand Up @@ -1688,7 +1689,7 @@ def eval(self, items, seqs, evaluation):
return

try:
return parts(items, [_take_span_selector(seq) for seq in seqs], evaluation)
return parts(items, [take_span_selector(seq) for seq in seqs], evaluation)
except MessageException as e:
e.message(evaluation)

Expand Down
1 change: 1 addition & 0 deletions mathics/builtin/messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,7 @@ class General(Builtin):
"pspec": (
"Part specification `1` is neither an integer nor " "a list of integer."
),
"psl": "Position specification `1` in `2` is not a machine-sized integer or a list of machine-sized integers.",
"rvalue": "`1` is not a variable with a value, so its value cannot be changed.",
"seqs": "Sequence specification expected, but got `1`.",
"setp": "Part assignment to `1` could not be made",
Expand Down
4 changes: 2 additions & 2 deletions mathics/builtin/numbers/algebra.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,9 @@
SymbolTable,
SymbolTanh,
)
from mathics.eval.list.eol import eval_Part
from mathics.eval.numbers.algebra.simplify import eval_Simplify
from mathics.eval.numbers.numbers import cancel, sympy_factor
from mathics.eval.parts import walk_parts
from mathics.eval.patterns import match


Expand Down Expand Up @@ -868,7 +868,7 @@ def eval_list(self, polys, varlist, evaluation: Evaluation, options: dict):
if dim1 == 1 and order == 0:
arrays[0] = coeff
else:
walk_parts([curr_array], arrayidx, evaluation, coeff)
eval_Part([curr_array], arrayidx, evaluation, coeff)
arrays[order] = curr_array
return ListExpression(*arrays)

Expand Down
4 changes: 2 additions & 2 deletions mathics/builtin/sparse.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
SymbolSparseArray,
SymbolTable,
)
from mathics.eval.parts import walk_parts
from mathics.eval.list.eol import eval_Part


class SparseArray(Builtin):
Expand Down Expand Up @@ -135,7 +135,7 @@ def eval_normal(self, dims, default, data, evaluation: Evaluation):
for item in data.elements:
pos, val = item.elements
if pos.has_form("List", None):
walk_parts([table], pos.elements, evaluation, val)
eval_Part([table], pos.elements, evaluation, val)
return table

def find_dimensions(self, rules, evaluation: Evaluation):
Expand Down
3 changes: 1 addition & 2 deletions mathics/builtin/string/operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@
SymbolStringRiffle,
SymbolStringSplit,
)
from mathics.eval.list.eol import convert_seq, python_seq
from mathics.eval.makeboxes import format_element
from mathics.eval.parts import convert_seq, python_seq
from mathics.eval.strings import eval_StringFind


Expand Down Expand Up @@ -200,7 +200,6 @@ class StringInsert(Builtin):
messages = {
"string": "String expected at position `1` in `2`.",
"ins": "Cannot insert at position `1` in `2`.",
"psl": "Position specification `1` in `2` is not a machine-sized integer or a list of machine-sized integers.",
}

summary_text = "insert a string in a given position"
Expand Down
4 changes: 2 additions & 2 deletions mathics/core/assignment.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
SymbolPattern,
SymbolRuleDelayed,
)
from mathics.eval.parts import walk_parts
from mathics.eval.list.eol import eval_Part


class AssignmentException(Exception):
Expand Down Expand Up @@ -689,7 +689,7 @@ def eval_assign_part(self, lhs, rhs, evaluation, tags, upset):
evaluation.message(self.get_name(), "noval", symbol)
return False
indices = lhs.elements[1:]
return walk_parts([rule.replace], indices, evaluation, rhs)
return eval_Part([rule.replace], indices, evaluation, rhs)


def eval_assign_random_state(self, lhs, rhs, evaluation, tags, upset):
Expand Down
2 changes: 1 addition & 1 deletion mathics/core/subexpression.py
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ def to_expression(self):

def replace(self, new):
"""
Assigns `new` to the subexpression, according to the logic of `mathics.core.walk_parts`
Assigns `new` to the subexpression, according to the logic of `mathics.eval.list.eol.eval_Part`
"""
if (new.has_form("List", None) or new.get_head_name() == "System`List") and len(
new.elements
Expand Down
4 changes: 4 additions & 0 deletions mathics/core/systemsymbols.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
SymbolAlternatives = Symbol("System`Alternatives")
SymbolAnd = Symbol("System`And")
SymbolAppend = Symbol("System`Append")
SymbolAppendTo = Symbol("System`AppendTo")
SymbolApply = Symbol("System`Apply")
SymbolArcCos = Symbol("System`ArcCos")
SymbolArcSin = Symbol("System`ArcSin")
Expand Down Expand Up @@ -80,6 +81,7 @@
SymbolDispatch = Symbol("System`Dispatch")
SymbolDot = Symbol("System`Dot")
SymbolDownValues = Symbol("System`DownValues")
SymbolDrop = Symbol("System`Drop")
SymbolE = Symbol("System`E")
SymbolEdgeForm = Symbol("System`EdgeForm")
SymbolEndOfFile = Symbol("System`EndOfFile")
Expand Down Expand Up @@ -146,6 +148,7 @@
SymbolMachinePrecision = Symbol("System`MachinePrecision")
SymbolMakeBoxes = Symbol("System`MakeBoxes")
SymbolMap = Symbol("System`Map")
SymbolMapAt = Symbol("System`MapAt")
SymbolMapThread = Symbol("System`MapThread")
SymbolMatchQ = Symbol("System`MatchQ")
SymbolMatrixQ = Symbol("System`MatrixQ")
Expand Down Expand Up @@ -266,6 +269,7 @@
SymbolSubsuperscriptBox = Symbol("System`SubsuperscriptBox")
SymbolSuperscriptBox = Symbol("System`SuperscriptBox")
SymbolTable = Symbol("System`Table")
SymbolTake = Symbol("System`Take")
SymbolTan = Symbol("System`Tan")
SymbolTanh = Symbol("System`Tanh")
SymbolTeXForm = Symbol("System`TeXForm")
Expand Down
Empty file.
57 changes: 57 additions & 0 deletions mathics/eval/functional/apply_fns_to_lists.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
"""
Evaluation routines for mathics.builtin.functional.appy_fns_to_lists
"""
from mathics.core.atoms import Integer
from mathics.core.evaluation import Evaluation
from mathics.core.exceptions import PartRangeError
from mathics.core.expression import Expression
from mathics.core.list import ListExpression
from mathics.core.symbols import Symbol
from mathics.core.systemsymbols import SymbolMapAt, SymbolRule


def eval_MapAt(f, expr, args, evaluation: Evaluation):
m = len(expr.elements)
new_elements = list(expr.elements)

def map_at_replace_one(i: int):
if 1 <= i <= m:
j = i - 1
elif -m <= i <= -1:
j = m + i
else:
evaluation.message("MapAt", "partw", ListExpression(Integer(i)), expr)
raise PartRangeError
replace_element = new_elements[j]
if hasattr(replace_element, "head") and replace_element.head is Symbol(
"System`Rule"
):
new_elements[j] = Expression(
SymbolRule,
replace_element.elements[0],
Expression(f, replace_element.elements[1]),
)
else:
new_elements[j] = Expression(f, replace_element)

try:
if isinstance(args, Integer):
map_at_replace_one(args.value)
return ListExpression(*new_elements)
elif isinstance(args, Expression):
for item in args.elements:
# Get value for arg in expr.elemnts
# Replace value
if (
isinstance(item, Expression)
and len(item.elements) == 1
and isinstance(item.elements[0], Integer)
):
map_at_replace_one(item.elements[0].value)
return ListExpression(*new_elements)
else:
evaluation.message(
"MapAt", "psl", args, Expression(SymbolMapAt, f, expr, args)
)
except PartRangeError:
return
Empty file added mathics/eval/list/__init__.py
Empty file.
Loading
Loading