Skip to content

Evaluation cache #1226

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

Draft
wants to merge 7 commits into
base: master
Choose a base branch
from
Draft
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
22 changes: 15 additions & 7 deletions mathics/builtin/assignment.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ class _SetOperator(object):
def assign_elementary(self, lhs, rhs, evaluation, tags=None, upset=False):
# TODO: This function should be splitted and simplified

evaluation.cache_result = False
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line of code appear many many times. What's the rule, and reason behind when to do and when not to?

I wonder if there's a better way.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, this is just an experiment to see how we can implement the Expression cache.

evaluation.cache_result = False

means that the result of this expression should not be stored in the cache. For example, control expressions, loops and file handling should not be stored in the cache.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok - thanks for the information. I got the gist of that aspect.

Generally one thinks of a cache as just working not something where you have to make 30 hand decisions as to what goes in and what doesn't.

That's what I mean by I wonder if there is a better way. Like using someone else's mechanism like LRUCache. (Hmm, where have I heard this idea before - use someone else's package rather than rolling your own?)

Since this is an experiment let's mark it as a draft for now.

Disclaimer: for now I am rewriting/revising the doc system. Although I would love to ditch that, I also want the docs to get tagged and organized better and using a more standard doc system is too big a lift for me right now.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's what I mean by I wonder if there is a better way. Like using someone else's mechanism like LRUCache. (Hmm, where have I heard this idea before - use someone else's package rather than rolling your own?)

OK, I totally agree: if there is something already implemented, let's use it. The problem here is that I didn't find something like LRUCache that works with expressions. In any case, right now I do not have much time to work on this. I just rebase this in case we want to come back to it in the future.

Since this is an experiment let's mark it as a draft for now.

Disclaimer: for now I am rewriting/revising the doc system. Although I would love to ditch that, I also want the docs to get tagged and organized better and using a more standard doc system is too big a lift for me right now.

I think this is more urgent: to have a clear code and documentation will help to get more help...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's what I mean by I wonder if there is a better way. Like using someone else's mechanism like LRUCache. (Hmm, where have I heard this idea before - use someone else's package rather than rolling your own?)

OK, I totally agree: if there is something already implemented, let's use it. The problem here is that I didn't find something like LRUCache that works with expressions. In any case, right now I do not have much time to work on this. I just rebase this in case we want to come back to it in the future.

Since this is an experiment let's mark it as a draft for now.
Disclaimer: for now I am rewriting/revising the doc system. Although I would love to ditch that, I also want the docs to get tagged and organized better and using a more standard doc system is too big a lift for me right now.

I think this is more urgent: to have a clear code and documentation will help to get more help...

I am working on it and I hope to have the code for Django in place this week. Basically I'm continuing what I started before in on the Mathics side where we are grouping builtins - eventually according to how it appears in Mathematica 5 or listed as "Guides" in the online docs. So far it has been pleasing to see.

After the code to see this on Django is done, on the Core side we can move more stuff around and make it more closely conform to the Mathematica organization.

name = lhs.get_head_name()
lhs._format_cache = None
condition = None
Expand Down Expand Up @@ -547,7 +548,7 @@ class Set(BinaryOperator, _SetOperator):

def apply(self, lhs, rhs, evaluation):
"lhs_ = rhs_"

evaluation.cache_result = False
self.assign(lhs, rhs, evaluation)
return rhs

Expand Down Expand Up @@ -600,7 +601,7 @@ class SetDelayed(Set):

def apply(self, lhs, rhs, evaluation):
"lhs_ := rhs_"

evaluation.cache_result = False
if self.assign(lhs, rhs, evaluation):
return Symbol("Null")
else:
Expand Down Expand Up @@ -648,7 +649,7 @@ class UpSet(BinaryOperator, _SetOperator):

def apply(self, lhs, rhs, evaluation):
"lhs_ ^= rhs_"

evaluation.cache_result = False
self.assign_elementary(lhs, rhs, evaluation, upset=True)
return rhs

Expand Down Expand Up @@ -681,7 +682,7 @@ class UpSetDelayed(UpSet):

def apply(self, lhs, rhs, evaluation):
"lhs_ ^:= rhs_"

evaluation.cache_result = False
if self.assign_elementary(lhs, rhs, evaluation, upset=True):
return Symbol("Null")
else:
Expand Down Expand Up @@ -723,7 +724,7 @@ class TagSet(Builtin, _SetOperator):

def apply(self, f, lhs, rhs, evaluation):
"f_ /: lhs_ = rhs_"

evaluation.cache_result = False
name = f.get_name()
if not name:
evaluation.message(self.get_name(), "sym", f, 1)
Expand All @@ -747,7 +748,7 @@ class TagSetDelayed(TagSet):

def apply(self, f, lhs, rhs, evaluation):
"f_ /: lhs_ := rhs_"

evaluation.cache_result = False
name = f.get_name()
if not name:
evaluation.message(self.get_name(), "sym", f, 1)
Expand Down Expand Up @@ -1240,6 +1241,7 @@ def do_clear(self, definition):

def apply(self, symbols, evaluation):
"%(name)s[symbols___]"
evaluation.cache_result = False
if isinstance(symbols, Symbol):
symbols = [symbols]
elif isinstance(symbols, Expression):
Expand Down Expand Up @@ -1276,6 +1278,8 @@ def apply(self, symbols, evaluation):

def apply_all(self, evaluation):
"Clear[System`All]"
evaluation.cache_result = False
evaluation.cache_expr = {}
evaluation.definitions.set_user_definitions({})
evaluation.definitions.clear_pymathics_modules()
return
Expand Down Expand Up @@ -1315,6 +1319,8 @@ def do_clear(self, definition):

def apply_all(self, evaluation):
"ClearAll[System`All]"
evaluation.cache_result = False
evaluation.cache_expr = {}
evaluation.definitions.set_user_definitions({})
evaluation.definitions.clear_pymathics_modules()
return
Expand Down Expand Up @@ -1403,6 +1409,7 @@ class Unset(PostfixOperator):

def apply(self, expr, evaluation):
"Unset[expr_]"
evaluation.cache_result = False

name = expr.get_head_name()
if name in system_symbols(
Expand Down Expand Up @@ -1659,7 +1666,7 @@ class Messages(Builtin):

def apply(self, symbol, evaluation):
"Messages[symbol_]"

evaluation.cache_result = False
return get_symbol_values(symbol, "Messages", "messages", evaluation)


Expand Down Expand Up @@ -1922,6 +1929,7 @@ class LoadModule(Builtin):

def apply(self, module, evaluation):
"LoadModule[module_String]"
evaluation.cache_result = False
try:
evaluation.definitions.load_pymathics_module(module.value)
except PyMathicsLoadException:
Expand Down
17 changes: 11 additions & 6 deletions mathics/builtin/control.py
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,7 @@ class For(Builtin):

def apply(self, start, test, incr, body, evaluation):
"For[start_, test_, incr_, body_]"
evaluation.cache_result = False
while test.evaluate(evaluation).is_true():
evaluation.check_stopped()
try:
Expand Down Expand Up @@ -382,7 +383,7 @@ class While(Builtin):

def apply(self, test, body, evaluation):
"While[test_, body_]"

evaluation.cache_result = False
while test.evaluate(evaluation).is_true():
try:
evaluation.check_stopped()
Expand Down Expand Up @@ -645,7 +646,7 @@ class Abort(Builtin):

def apply(self, evaluation):
"Abort[]"

evaluation.cache_result = False
raise AbortInterrupt


Expand All @@ -662,7 +663,7 @@ class Interrupt(Builtin):

def apply(self, evaluation):
"Interrupt[]"

evaluation.cache_result = False
raise AbortInterrupt


Expand Down Expand Up @@ -707,7 +708,7 @@ class Return(Builtin):

def apply(self, expr, evaluation):
"Return[expr_]"

evaluation.cache_result = False
raise ReturnInterrupt(expr)


Expand All @@ -729,7 +730,7 @@ class Break(Builtin):

def apply(self, evaluation):
"Break[]"

evaluation.cache_result = False
raise BreakInterrupt


Expand All @@ -753,7 +754,7 @@ class Continue(Builtin):

def apply(self, evaluation):
"Continue[]"

evaluation.cache_result = False
raise ContinueInterrupt


Expand Down Expand Up @@ -790,6 +791,7 @@ class Catch(Builtin):

def apply1(self, expr, evaluation):
"Catch[expr_]"
evaluation.cache_result = False
try:
ret = expr.evaluate(evaluation)
except WLThrowInterrupt as e:
Expand All @@ -798,6 +800,7 @@ def apply1(self, expr, evaluation):

def apply3(self, expr, form, f, evaluation):
"Catch[expr_, form_, f__:Identity]"
evaluation.cache_result = False
try:
ret = expr.evaluate(evaluation)
except WLThrowInterrupt as e:
Expand Down Expand Up @@ -840,8 +843,10 @@ class Throw(Builtin):

def apply1(self, value, evaluation):
"Throw[value_]"
evaluation.cache_result = False
raise WLThrowInterrupt(value)

def apply_with_tag(self, value, tag, evaluation):
"Throw[value_, tag_]"
evaluation.cache_result = False
raise WLThrowInterrupt(value, tag)
14 changes: 9 additions & 5 deletions mathics/builtin/datentime.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ class TimeRemaining(Builtin):

def apply(self, evaluation):
"TimeRemaining[]"
evaluation.cache_result = False
if len(evaluation.timeout_queue) > 0:
t, start_time = evaluation.timeout_queue[-1]
curr_time = datetime.now().timestamp()
Expand Down Expand Up @@ -167,10 +168,12 @@ class TimeConstrained(Builtin):

def apply_2(self, expr, t, evaluation):
"TimeConstrained[expr_, t_]"
evaluation.cache_result = False
return self.apply_3(expr, t, SymbolAborted, evaluation)

def apply_3(self, expr, t, failexpr, evaluation):
"TimeConstrained[expr_, t_, failexpr_]"
evaluation.cache_result = False
t = t.evaluate(evaluation)
if not t.is_numeric():
evaluation.message("TimeConstrained", "timc", t)
Expand Down Expand Up @@ -208,10 +211,10 @@ class Timing(Builtin):

def apply(self, expr, evaluation):
"Timing[expr_]"

start = time.process_time()
result = expr.evaluate(evaluation)
stop = time.process_time()
evaluation.cache_result = False
return Expression("List", Real(stop - start), result)


Expand All @@ -232,7 +235,7 @@ class AbsoluteTiming(Builtin):

def apply(self, expr, evaluation):
"AbsoluteTiming[expr_]"

evaluation.cache_result = False
start = time.time()
result = expr.evaluate(evaluation)
stop = time.time()
Expand Down Expand Up @@ -498,7 +501,6 @@ class DateList(_DateFormat):
def apply(self, epochtime, evaluation):
"%(name)s[epochtime_]"
datelist = self.to_datelist(epochtime, evaluation)

if datelist is None:
return

Expand Down Expand Up @@ -754,7 +756,7 @@ class AbsoluteTime(_DateFormat):

def apply_now(self, evaluation):
"AbsoluteTime[]"

evaluation.cache_result = False
return from_python(total_seconds(datetime.now() - EPOCH_START))

def apply_spec(self, epochtime, evaluation):
Expand Down Expand Up @@ -849,6 +851,7 @@ def apply(self, evaluation):
"TimeUsed[]"
# time.process_time() is better than
# time.clock(). See https://bugs.python.org/issue31803
evaluation.cache_result = False
return Real(time.process_time())


Expand All @@ -865,6 +868,7 @@ class SessionTime(Builtin):

def apply(self, evaluation):
"SessionTime[]"
evaluation.cache_result = False
return Real(time.time() - START_TIME)


Expand All @@ -886,11 +890,11 @@ class Pause(Builtin):

def apply(self, n, evaluation):
"Pause[n_]"
evaluation.cache_result = False
sleeptime = n.to_python()
if not isinstance(sleeptime, (int, float)) or sleeptime < 0:
evaluation.message("Pause", "numnm", Expression("Pause", n))
return

time.sleep(sleeptime)
return Symbol("Null")

Expand Down
2 changes: 2 additions & 0 deletions mathics/builtin/evaluation.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ class RecursionLimit(Predefined):
}

def evaluate(self, evaluation) -> Integer:
evaluation.cache_result = False
return Integer(self.value)


Expand Down Expand Up @@ -138,6 +139,7 @@ class IterationLimit(Predefined):
}

def evaluate(self, evaluation):
evaluation.cache_result = False
return Integer(self.value)


Expand Down
Loading