def format_plus(self, items, evaluation): 'Plus[items__]' def negate(item): if item.has_form('Times', 1, None): if isinstance(item.leaves[0], (Integer, Rational, Real, Complex)): neg = Number.from_mp(-item.leaves[0].to_sympy()) if neg.same(Integer(1)): if len(item.leaves) == 1: return neg else: return Expression('Times', *item.leaves[1:]) else: return Expression('Times', neg, *item.leaves[1:]) else: return Expression('Times', -1, *item.leaves) elif isinstance(item, (Integer, Rational, Real, Complex)): return Number.from_mp(-item.to_sympy()) else: return Expression('Times', -1, item) def is_negative(value): if isinstance(value, (Integer, Rational, Real)) and value.to_sympy() < 0: return True if isinstance(value, Complex): real, imag = value.to_sympy().as_real_imag() if real <= 0 and imag <= 0: return True return False items = items.get_sequence() values = [Expression('HoldForm', item) for item in items[:1]] ops = [] for item in items[1:]: if (item.has_form('Times', 1, None) and is_negative(item.leaves[0])) or is_negative(item): item = negate(item) op = "-" else: op = "+" values.append(Expression('HoldForm', item)) ops.append(String(op)) return Expression('Infix', Expression('List', *values), Expression('List', *ops), 310, Symbol('Left'))
def apply(self, items, evaluation): 'Inequality[items___]' items = items.numerify(evaluation).get_sequence() count = len(items) if count == 1: return Symbol('True') elif count % 2 == 0: evaluation.message('Inequality', 'ineq', count) elif count == 3: name = items[1].get_name() if name in operators.keys(): return Expression(name, items[0], items[2]) else: groups = [Expression('Inequality', *items[index - 1:index + 2]) for index in range(1, count - 1, 2)] return Expression('And', *groups)
def apply(self, expr, ls, evaluation, options={}): 'Level[expr_, ls_, OptionsPattern[Level]]' try: start, stop = python_levelspec(ls) except InvalidLevelspecError: evaluation.message('Level', 'level', ls) return result = [] def callback(level): result.append(level) return level heads = self.get_option(options, 'Heads', evaluation) == Symbol('True') walk_levels(expr, start, stop, heads=heads, callback=callback) return Expression('List', *result)
def apply_symbol(self, vars, attributes, evaluation): 'Unique[vars_, attributes___]' from mathics.core.parser import is_symbol_name from mathics.builtin.attributes import get_symbol_list attributes = attributes.get_sequence() if len(attributes) > 1: return evaluation.message('Unique', 'argrx', Integer(len(attributes) + 1)) # Check valid symbol variables symbols = vars.leaves if vars.has_form('List', None) else [vars] for symbol in symbols: if not isinstance(symbol, Symbol): text = symbol.get_string_value() if text is None or not is_symbol_name(text): return evaluation.message('Unique', 'usym', symbol) # Check valid attributes attrs = [] if len(attributes) > 0: attrs = get_symbol_list(attributes[0], lambda item: evaluation.message('Unique', 'attnf', item)) if attrs is None: return None # Generate list new symbols list = [] for symbol in symbols: if isinstance(symbol, Symbol): list.append(Module(Expression('List', symbol), symbol).evaluate(evaluation)) else: new_name = '%s%d' % (symbol.get_string_value(), self.seq_number) self.seq_number += 1 # Next symbol in case of new name is defined before while evaluation.definitions.get_definition(new_name, True) is not None: new_name = '%s%d' % (symbol.get_string_value(), self.seq_number) self.seq_number += 1 list.append(Symbol(new_name)) for symbol in list: for att in attrs: evaluation.definitions.set_attribute(symbol.get_name(), att) if vars.has_form('List', None): return Expression('List', *list) else: return list[0]
def apply(self, start, test, incr, body, evaluation): 'For[start_, test_, incr_, body_]' while test.evaluate(evaluation).is_true(): evaluation.check_stopped() try: try: body.evaluate(evaluation) except ContinueInterrupt: pass try: incr.evaluate(evaluation) except ContinueInterrupt: # Critical, most likely leads to an infinite loop pass except BreakInterrupt: break return Symbol('Null')
def testInstances(self): # duplicate instantiations of same content (like Integer 5) to test for potential instantiation randomness. _test_group( list( map( lambda f: (f(), f()), ( lambda: Integer(5), lambda: Rational(5, 2), lambda: MachineReal(5.12345678), lambda: Complex(Integer(5), Integer(2)), lambda: String("xy"), lambda: Symbol("xy"), ), ) ) )
def apply(self, f, expr, test, m, evaluation): 'NestWhile[f_, expr_, test_, Pattern[m,_Integer|All]]' results = [expr] while True: if m.get_name() == 'All': test_leaves = results else: test_leaves = results[-m.value:] test_expr = Expression(test, *test_leaves) test_result = test_expr.evaluate(evaluation) if test_result == Symbol('True'): next = Expression(f, results[-1]) results.append(next.evaluate(evaluation)) else: break return results[-1]
def quiet_evaluate(expr, vars, evaluation, expect_list=False): """ Evaluates expr with given dynamic scoping values without producing arithmetic error messages. """ expr = Expression('N', expr) quiet_expr = Expression('Quiet', expr, Expression('List', Expression('MessageName', Symbol('Power'), String('infy')))) value = dynamic_scoping(quiet_expr.evaluate, vars, evaluation) if expect_list: if value.has_form('List', None): value = [chop(item).get_real_value() for item in value.leaves] if any(item is None for item in value): return None return value else: return None else: return chop(value).get_real_value()
def apply(self, expr, args, evaluation): 'Manipulate[expr_, args__]' if (not _jupyter) or (not Kernel.initialized()) or (Kernel.instance() is None): return evaluation.message('Manipulate', 'jupyter') instantiator = _WidgetInstantiator() # knows about the arguments and their widgets for arg in args.get_sequence(): try: if not instantiator.add(arg, evaluation): # not a valid argument pattern? return except IllegalWidgetArguments as e: return evaluation.message('Manipulate', 'widgetargs', strip_context(str(e.var))) except JupyterWidgetError as e: return evaluation.message('Manipulate', 'widgetmake', e.err) clear_output_callback = evaluation.output.clear display_data_callback = evaluation.output.display # for pushing updates try: clear_output_callback(wait=True) except NotImplementedError: return evaluation.message('Manipulate', 'imathics') def callback(**kwargs): clear_output_callback(wait=True) line_no = evaluation.definitions.get_line_no() vars = [Expression('Set', Symbol(name), value) for name, value in kwargs.items()] evaluatable = Expression('ReleaseHold', Expression('Module', Expression('List', *vars), expr)) result = evaluation.evaluate(evaluatable, timeout=settings.TIMEOUT) if result: display_data_callback(data=result.result, metadata={}) evaluation.definitions.set_line_no(line_no) # do not increment line_no for manipulate computations widgets = instantiator.get_widgets() if len(widgets) > 0: box = _interactive(instantiator.build_callback(callback), widgets) # create the widget formatter = IPythonDisplayFormatter() if not formatter(box): # make the widget appear on the Jupyter notebook return evaluation.message('Manipulate', 'widgetdisp') return Symbol('Null') # the interactive output is pushed via kernel.display_data_callback (see above)
def read_list_from_types(read_types): """Return a Mathics List from a list of read_type names or a single read_type""" # Trun read_types into a list if it isn't already one. if read_types.has_form("List", None): read_types = read_types._leaves else: read_types = (read_types, ) # TODO: look for a better implementation handling "Hold[Expression]". # read_types = (Symbol("HoldExpression") if (typ.get_head_name() == "System`Hold" and typ.leaves[0].get_name() == "System`Expression") else typ for typ in read_types) return Expression("List", *read_types)
def map_at_one(i, leaves): if 1 <= i <= m: j = i - 1 elif -m <= i <= -1: j = m + i else: raise PartRangeError replace_leaf = new_leaves[j] if hasattr(replace_leaf, "head") and replace_leaf.head == Symbol("System`Rule"): new_leaves[j] = Expression( "System`Rule", replace_leaf.leaves[0], Expression(f, replace_leaf.leaves[1]), ) else: new_leaves[j] = Expression(f, replace_leaf) return new_leaves
def apply(self, l, k, f, evaluation): "CombinatoricaOld`BinarySearch[l_List, k_, f_] /; Length[l] > 0" leaves = l.leaves lower_index = 1 upper_index = len(leaves) if ( lower_index > upper_index ): # empty list l? Length[l] > 0 condition should guard us, but check anyway return Symbol("$Aborted") # "transform" is a handy wrapper for applying "f" or nothing if f.get_name() == "System`Identity": def transform(x): return x else: def transform(x): return Expression(f, x).evaluate(evaluation) # loop invariants (true at any time in the following loop): # (1) lower_index <= upper_index # (2) k > leaves[i] for all i < lower_index # (3) k < leaves[i] for all i > upper_index while True: pivot_index = (lower_index + upper_index) >> 1 # i.e. a + (b - a) // 2 # as lower_index <= upper_index, lower_index <= pivot_index <= upper_index pivot = transform(leaves[pivot_index - 1]) # 1-based to 0-based # we assume a trichotomous relation: k < pivot, or k = pivot, or k > pivot if k < pivot: if pivot_index == lower_index: # see invariant (2), to see that # k < leaves[pivot_index] and k > leaves[pivot_index - 1] return Rational((pivot_index - 1) + pivot_index, 2) upper_index = pivot_index - 1 elif k == pivot: return Integer(pivot_index) else: # k > pivot if pivot_index == upper_index: # see invariant (3), to see that # k > leaves[pivot_index] and k < leaves[pivot_index + 1] return Rational(pivot_index + (pivot_index + 1), 2) lower_index = pivot_index + 1
def get_default_value(name, evaluation, k=None, n=None): pos = [] if k is not None: pos.append(k) if n is not None: pos.append(n) for pos_len in reversed(range(len(pos) + 1)): # Try patterns from specific to general defaultexpr = Expression('Default', Symbol(name), *[Integer(index) for index in pos[:pos_len]]) result = evaluation.definitions.get_value(name, 'System`DefaultValues', defaultexpr, evaluation) if result is not None: if result.same(defaultexpr): result = result.evaluate(evaluation) return result return None
def apply_1(self, rules, evaluation): """SparseArray[rules_List]""" if not (rules.has_form("List", None) and len(rules.leaves) > 0): if rules == Symbol("Automatic"): return print(rules.has_form("List", (1,))) evaluation.message("SparseArray", "list", rules) return if not rules.leaves[0].is_atom() and rules.leaves[0].get_head_name() in ( "System`Rule", "System`DelayedRule", ): dims = self.find_dimensions(rules.leaves, evaluation) if dims is None: return return self.apply_3(rules, dims, Integer0, evaluation) return self.list_to_sparse(rules, evaluation)
def apply(self, number, evaluation, options={}): "Factorial2[number_?NumberQ, OptionsPattern[%(name)s]]" try: import scipy.special as sp from numpy import pi # From https://stackoverflow.com/a/36779406/546218 def fact2_generic(x): n = (x + 1.0) / 2.0 return 2.0**n * sp.gamma(n + 0.5) / (pi**(0.5)) except ImportError: fact2_generic = None pref_expr = self.get_option(options, "Method", evaluation) is_automatic = False if pref_expr == Symbol("System`Automatic"): is_automatic = True preference = "mpmath" else: preference = pref_expr.get_string_value() if preference in ("mpmath", "Automatic"): number_arg = number.to_mpmath() convert_from_fn = from_mpmath fact2_fn = getattr(mpmath, self.mpmath_name) elif preference == "sympy": number_arg = number.to_sympy() convert_from_fn = from_sympy fact2_fn = getattr(sympy, self.sympy_name) else: return evaluation.message("Factorial2", "unknownp", preference) try: result = fact2_fn(number_arg) except: # noqa number_arg = number.to_python() # Maybe an even negative number? Try generic routine if is_automatic and fact2_generic: return from_python(fact2_generic(number_arg)) return evaluation.message("Factorial2", "ndf", preference, str(sys.exc_info()[1])) return convert_from_fn(result)
def atom_to_boxes(self, f, evaluation): try: if self.color_space == 'Grayscale': pixels = self.pixels else: pixels = self.color_convert('RGB').pixels if pixels.dtype == numpy.bool: pixels = skimage.img_as_ubyte(pixels) shape = pixels.shape width = shape[1] height = shape[0] scaled_width = width scaled_height = height # if the image is very small, scale it up using nearest neighbour. min_size = 128 if width < min_size and height < min_size: scale = min_size / max(width, height) scaled_width = int(scale * width) scaled_height = int(scale * height) pixels = skimage.transform.resize( pixels, (scaled_height, scaled_width), order=0) with warnings.catch_warnings(): warnings.simplefilter("ignore") stream = BytesIO() skimage.io.imsave(stream, pixels, 'pil', format_str='png') stream.seek(0) contents = stream.read() stream.close() encoded = base64.b64encode(contents) if not six.PY2: encoded = encoded.decode('utf8') encoded = 'data:image/png;base64,' + encoded return Expression('ImageBox', String(encoded), Integer(scaled_width), Integer(scaled_height)) except: return Symbol("$Failed")
def apply(self, mlist, test, evaluation): 'Split[mlist_, test_]' expr = Expression('Split', mlist, test) if mlist.is_atom(): evaluation.message('Select', 'normal', 1, expr) return result = [[mlist.leaves[0]]] for leaf in mlist.leaves[1:]: applytest = Expression(test, result[-1][-1], leaf) if applytest.evaluate(evaluation) == Symbol('True'): result[-1].append(leaf) else: result.append([leaf]) return Expression(mlist.head, *[Expression('List', *l) for l in result])
def apply_inexact(self, z, evaluation): '%(name)s[z_Real|z_Complex?InexactNumberQ]' prec = z.get_precision() with mpmath.workprec(prec): z = sympy2mpmath(z.to_sympy()) if z is None: return try: result = self.eval(z) result = mpmath2sympy(result, prec) except ValueError, exc: text = str(exc) if text == 'gamma function pole': return Symbol('ComplexInfinity') else: raise except ZeroDivisionError: return
def evaluate(): if history_length > 0: self.definitions.add_rule( 'In', Rule(Expression('In', line_no), query)) result = query.evaluate(self) if history_length > 0: if self.predetermined_out is not None: out_result = self.predetermined_out self.predetermined_out = None else: out_result = result stored_result = self.get_stored_result(out_result) self.definitions.add_rule( 'Out', Rule(Expression('Out', line_no), stored_result)) if result != Symbol('Null'): return self.format_output(result, self.format) else: return None
def apply_level(self, f, expr, ls, evaluation, options={}): '''Scan[f_, expr_, Optional[Pattern[ls, _?LevelQ], {1}], OptionsPattern[Map]]''' try: start, stop = python_levelspec(ls) except InvalidLevelspecError: evaluation.message('Map', 'level', ls) return def callback(level): Expression(f, level).evaluate(evaluation) return level heads = self.get_option(options, 'Heads', evaluation).is_true() result, depth = walk_levels( expr, start, stop, heads=heads, callback=callback) return Symbol('Null')
def check(level, expr): if not expr.has_form('List', None): test_expr = Expression(test, expr) if test_expr.evaluate(evaluation) != Symbol('True'): return False level_dim = None else: level_dim = len(expr.leaves) if len(dims) > level: if dims[level] != level_dim: return False else: dims.append(level_dim) if level_dim is not None: for leaf in expr.leaves: if not check(level + 1, leaf): return False return True
def apply(self, symbols, attributes, evaluation): 'ClearAttributes[symbols_, attributes_]' symbols = get_symbol_list( symbols, lambda item: evaluation.message('ClearAttributes', 'sym', item, 1)) if symbols is None: return values = get_symbol_list( attributes, lambda item: evaluation.message('ClearAttributes', 'sym', item, 2)) if values is None: return for symbol in symbols: if 'Locked' in evaluation.definitions.get_attributes(symbol): evaluation.message('ClearAttributes', 'locked', symbol) else: for value in values: evaluation.definitions.clear_attribute(symbol, value) return Symbol('Null')
def apply(self, a, b, evaluation, options): '%(name)s[a_, b_, OptionsPattern[%(name)s]]' if isinstance(a, String) and isinstance(b, String): py_a = a.get_string_value() py_b = b.get_string_value() if options['System`IgnoreCase'] == Symbol('True'): if hasattr(str, 'casefold'): def normalize(c): return unicodedata.normalize("NFKD", c.casefold()) py_a = [normalize(c) for c in py_a] py_b = [normalize(c) for c in py_b] else: # python2, PyPy py_a = py_a.lower() py_b = py_b.lower() return Integer(self._distance( py_a, py_b, lambda u, v: u == v)) elif a.get_head_name() == 'System`List' and b.get_head_name() == 'System`List': return Integer(self._distance( a.leaves, b.leaves, lambda u, v: u.same(v))) else: return Expression('EditDistance', a, b)
def apply(self, c, G, h, evaluation): "LinearProgramming[c_, G_, h_]" (c, G, h), subs = to_sage((c, G, h), evaluation) n = len(c) c = vector(c) G = matrix([[-item for item in row] for row in G] + [unit_vector(k, n, -1) for k in range(n)]) h = vector([-item for item in h] + [0] * n) result = linear_program(c, G, h) status = result['status'] if status == 'dual infeasible': evaluation.message('LinearProgramming', 'lpsub') return Expression('List', *([Symbol('Indeterminate')] * n)) elif status == 'primal infeasible': return evaluation.message('LinearProgramming', 'lpsnf') #print result x = result['x'] x = [round(value, 6) for value in x] # round result to 6 digits after comma return from_sage(x, subs)
def apply(self, symbols, evaluation): '%(name)s[symbols___]' for symbol in symbols.get_sequence(): name = symbol.get_name() if not name: name = symbol.get_string_value() if not name: evaluation.message('Clear', 'ssym', symbol) continue attributes = evaluation.definitions.get_attributes(name) if 'Protected' in attributes: evaluation.message('Clear', 'wrsym', name) continue if not self.allow_locked and 'Locked' in attributes: evaluation.message('Clear', 'locked', name) continue definition = evaluation.definitions.get_user_definition(name) self.do_clear(definition) return Symbol('Null')
def apply(self, symbols, attributes, evaluation): "SetAttributes[symbols_, attributes_]" symbols = get_symbol_list( symbols, lambda item: evaluation.message("SetAttributes", "sym", item, 1)) if symbols is None: return values = get_symbol_list( attributes, lambda item: evaluation.message("SetAttributes", "sym", item, 2)) if values is None: return for symbol in symbols: if "System`Locked" in evaluation.definitions.get_attributes( symbol): evaluation.message("SetAttributes", "locked", Symbol(symbol)) else: for value in values: evaluation.definitions.set_attribute(symbol, value) return SymbolNull
def apply_N(self, precision, evaluation, options={}): "N[Degree, precision_, OptionsPattern[%(name)s]]" try: if precision: d = get_precision(precision, evaluation) else: d = get_precision(Symbol("System`MachinePrecision"), evaluation) except PrecisionValueError: return # FIXME: There are all sorts of interactions between in the trig functions, # that are expected to work out right. Until we have convertion between # mpmath and sympy worked out so that values can be made the to the same # precision and compared. we have to not use mpmath right now. # return self.get_constant(precision, evaluation, preference="mpmath") if d is None: return MachineReal(math.pi / 180) else: return PrecisionReal((sympy.pi / 180).n(d))
def apply(self, f, expr, n, evaluation, options): "FixedPoint[f_, expr_, n_:DirectedInfinity[1], OptionsPattern[FixedPoint]]" if n == Expression("DirectedInfinity", 1): count = None else: count = n.get_int_value() if count is None or count < 0: evaluation.message("FixedPoint", "intnn") return if count is None: count = self.get_option(options, "MaxIterations", evaluation) if count.is_numeric(): count = count.get_int_value() else: count = None result = expr index = 0 sametest = self.get_option(options, "SameTest", evaluation) if sametest == Symbol("Automatic"): sametest = None while count is None or index < count: evaluation.check_stopped() new_result = Expression(f, result).evaluate(evaluation) if sametest: same = Expression(sametest, result, new_result).evaluate(evaluation) same = same.is_true() if same: break else: if new_result == result: result = new_result break result = new_result index += 1 return result