From ceecb4b3c0b7bc8cc06455acb0f8398abbbee853 Mon Sep 17 00:00:00 2001 From: mmatera Date: Sun, 4 Apr 2021 11:45:39 -0300 Subject: [PATCH 1/7] adding cache_eval to the Evaluation object --- mathics/core/evaluation.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mathics/core/evaluation.py b/mathics/core/evaluation.py index 15643f443..6b9d817b1 100644 --- a/mathics/core/evaluation.py +++ b/mathics/core/evaluation.py @@ -264,6 +264,8 @@ def __init__( # Necesary to handle OneIdentity on # lhs in assignment self.ignore_oneidentity = False + self.cache_eval = {} + def parse(self, query): "Parse a single expression and print the messages." From 51b4569fd67faec1c9f992ad09976aa4e0b5fe23 Mon Sep 17 00:00:00 2001 From: mmatera Date: Sun, 4 Apr 2021 12:40:20 -0300 Subject: [PATCH 2/7] using evaluation.expr_cache to avoid recalculate --- mathics/core/expression.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/mathics/core/expression.py b/mathics/core/expression.py index ec49c97a2..53253ce02 100644 --- a/mathics/core/expression.py +++ b/mathics/core/expression.py @@ -20,6 +20,12 @@ # Imperical number that seems to work. # We have to be able to match mpmath values with sympy values COMPARE_PREC = 50 +# Expressions that should not be cached +NO_CACHE_EXPR = [ + "System`Return", + "System`Run", + "System`GetEnvironment", +] def fully_qualified_symbol_name(name) -> bool: @@ -1301,6 +1307,21 @@ def evaluate(self, evaluation) -> typing.Union["Expression", "Symbol"]: old_options = evaluation.options evaluation.inc_recursion_depth() + + if self.get_head_name() in NO_CACHE_EXPR: + expr_hash = None + else: + expr_hash = self.hash() + + if expr_hash: + cache_expr_result = evaluation.cache_eval.get(expr_hash, None) + if cache_expr_result is not None: + expr = cache_expr_result[0] + if not expr.has_changed(definitions): + expr = cache_expr_result[1] + if not expr.has_changed(definitions): + return expr + try: while reevaluate: # changed before last evaluated? @@ -1340,6 +1361,8 @@ def evaluate(self, evaluation) -> typing.Union["Expression", "Symbol"]: evaluation.options = old_options evaluation.dec_recursion_depth() + if expr_hash: + evaluation.cache_eval[expr_hash] = (self, expr) return expr def evaluate_next(self, evaluation) -> typing.Tuple["Expression", bool]: From 37ad64dd16179179d50ebaab71953cfeb412e2e2 Mon Sep 17 00:00:00 2001 From: mmatera Date: Sun, 4 Apr 2021 17:34:51 -0300 Subject: [PATCH 3/7] mark symbols that shouldn't be cached --- mathics/builtin/assignment.py | 22 +++++++--- mathics/builtin/control.py | 17 +++++--- mathics/builtin/datentime.py | 14 +++--- mathics/builtin/evaluation.py | 2 + mathics/builtin/files_io/files.py | 54 +++++++++++++++++++++++- mathics/builtin/files_io/importexport.py | 19 ++++++--- mathics/builtin/inout.py | 2 +- mathics/builtin/manipulate.py | 1 + mathics/builtin/numbers/randomnumbers.py | 16 ++++--- mathics/builtin/system.py | 29 +++++++++++++ mathics/core/evaluation.py | 2 + mathics/core/expression.py | 20 ++++++--- 12 files changed, 160 insertions(+), 38 deletions(-) diff --git a/mathics/builtin/assignment.py b/mathics/builtin/assignment.py index 5cd94153e..b6af29319 100644 --- a/mathics/builtin/assignment.py +++ b/mathics/builtin/assignment.py @@ -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 name = lhs.get_head_name() lhs._format_cache = None condition = None @@ -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 @@ -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: @@ -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 @@ -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: @@ -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) @@ -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) @@ -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): @@ -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 @@ -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 @@ -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( @@ -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) @@ -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: diff --git a/mathics/builtin/control.py b/mathics/builtin/control.py index 990d6b6d3..692b0560d 100644 --- a/mathics/builtin/control.py +++ b/mathics/builtin/control.py @@ -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: @@ -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() @@ -645,7 +646,7 @@ class Abort(Builtin): def apply(self, evaluation): "Abort[]" - + evaluation.cache_result = False raise AbortInterrupt @@ -662,7 +663,7 @@ class Interrupt(Builtin): def apply(self, evaluation): "Interrupt[]" - + evaluation.cache_result = False raise AbortInterrupt @@ -707,7 +708,7 @@ class Return(Builtin): def apply(self, expr, evaluation): "Return[expr_]" - + evaluation.cache_result = False raise ReturnInterrupt(expr) @@ -729,7 +730,7 @@ class Break(Builtin): def apply(self, evaluation): "Break[]" - + evaluation.cache_result = False raise BreakInterrupt @@ -753,7 +754,7 @@ class Continue(Builtin): def apply(self, evaluation): "Continue[]" - + evaluation.cache_result = False raise ContinueInterrupt @@ -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: @@ -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: @@ -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) diff --git a/mathics/builtin/datentime.py b/mathics/builtin/datentime.py index c415d7a31..c8d0f4f92 100644 --- a/mathics/builtin/datentime.py +++ b/mathics/builtin/datentime.py @@ -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() @@ -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) @@ -208,7 +211,7 @@ class Timing(Builtin): def apply(self, expr, evaluation): "Timing[expr_]" - + evaluation.cache_result = False start = time.process_time() result = expr.evaluate(evaluation) stop = time.process_time() @@ -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() @@ -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 @@ -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): @@ -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()) @@ -865,6 +868,7 @@ class SessionTime(Builtin): def apply(self, evaluation): "SessionTime[]" + evaluation.cache_result = False return Real(time.time() - START_TIME) @@ -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") diff --git a/mathics/builtin/evaluation.py b/mathics/builtin/evaluation.py index 708698fd4..8d8a07da3 100644 --- a/mathics/builtin/evaluation.py +++ b/mathics/builtin/evaluation.py @@ -78,6 +78,7 @@ class RecursionLimit(Predefined): } def evaluate(self, evaluation) -> Integer: + evaluation.cache_result = False return Integer(self.value) @@ -138,6 +139,7 @@ class IterationLimit(Predefined): } def evaluate(self, evaluation): + evaluation.cache_result = False return Integer(self.value) diff --git a/mathics/builtin/files_io/files.py b/mathics/builtin/files_io/files.py index 7d6bff361..04c6a3f18 100644 --- a/mathics/builtin/files_io/files.py +++ b/mathics/builtin/files_io/files.py @@ -476,7 +476,7 @@ def check_options(self, options): def apply(self, channel, types, evaluation, options): "Read[channel_, types_, OptionsPattern[Read]]" - + evaluation.cache_result = False if channel.has_form("OutputStream", 2): evaluation.message("General", "openw", channel) return @@ -699,6 +699,7 @@ def reader(stream, word_separators, accepted=None): def apply_nostream(self, arg1, arg2, evaluation): "Read[arg1_, arg2_]" + evaluation.cache_result = False evaluation.message("General", "stream", arg1) return @@ -726,6 +727,7 @@ class Write(Builtin): def apply(self, channel, expr, evaluation): "Write[channel_, expr___]" + evaluation.cache_result = False strm = _channel_to_stream(channel) @@ -1314,10 +1316,12 @@ class BinaryWrite(Builtin): def apply_notype(self, name, n, b, evaluation): "BinaryWrite[OutputStream[name_, n_], b_]" + evaluation.cache_result = False return self.apply(name, n, b, None, evaluation) def apply(self, name, n, b, typ, evaluation): "BinaryWrite[OutputStream[name_, n_], b_, typ_]" + evaluation.cache_result = False channel = Expression("OutputStream", name, n) @@ -1679,10 +1683,12 @@ class BinaryRead(Builtin): def apply_empty(self, name, n, evaluation): "BinaryRead[InputStream[name_, n_]]" + evaluation.cache_result = False return self.apply(name, n, None, evaluation) def apply(self, name, n, typ, evaluation): "BinaryRead[InputStream[name_, n_], typ_]" + evaluation.cache_result = False channel = Expression("InputStream", name, n) @@ -1783,6 +1789,7 @@ class WriteString(Builtin): def apply(self, channel, expr, evaluation): "WriteString[channel_, expr___]" + evaluation.cache_result = False strm = _channel_to_stream(channel, "w") if strm is None: @@ -1843,6 +1850,7 @@ class _OpenAction(Builtin): def apply_empty(self, evaluation, options): "%(name)s[OptionsPattern[]]" + evaluation.cache_result = False if isinstance(self, (OpenWrite, OpenAppend)): tmpf = tempfile.NamedTemporaryFile(dir=TMP_DIR) @@ -1855,6 +1863,7 @@ def apply_empty(self, evaluation, options): def apply_path(self, path, evaluation, options): "%(name)s[path_?NotOptionQ, OptionsPattern[]]" + evaluation.cache_result = False # Options # BinaryFormat @@ -2026,6 +2035,7 @@ class Get(PrefixOperator): def apply(self, path, evaluation, options): "Get[path_String, OptionsPattern[Get]]" + evaluation.cache_result = False def check_options(options): # Options @@ -2078,6 +2088,8 @@ def check_options(options): def apply_default(self, filename, evaluation): "Get[filename_]" + evaluation.cache_result = False + expr = Expression("Get", filename) evaluation.message("General", "stream", filename) return expr @@ -2139,6 +2151,8 @@ class Put(BinaryOperator): def apply(self, exprs, filename, evaluation): "Put[exprs___, filename_String]" + evaluation.cache_result = False + instream = Expression("OpenWrite", filename).evaluate(evaluation) if len(instream.leaves) == 2: name, n = instream.leaves @@ -2150,6 +2164,8 @@ def apply(self, exprs, filename, evaluation): def apply_input(self, exprs, name, n, evaluation): "Put[exprs___, OutputStream[name_, n_]]" + evaluation.cache_result = False + stream = stream_manager.lookup_stream(n.get_int_value()) if stream is None or stream.io.closed: @@ -2169,6 +2185,8 @@ def apply_input(self, exprs, name, n, evaluation): def apply_default(self, exprs, filename, evaluation): "Put[exprs___, filename_]" + evaluation.cache_result = False + expr = Expression("Put", exprs, filename) evaluation.message("General", "stream", filename) return expr @@ -2229,6 +2247,8 @@ class PutAppend(BinaryOperator): def apply(self, exprs, filename, evaluation): "PutAppend[exprs___, filename_String]" + evaluation.cache_result = False + instream = Expression("OpenAppend", filename).evaluate(evaluation) if len(instream.leaves) == 2: name, n = instream.leaves @@ -2240,6 +2260,8 @@ def apply(self, exprs, filename, evaluation): def apply_input(self, exprs, name, n, evaluation): "PutAppend[exprs___, OutputStream[name_, n_]]" + evaluation.cache_result = False + stream = stream_manager.lookup_stream(n.get_int_value()) if stream is None or stream.io.closed: @@ -2259,6 +2281,8 @@ def apply_input(self, exprs, name, n, evaluation): def apply_default(self, exprs, filename, evaluation): "PutAppend[exprs___, filename_]" + evaluation.cache_result = False + expr = Expression("PutAppend", exprs, filename) evaluation.message("General", "stream", filename) return expr @@ -2331,6 +2355,7 @@ class ReadList(Read): def apply(self, channel, types, evaluation, options): "ReadList[channel_, types_, OptionsPattern[ReadList]]" + evaluation.cache_result = False # Options # TODO: Implement extra options @@ -2358,6 +2383,7 @@ def apply(self, channel, types, evaluation, options): def apply_m(self, channel, types, m, evaluation, options): "ReadList[channel_, types_, m_, OptionsPattern[ReadList]]" + evaluation.cache_result = False # Options # TODO: Implement extra options @@ -2425,6 +2451,8 @@ class FilePrint(Builtin): def apply(self, path, evaluation, options): "FilePrint[path_ OptionsPattern[FilePrint]]" + evaluation.cache_result = False + pypath = path.to_python() if not ( isinstance(pypath, str) @@ -2507,6 +2535,7 @@ class Close(Builtin): def apply(self, channel, evaluation): "Close[channel_]" + evaluation.cache_result = False if channel.has_form(("InputStream", "OutputStream"), 2): [name, n] = channel.get_leaves() @@ -2544,6 +2573,7 @@ class StreamPosition(Builtin): def apply_input(self, name, n, evaluation): "StreamPosition[InputStream[name_, n_]]" stream = stream_manager.lookup_stream(n.get_int_value()) + evaluation.cache_result = False if stream is None or stream.io is None or stream.io.closed: evaluation.message("General", "openx", name) @@ -2553,10 +2583,14 @@ def apply_input(self, name, n, evaluation): def apply_output(self, name, n, evaluation): "StreamPosition[OutputStream[name_, n_]]" + evaluation.cache_result = False + self.input_apply(name, n, evaluation) def apply_default(self, stream, evaluation): "StreamPosition[stream_]" + evaluation.cache_result = False + evaluation.message("General", "stream", stream) return @@ -2604,6 +2638,8 @@ class SetStreamPosition(Builtin): def apply_input(self, name, n, m, evaluation): "SetStreamPosition[InputStream[name_, n_], m_]" + evaluation.cache_result = False + stream = stream_manager.lookup_stream(n.get_int_value()) if stream is None or stream.io is None or stream.io.closed: @@ -2635,10 +2671,14 @@ def apply_input(self, name, n, m, evaluation): def apply_output(self, name, n, m, evaluation): "SetStreamPosition[OutputStream[name_, n_], m_]" + evaluation.cache_result = False + return self.apply_input(name, n, m, evaluation) def apply_default(self, stream, evaluation): "SetStreamPosition[stream_]" + evaluation.cache_result = False + evaluation.message("General", "stream", stream) return @@ -2691,6 +2731,7 @@ class Skip(Read): def apply(self, name, n, types, m, evaluation, options): "Skip[InputStream[name_, n_], types_, m_, OptionsPattern[Skip]]" + evaluation.cache_result = False channel = Expression("InputStream", name, n) @@ -2754,6 +2795,7 @@ class Find(Read): def apply(self, name, n, text, evaluation, options): "Find[InputStream[name_, n_], text_, OptionsPattern[Find]]" + evaluation.cache_result = False # Options # TODO Implement extra options @@ -2811,6 +2853,8 @@ class InputStream(Builtin): def apply(self, name, n, evaluation): "InputStream[name_, n_]" + evaluation.cache_result = False + return @@ -2831,6 +2875,8 @@ class OutputStream(Builtin): def apply(self, name, n, evaluation): "OutputStream[name_, n_]" + evaluation.cache_result = False + return @@ -2858,6 +2904,8 @@ class StringToStream(Builtin): def apply(self, string, evaluation): "StringToStream[string_]" + evaluation.cache_result = False + pystring = string.to_python()[1:-1] fp = io.StringIO(str(pystring)) @@ -2892,10 +2940,14 @@ class Streams(Builtin): def apply(self, evaluation): "Streams[]" + evaluation.cache_result = False + return self.apply_name(None, evaluation) def apply_name(self, name, evaluation): "Streams[name_String]" + evaluation.cache_result = False + result = [] for stream in stream_manager.STREAMS.values(): if stream is None or stream.io.closed: diff --git a/mathics/builtin/files_io/importexport.py b/mathics/builtin/files_io/importexport.py index 176d34dbd..f34065ffe 100644 --- a/mathics/builtin/files_io/importexport.py +++ b/mathics/builtin/files_io/importexport.py @@ -1092,7 +1092,8 @@ class RegisterImport(Builtin): def apply(self, formatname, function, posts, evaluation, options): """ImportExport`RegisterImport[formatname_String, function_, posts_, - OptionsPattern[ImportExport`RegisterImport]]""" + OptionsPattern[ImportExport`RegisterImport]]""" + evaluation.cache_result = False if function.has_form("List", None): leaves = function.get_leaves() @@ -1174,7 +1175,9 @@ class RegisterExport(Builtin): def apply(self, formatname, function, evaluation, options): """ImportExport`RegisterExport[formatname_String, function_, - OptionsPattern[ImportExport`RegisterExport]]""" + OptionsPattern[ImportExport`RegisterExport]]""" + + evaluation.cache_result = False EXPORTERS[formatname.get_string_value()] = (function, options) return Symbol("Null") @@ -1204,7 +1207,7 @@ def apply(self, url, elements, evaluation, options={}): import tempfile import os - + evaluation.cache_result = False py_url = url.get_string_value() temp_handle, temp_path = tempfile.mkstemp(suffix="") @@ -1329,18 +1332,21 @@ class Import(Builtin): def apply(self, filename, evaluation, options={}): "Import[filename_, OptionsPattern[]]" + evaluation.cache_result = False return self.apply_elements( filename, Expression(SymbolList), evaluation, options ) def apply_element(self, filename, element, evaluation, options={}): "Import[filename_, element_String, OptionsPattern[]]" + evaluation.cache_result = False return self.apply_elements( filename, Expression(SymbolList, element), evaluation, options ) def apply_elements(self, filename, elements, evaluation, options={}): "Import[filename_, elements_List?(AllTrue[#, NotOptionQ]&), OptionsPattern[]]" + evaluation.cache_result = False # Check filename path = filename.to_python() if not (isinstance(path, str) and path[0] == path[-1] == '"'): @@ -1742,7 +1748,7 @@ class Export(Builtin): def apply(self, filename, expr, evaluation, **options): "Export[filename_, expr_, OptionsPattern[Export]]" - + evaluation.cache_result = False # Check filename if not self._check_filename(filename, evaluation): return SymbolFailed @@ -1760,13 +1766,14 @@ def apply(self, filename, expr, evaluation, **options): def apply_element(self, filename, expr, element, evaluation, options={}): "Export[filename_, expr_, element_String, OptionsPattern[]]" + evaluation.cache_result = False return self.apply_elements( filename, expr, Expression(SymbolList, element), evaluation, options ) def apply_elements(self, filename, expr, elems, evaluation, options={}): "Export[filename_, expr_, elems_List?(AllTrue[#, NotOptionQ]&), OptionsPattern[]]" - + evaluation.cache_result = False # Check filename if not self._check_filename(filename, evaluation): return SymbolFailed @@ -2095,7 +2102,7 @@ class FileFormat(Builtin): def apply(self, filename, evaluation): "FileFormat[filename_String]" - + evaluation.cache_result = False findfile = Expression("FindFile", filename).evaluate(evaluation) if findfile == SymbolFailed: evaluation.message( diff --git a/mathics/builtin/inout.py b/mathics/builtin/inout.py index 4ef568e3f..e893a8a7e 100644 --- a/mathics/builtin/inout.py +++ b/mathics/builtin/inout.py @@ -1859,7 +1859,7 @@ class Print(Builtin): def apply(self, expr, evaluation): "Print[expr__]" - + evaluation.cache_result = False expr = expr.get_sequence() expr = Expression("Row", Expression(SymbolList, *expr)) evaluation.print_out(expr) diff --git a/mathics/builtin/manipulate.py b/mathics/builtin/manipulate.py index 5cf8d80da..3bae9cbc7 100755 --- a/mathics/builtin/manipulate.py +++ b/mathics/builtin/manipulate.py @@ -289,6 +289,7 @@ class Manipulate(Builtin): def apply(self, expr, args, evaluation): "Manipulate[expr_, args__]" + evaluation.cache_result = False if (not _jupyter) or (not Kernel.initialized()) or (Kernel.instance() is None): return evaluation.message("Manipulate", "jupyter") diff --git a/mathics/builtin/numbers/randomnumbers.py b/mathics/builtin/numbers/randomnumbers.py index 476730076..53c9a96e8 100644 --- a/mathics/builtin/numbers/randomnumbers.py +++ b/mathics/builtin/numbers/randomnumbers.py @@ -165,7 +165,7 @@ class RandomState(Builtin): def apply(self, evaluation): "$RandomState" - + evaluation.cache_result = False with RandomEnv(evaluation): return Integer(get_random_state()) @@ -213,7 +213,7 @@ class SeedRandom(Builtin): def apply(self, x, evaluation): "SeedRandom[x_]" - + evaluation.cache_result = False if isinstance(x, Integer): value = x.value elif isinstance(x, String): @@ -315,7 +315,7 @@ class RandomInteger(Builtin): def apply(self, rmin, rmax, evaluation): "RandomInteger[{rmin_, rmax_}]" - + evaluation.cache_result = False if not isinstance(rmin, Integer) or not isinstance(rmax, Integer): return evaluation.message( "RandomInteger", "unifr", Expression("List", rmin, rmax) @@ -326,6 +326,7 @@ def apply(self, rmin, rmax, evaluation): def apply_list(self, rmin, rmax, ns, evaluation): "RandomInteger[{rmin_, rmax_}, ns_?ListQ]" + evaluation.cache_result = False if not isinstance(rmin, Integer) or not isinstance(rmax, Integer): return evaluation.message( "RandomInteger", "unifr", Expression("List", rmin, rmax) @@ -392,7 +393,7 @@ class RandomReal(Builtin): def apply(self, xmin, xmax, evaluation): "RandomReal[{xmin_, xmax_}]" - + evaluation.cache_result = False if not ( isinstance(xmin, (Real, Integer)) and isinstance(xmax, (Real, Integer)) ): @@ -414,7 +415,7 @@ def apply_list(self, xmin, xmax, ns, evaluation): return evaluation.message( "RandomReal", "unifr", Expression("List", xmin, xmax) ) - + evaluation.cache_result = False min_value, max_value = xmin.to_python(), xmax.to_python() result = ns.to_python() @@ -497,7 +498,7 @@ def to_complex(value, evaluation): def apply(self, zmin, zmax, evaluation): "RandomComplex[{zmin_, zmax_}]" - + evaluation.cache_result = False min_value, max_value = ( self.to_complex(zmin, evaluation), self.to_complex(zmax, evaluation), @@ -515,7 +516,7 @@ def apply(self, zmin, zmax, evaluation): def apply_list(self, zmin, zmax, ns, evaluation): "RandomComplex[{zmin_, zmax_}, ns_]" expr = Expression("RandomComplex", Expression("List", zmin, zmax), ns) - + evaluation.cache_result = False min_value, max_value = ( self.to_complex(zmin, evaluation), self.to_complex(zmax, evaluation), @@ -556,6 +557,7 @@ class _RandomSelection(_RandomBase): def apply(self, domain, size, evaluation): """%(name)s[domain_, size_]""" + evaluation.cache_result = False if domain.get_head_name() == "System`Rule": # elements and weights err, py_weights = self._weights_to_python(domain.leaves[0], evaluation) if py_weights is None: diff --git a/mathics/builtin/system.py b/mathics/builtin/system.py index 7153ddee8..177778b46 100644 --- a/mathics/builtin/system.py +++ b/mathics/builtin/system.py @@ -360,6 +360,7 @@ class Run(Builtin): def apply(self, command, evaluation): "Run[command_?StringQ]" command_str = command.to_python() + evaluation.cache_result = False return Integer(subprocess.call(command_str, shell=True)) @@ -612,3 +613,31 @@ def apply_1(self, symbol, evaluation) -> Integer: # remplace them by references. # Return the amount of memory recovered. return Integer0 + + +class ClearSystemCache(Builtin): + """ +
+
'ClearSystemCache[]' +
Clears the internal system cache of expressions. +
+ + """ + def apply_clear(self, evaluation): + "ClearSystemCache[]" + evaluation.cache_result = False + evaluation.cache_expr = {} + return + + def apply_clear_symbolic(self, evaluation): + 'ClearSystemCache["Symbolic"]' + evaluation.cache_result = False + evaluation.cache_expr = {} + return + + def apply_clear_numeric(self, evaluation): + 'ClearSystemCache["Numeric"]' + evaluation.cache_result = False + evaluation.cache_expr = {} + return + diff --git a/mathics/core/evaluation.py b/mathics/core/evaluation.py index 6b9d817b1..1696c7c09 100644 --- a/mathics/core/evaluation.py +++ b/mathics/core/evaluation.py @@ -265,6 +265,7 @@ def __init__( # lhs in assignment self.ignore_oneidentity = False self.cache_eval = {} + self.cache_result = False def parse(self, query): @@ -311,6 +312,7 @@ def evaluate(self, query, timeout=None, format=None): self.stopped = False self.exc_result = self.SymbolNull self.last_eval = None + self.cache_result = True if format is None: format = self.format diff --git a/mathics/core/expression.py b/mathics/core/expression.py index 53253ce02..799e21cfe 100644 --- a/mathics/core/expression.py +++ b/mathics/core/expression.py @@ -22,9 +22,17 @@ COMPARE_PREC = 50 # Expressions that should not be cached NO_CACHE_EXPR = [ + "System`Set", + "System`SetDelayed", + "System`TimeRemaining", + "System`Timing", + "System`AbsoluteTiming", + "System`Timing", "System`Return", "System`Run", "System`GetEnvironment", + "System`DateList", + "System`TimeUsed", ] @@ -1307,11 +1315,13 @@ def evaluate(self, evaluation) -> typing.Union["Expression", "Symbol"]: old_options = evaluation.options evaluation.inc_recursion_depth() - - if self.get_head_name() in NO_CACHE_EXPR: - expr_hash = None + # evaluation.cache_result can be set here or from inside the evaluation + # of a branch. Once it is set to false, the result is not cached, + # and hence, not used. + if evaluation.cache_result: + expr_hash = self.__hash__() else: - expr_hash = self.hash() + expr_hash = None if expr_hash: cache_expr_result = evaluation.cache_eval.get(expr_hash, None) @@ -1361,7 +1371,7 @@ def evaluate(self, evaluation) -> typing.Union["Expression", "Symbol"]: evaluation.options = old_options evaluation.dec_recursion_depth() - if expr_hash: + if evaluation.cache_result: evaluation.cache_eval[expr_hash] = (self, expr) return expr From c3cebc23b62e861800b0b95a67ffe7d31252ea56 Mon Sep 17 00:00:00 2001 From: mmatera Date: Sun, 4 Apr 2021 18:21:14 -0300 Subject: [PATCH 4/7] implementing cache at the level of the leaves --- mathics/builtin/lists.py | 2 ++ mathics/core/expression.py | 27 ++++++++++++++++++++++++++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/mathics/builtin/lists.py b/mathics/builtin/lists.py index 3ed247cd4..e06d8c097 100644 --- a/mathics/builtin/lists.py +++ b/mathics/builtin/lists.py @@ -2906,6 +2906,7 @@ class AppendTo(Builtin): def apply(self, s, item, evaluation): "AppendTo[s_, item_]" + evaluation.cache_result = False resolved_s = s.evaluate(evaluation) if s == resolved_s: return evaluation.message("AppendTo", "rvalue", s) @@ -3008,6 +3009,7 @@ class PrependTo(Builtin): def apply(self, s, item, evaluation): "PrependTo[s_, item_]" + evaluation.cache_result = False resolved_s = s.evaluate(evaluation) if s == resolved_s: return evaluation.message("PrependTo", "rvalue", s) diff --git a/mathics/core/expression.py b/mathics/core/expression.py index 799e21cfe..3398b2386 100644 --- a/mathics/core/expression.py +++ b/mathics/core/expression.py @@ -1378,7 +1378,11 @@ def evaluate(self, evaluation) -> typing.Union["Expression", "Symbol"]: def evaluate_next(self, evaluation) -> typing.Tuple["Expression", bool]: from mathics.builtin.base import BoxConstruct + up_cache_result = evaluation.cache_result + cache_result = up_cache_result head = self._head.evaluate(evaluation) + cache_result = cache_result and evaluation.cache_result + evaluation.cache_result = up_cache_result attributes = head.get_attributes(evaluation.definitions) leaves = self.get_mutable_leaves() @@ -1389,7 +1393,11 @@ def rest_range(indices): for index in indices: leaf = leaves[index] if leaf.has_form("Evaluate", 1): + up_cache_result = evaluation.cache_result + cache_result = up_cache_result leaves[index] = leaf.evaluate(evaluation) + cache_result = cache_result and evaluation.cache_result + evaluation.cache_result = up_cache_result def eval_range(indices): for index in indices: @@ -1405,11 +1413,18 @@ def eval_range(indices): elif "System`HoldFirst" in attributes: rest_range(range(0, min(1, len(leaves)))) eval_range(range(1, len(leaves))) + cache_result = cache_result and evaluation.cache_result + evaluation.cache_result = up_cache_result elif "System`HoldRest" in attributes: eval_range(range(0, min(1, len(leaves)))) + cache_result = cache_result and evaluation.cache_result + evaluation.cache_result = up_cache_result rest_range(range(1, len(leaves))) else: eval_range(range(len(leaves))) + cache_result = cache_result and evaluation.cache_result + evaluation.cache_result = up_cache_result + # rest_range(range(0, 0)) new = Expression(head) @@ -1454,6 +1469,7 @@ def flatten_callback(new_leaves, old): if "System`Listable" in attributes: done, threaded = new.thread(evaluation) if done: + evaluation.cache_result = cache_result if threaded.sameQ(new): new._timestamp_cache(evaluation) return new, False @@ -1481,6 +1497,7 @@ def rules(): for rule in rules(): result = rule.apply(new, evaluation, fully=False) if result is not None: + evaluation.cache_result = cache_result if isinstance(result, BoxConstruct): return result, False if result.sameQ(new): @@ -1504,11 +1521,19 @@ def rules(): new.unformatted = self.unformatted new._timestamp_cache(evaluation) + evaluation.cache_result = cache_result return new, False def evaluate_leaves(self, evaluation) -> "Expression": - leaves = [leaf.evaluate(evaluation) for leaf in self._leaves] + up_cache_result = evaluation.cache_result + cache_result = up_cache_result + leaves = [] + for leaf in self._leaves: + leaves.append(leaf.evaluate(evaluation)) + cache_result = cache_result and evaluation.cache_result + evaluation.cache_result = up_cache_result head = self._head.evaluate_leaves(evaluation) + evaluation.cache_result = cache_result and evaluation.cache_result return Expression(head, *leaves) def __str__(self) -> str: From 74ae49912c0e8ae69ba21ddd88b77af72f75225c Mon Sep 17 00:00:00 2001 From: mmatera Date: Sun, 4 Apr 2021 20:27:59 -0300 Subject: [PATCH 5/7] cache_expr to Definitions --- mathics/builtin/datentime.py | 2 +- mathics/builtin/system.py | 6 +++--- mathics/core/definitions.py | 1 + mathics/core/evaluation.py | 5 +++-- mathics/core/expression.py | 14 +++++++------- 5 files changed, 15 insertions(+), 13 deletions(-) diff --git a/mathics/builtin/datentime.py b/mathics/builtin/datentime.py index c8d0f4f92..eb1cc4a00 100644 --- a/mathics/builtin/datentime.py +++ b/mathics/builtin/datentime.py @@ -211,9 +211,9 @@ class Timing(Builtin): def apply(self, expr, evaluation): "Timing[expr_]" - evaluation.cache_result = False start = time.process_time() result = expr.evaluate(evaluation) + evaluation.cache_result = False stop = time.process_time() return Expression("List", Real(stop - start), result) diff --git a/mathics/builtin/system.py b/mathics/builtin/system.py index 177778b46..fbfe39268 100644 --- a/mathics/builtin/system.py +++ b/mathics/builtin/system.py @@ -626,18 +626,18 @@ class ClearSystemCache(Builtin): def apply_clear(self, evaluation): "ClearSystemCache[]" evaluation.cache_result = False - evaluation.cache_expr = {} + evaluation.definitions.cache_eval = {} return def apply_clear_symbolic(self, evaluation): 'ClearSystemCache["Symbolic"]' evaluation.cache_result = False - evaluation.cache_expr = {} + evaluation.definitions.cache_eval = {} return def apply_clear_numeric(self, evaluation): 'ClearSystemCache["Numeric"]' evaluation.cache_result = False - evaluation.cache_expr = {} + evaluation.definitions.cache_eval = {} return diff --git a/mathics/core/definitions.py b/mathics/core/definitions.py index 224db67a5..fcf0085e7 100644 --- a/mathics/core/definitions.py +++ b/mathics/core/definitions.py @@ -84,6 +84,7 @@ def __init__( self.proxy = defaultdict(set) self.now = 0 # increments whenever something is updated self._packages = [] + self.cache_eval = {} if add_builtin: from mathics.builtin import modules, contribute diff --git a/mathics/core/evaluation.py b/mathics/core/evaluation.py index 1696c7c09..c25c13060 100644 --- a/mathics/core/evaluation.py +++ b/mathics/core/evaluation.py @@ -238,7 +238,6 @@ def __init__( ) -> None: from mathics.core.definitions import Definitions from mathics.core.expression import Symbol - if definitions is None: definitions = Definitions() self.definitions = definitions @@ -334,11 +333,13 @@ def evaluate(): self.last_eval = Expression("System`$Pre", query).evaluate(self) else: self.last_eval = query.evaluate(self) - if check_io_hook("System`$Post"): self.last_eval = Expression("System`$Post", self.last_eval).evaluate( self ) + # From there, it is all about format. Do not catch evaluations. + self.cache_result = False + if history_length > 0: if self.predetermined_out is not None: out_result = self.predetermined_out diff --git a/mathics/core/expression.py b/mathics/core/expression.py index 3398b2386..2e3c8defe 100644 --- a/mathics/core/expression.py +++ b/mathics/core/expression.py @@ -1319,12 +1319,12 @@ def evaluate(self, evaluation) -> typing.Union["Expression", "Symbol"]: # of a branch. Once it is set to false, the result is not cached, # and hence, not used. if evaluation.cache_result: - expr_hash = self.__hash__() + expr_hash = str(self.__hash__()) else: expr_hash = None if expr_hash: - cache_expr_result = evaluation.cache_eval.get(expr_hash, None) + cache_expr_result = evaluation.definitions.cache_eval.get(expr_hash, None) if cache_expr_result is not None: expr = cache_expr_result[0] if not expr.has_changed(definitions): @@ -1342,7 +1342,6 @@ def evaluate(self, evaluation) -> typing.Union["Expression", "Symbol"]: if hasattr(expr, "options") and expr.options: evaluation.options = expr.options - expr, reevaluate = expr.evaluate_next(evaluation) if not reevaluate: break @@ -1372,7 +1371,8 @@ def evaluate(self, evaluation) -> typing.Union["Expression", "Symbol"]: evaluation.dec_recursion_depth() if evaluation.cache_result: - evaluation.cache_eval[expr_hash] = (self, expr) + self._timestamp_cache(evaluation) + evaluation.definitions.cache_eval[expr_hash] = (self, expr) return expr def evaluate_next(self, evaluation) -> typing.Tuple["Expression", bool]: @@ -1426,7 +1426,6 @@ def eval_range(indices): evaluation.cache_result = up_cache_result # rest_range(range(0, 0)) - new = Expression(head) new._leaves = tuple(leaves) @@ -1497,7 +1496,7 @@ def rules(): for rule in rules(): result = rule.apply(new, evaluation, fully=False) if result is not None: - evaluation.cache_result = cache_result + evaluation.cache_result = cache_result and evaluation.cache_result if isinstance(result, BoxConstruct): return result, False if result.sameQ(new): @@ -1522,6 +1521,7 @@ def rules(): new.unformatted = self.unformatted new._timestamp_cache(evaluation) evaluation.cache_result = cache_result + return new, False def evaluate_leaves(self, evaluation) -> "Expression": @@ -1531,7 +1531,7 @@ def evaluate_leaves(self, evaluation) -> "Expression": for leaf in self._leaves: leaves.append(leaf.evaluate(evaluation)) cache_result = cache_result and evaluation.cache_result - evaluation.cache_result = up_cache_result + evaluation.cache_result = up_cache_result head = self._head.evaluate_leaves(evaluation) evaluation.cache_result = cache_result and evaluation.cache_result return Expression(head, *leaves) From fbbb55ea8b528b3aa44448838ad598039dd53923 Mon Sep 17 00:00:00 2001 From: mmatera Date: Mon, 5 Apr 2021 09:19:50 -0300 Subject: [PATCH 6/7] do not catch Out and MakeBoxes --- mathics/builtin/assignment.py | 9 +++--- mathics/builtin/datentime.py | 2 +- mathics/builtin/files_io/files.py | 34 ++++++++++----------- mathics/builtin/files_io/importexport.py | 1 + mathics/builtin/system.py | 2 +- mathics/core/evaluation.py | 2 +- mathics/core/expression.py | 39 +++++++++++------------- 7 files changed, 43 insertions(+), 46 deletions(-) diff --git a/mathics/builtin/assignment.py b/mathics/builtin/assignment.py index b6af29319..cc5ea64e4 100644 --- a/mathics/builtin/assignment.py +++ b/mathics/builtin/assignment.py @@ -315,9 +315,8 @@ def assign_elementary(self, lhs, rhs, evaluation, tags=None, upset=False): # $Context = $Context <> "test`" # if new_context.startswith("`"): - new_context = ( - evaluation.definitions.get_current_context() - + new_context.lstrip("`") + new_context = evaluation.definitions.get_current_context() + new_context.lstrip( + "`" ) evaluation.definitions.set_current_context(new_context) @@ -1320,7 +1319,7 @@ def do_clear(self, definition): def apply_all(self, evaluation): "ClearAll[System`All]" evaluation.cache_result = False - evaluation.cache_expr = {} + evaluation.cache_expr = {} evaluation.definitions.set_user_definitions({}) evaluation.definitions.clear_pymathics_modules() return @@ -1929,7 +1928,7 @@ class LoadModule(Builtin): def apply(self, module, evaluation): "LoadModule[module_String]" - evaluation.cache_result = False + evaluation.cache_result = False try: evaluation.definitions.load_pymathics_module(module.value) except PyMathicsLoadException: diff --git a/mathics/builtin/datentime.py b/mathics/builtin/datentime.py index eb1cc4a00..0ab4bc004 100644 --- a/mathics/builtin/datentime.py +++ b/mathics/builtin/datentime.py @@ -213,8 +213,8 @@ def apply(self, expr, evaluation): "Timing[expr_]" start = time.process_time() result = expr.evaluate(evaluation) - evaluation.cache_result = False stop = time.process_time() + evaluation.cache_result = False return Expression("List", Real(stop - start), result) diff --git a/mathics/builtin/files_io/files.py b/mathics/builtin/files_io/files.py index 04c6a3f18..db4fcecde 100644 --- a/mathics/builtin/files_io/files.py +++ b/mathics/builtin/files_io/files.py @@ -2152,7 +2152,7 @@ class Put(BinaryOperator): def apply(self, exprs, filename, evaluation): "Put[exprs___, filename_String]" evaluation.cache_result = False - + instream = Expression("OpenWrite", filename).evaluate(evaluation) if len(instream.leaves) == 2: name, n = instream.leaves @@ -2165,7 +2165,7 @@ def apply(self, exprs, filename, evaluation): def apply_input(self, exprs, name, n, evaluation): "Put[exprs___, OutputStream[name_, n_]]" evaluation.cache_result = False - + stream = stream_manager.lookup_stream(n.get_int_value()) if stream is None or stream.io.closed: @@ -2186,7 +2186,7 @@ def apply_input(self, exprs, name, n, evaluation): def apply_default(self, exprs, filename, evaluation): "Put[exprs___, filename_]" evaluation.cache_result = False - + expr = Expression("Put", exprs, filename) evaluation.message("General", "stream", filename) return expr @@ -2248,7 +2248,7 @@ class PutAppend(BinaryOperator): def apply(self, exprs, filename, evaluation): "PutAppend[exprs___, filename_String]" evaluation.cache_result = False - + instream = Expression("OpenAppend", filename).evaluate(evaluation) if len(instream.leaves) == 2: name, n = instream.leaves @@ -2261,7 +2261,7 @@ def apply(self, exprs, filename, evaluation): def apply_input(self, exprs, name, n, evaluation): "PutAppend[exprs___, OutputStream[name_, n_]]" evaluation.cache_result = False - + stream = stream_manager.lookup_stream(n.get_int_value()) if stream is None or stream.io.closed: @@ -2282,7 +2282,7 @@ def apply_input(self, exprs, name, n, evaluation): def apply_default(self, exprs, filename, evaluation): "PutAppend[exprs___, filename_]" evaluation.cache_result = False - + expr = Expression("PutAppend", exprs, filename) evaluation.message("General", "stream", filename) return expr @@ -2452,7 +2452,7 @@ class FilePrint(Builtin): def apply(self, path, evaluation, options): "FilePrint[path_ OptionsPattern[FilePrint]]" evaluation.cache_result = False - + pypath = path.to_python() if not ( isinstance(pypath, str) @@ -2584,13 +2584,13 @@ def apply_input(self, name, n, evaluation): def apply_output(self, name, n, evaluation): "StreamPosition[OutputStream[name_, n_]]" evaluation.cache_result = False - + self.input_apply(name, n, evaluation) def apply_default(self, stream, evaluation): "StreamPosition[stream_]" evaluation.cache_result = False - + evaluation.message("General", "stream", stream) return @@ -2639,7 +2639,7 @@ class SetStreamPosition(Builtin): def apply_input(self, name, n, m, evaluation): "SetStreamPosition[InputStream[name_, n_], m_]" evaluation.cache_result = False - + stream = stream_manager.lookup_stream(n.get_int_value()) if stream is None or stream.io is None or stream.io.closed: @@ -2672,13 +2672,13 @@ def apply_input(self, name, n, m, evaluation): def apply_output(self, name, n, m, evaluation): "SetStreamPosition[OutputStream[name_, n_], m_]" evaluation.cache_result = False - + return self.apply_input(name, n, m, evaluation) def apply_default(self, stream, evaluation): "SetStreamPosition[stream_]" evaluation.cache_result = False - + evaluation.message("General", "stream", stream) return @@ -2854,7 +2854,7 @@ class InputStream(Builtin): def apply(self, name, n, evaluation): "InputStream[name_, n_]" evaluation.cache_result = False - + return @@ -2876,7 +2876,7 @@ class OutputStream(Builtin): def apply(self, name, n, evaluation): "OutputStream[name_, n_]" evaluation.cache_result = False - + return @@ -2905,7 +2905,7 @@ class StringToStream(Builtin): def apply(self, string, evaluation): "StringToStream[string_]" evaluation.cache_result = False - + pystring = string.to_python()[1:-1] fp = io.StringIO(str(pystring)) @@ -2941,13 +2941,13 @@ class Streams(Builtin): def apply(self, evaluation): "Streams[]" evaluation.cache_result = False - + return self.apply_name(None, evaluation) def apply_name(self, name, evaluation): "Streams[name_String]" evaluation.cache_result = False - + result = [] for stream in stream_manager.STREAMS.values(): if stream is None or stream.io.closed: diff --git a/mathics/builtin/files_io/importexport.py b/mathics/builtin/files_io/importexport.py index f34065ffe..4ac035340 100644 --- a/mathics/builtin/files_io/importexport.py +++ b/mathics/builtin/files_io/importexport.py @@ -1207,6 +1207,7 @@ def apply(self, url, elements, evaluation, options={}): import tempfile import os + evaluation.cache_result = False py_url = url.get_string_value() diff --git a/mathics/builtin/system.py b/mathics/builtin/system.py index fbfe39268..b34ff04e8 100644 --- a/mathics/builtin/system.py +++ b/mathics/builtin/system.py @@ -623,6 +623,7 @@ class ClearSystemCache(Builtin): """ + def apply_clear(self, evaluation): "ClearSystemCache[]" evaluation.cache_result = False @@ -640,4 +641,3 @@ def apply_clear_numeric(self, evaluation): evaluation.cache_result = False evaluation.definitions.cache_eval = {} return - diff --git a/mathics/core/evaluation.py b/mathics/core/evaluation.py index c25c13060..f4c046433 100644 --- a/mathics/core/evaluation.py +++ b/mathics/core/evaluation.py @@ -238,6 +238,7 @@ def __init__( ) -> None: from mathics.core.definitions import Definitions from mathics.core.expression import Symbol + if definitions is None: definitions = Definitions() self.definitions = definitions @@ -266,7 +267,6 @@ def __init__( self.cache_eval = {} self.cache_result = False - def parse(self, query): "Parse a single expression and print the messages." from mathics.core.parser import MathicsSingleLineFeeder diff --git a/mathics/core/expression.py b/mathics/core/expression.py index 2e3c8defe..01f6361cc 100644 --- a/mathics/core/expression.py +++ b/mathics/core/expression.py @@ -144,12 +144,7 @@ def from_python(arg): # return Symbol(arg) elif isinstance(arg, dict): entries = [ - Expression( - "Rule", - from_python(key), - from_python(arg[key]), - ) - for key in arg + Expression("Rule", from_python(key), from_python(arg[key]),) for key in arg ] return Expression(SymbolList, *entries) elif isinstance(arg, BaseExpression): @@ -1318,6 +1313,12 @@ def evaluate(self, evaluation) -> typing.Union["Expression", "Symbol"]: # evaluation.cache_result can be set here or from inside the evaluation # of a branch. Once it is set to false, the result is not cached, # and hence, not used. + if evaluation.cache_result and ( + self.get_head_name() + in ("System`Out", "System`ToBoxes", "System`MakeBoxes",) + ): + evaluation.cache_result = False + if evaluation.cache_result: expr_hash = str(self.__hash__()) else: @@ -1894,21 +1895,17 @@ def thread(self, evaluation, head=None) -> typing.Tuple[bool, "Expression"]: return True, Expression(head, *leaves) def is_numeric(self) -> bool: - return ( - self._head.get_name() - in system_symbols( - "Sqrt", - "Times", - "Plus", - "Subtract", - "Minus", - "Power", - "Abs", - "Divide", - "Sin", - ) - and all(leaf.is_numeric() for leaf in self._leaves) - ) + return self._head.get_name() in system_symbols( + "Sqrt", + "Times", + "Plus", + "Subtract", + "Minus", + "Power", + "Abs", + "Divide", + "Sin", + ) and all(leaf.is_numeric() for leaf in self._leaves) # TODO: complete list of numeric functions, or access NumericFunction # attribute From f3f433cef633af072238bec2fd71668fc83880bc Mon Sep 17 00:00:00 2001 From: autoblack Date: Tue, 29 Jun 2021 22:16:08 +0000 Subject: [PATCH 7/7] fixup: Format Python code with Black --- mathics/builtin/assignment.py | 5 +-- mathics/builtin/files_io/importexport.py | 4 +-- mathics/builtin/system.py | 2 +- mathics/core/expression.py | 39 ++++++++++++++++-------- 4 files changed, 32 insertions(+), 18 deletions(-) diff --git a/mathics/builtin/assignment.py b/mathics/builtin/assignment.py index cc5ea64e4..1cd561e8a 100644 --- a/mathics/builtin/assignment.py +++ b/mathics/builtin/assignment.py @@ -315,8 +315,9 @@ def assign_elementary(self, lhs, rhs, evaluation, tags=None, upset=False): # $Context = $Context <> "test`" # if new_context.startswith("`"): - new_context = evaluation.definitions.get_current_context() + new_context.lstrip( - "`" + new_context = ( + evaluation.definitions.get_current_context() + + new_context.lstrip("`") ) evaluation.definitions.set_current_context(new_context) diff --git a/mathics/builtin/files_io/importexport.py b/mathics/builtin/files_io/importexport.py index 4ac035340..b69a1fb61 100644 --- a/mathics/builtin/files_io/importexport.py +++ b/mathics/builtin/files_io/importexport.py @@ -1092,7 +1092,7 @@ class RegisterImport(Builtin): def apply(self, formatname, function, posts, evaluation, options): """ImportExport`RegisterImport[formatname_String, function_, posts_, - OptionsPattern[ImportExport`RegisterImport]]""" + OptionsPattern[ImportExport`RegisterImport]]""" evaluation.cache_result = False if function.has_form("List", None): @@ -1175,7 +1175,7 @@ class RegisterExport(Builtin): def apply(self, formatname, function, evaluation, options): """ImportExport`RegisterExport[formatname_String, function_, - OptionsPattern[ImportExport`RegisterExport]]""" + OptionsPattern[ImportExport`RegisterExport]]""" evaluation.cache_result = False EXPORTERS[formatname.get_string_value()] = (function, options) diff --git a/mathics/builtin/system.py b/mathics/builtin/system.py index b34ff04e8..f2516eca6 100644 --- a/mathics/builtin/system.py +++ b/mathics/builtin/system.py @@ -621,7 +621,7 @@ class ClearSystemCache(Builtin):
'ClearSystemCache[]'
Clears the internal system cache of expressions. - + """ def apply_clear(self, evaluation): diff --git a/mathics/core/expression.py b/mathics/core/expression.py index 01f6361cc..91d0f2ceb 100644 --- a/mathics/core/expression.py +++ b/mathics/core/expression.py @@ -144,7 +144,12 @@ def from_python(arg): # return Symbol(arg) elif isinstance(arg, dict): entries = [ - Expression("Rule", from_python(key), from_python(arg[key]),) for key in arg + Expression( + "Rule", + from_python(key), + from_python(arg[key]), + ) + for key in arg ] return Expression(SymbolList, *entries) elif isinstance(arg, BaseExpression): @@ -1315,7 +1320,11 @@ def evaluate(self, evaluation) -> typing.Union["Expression", "Symbol"]: # and hence, not used. if evaluation.cache_result and ( self.get_head_name() - in ("System`Out", "System`ToBoxes", "System`MakeBoxes",) + in ( + "System`Out", + "System`ToBoxes", + "System`MakeBoxes", + ) ): evaluation.cache_result = False @@ -1895,17 +1904,21 @@ def thread(self, evaluation, head=None) -> typing.Tuple[bool, "Expression"]: return True, Expression(head, *leaves) def is_numeric(self) -> bool: - return self._head.get_name() in system_symbols( - "Sqrt", - "Times", - "Plus", - "Subtract", - "Minus", - "Power", - "Abs", - "Divide", - "Sin", - ) and all(leaf.is_numeric() for leaf in self._leaves) + return ( + self._head.get_name() + in system_symbols( + "Sqrt", + "Times", + "Plus", + "Subtract", + "Minus", + "Power", + "Abs", + "Divide", + "Sin", + ) + and all(leaf.is_numeric() for leaf in self._leaves) + ) # TODO: complete list of numeric functions, or access NumericFunction # attribute