class Power(BinaryOperator, SympyFunction): """ <dl> <dt>'Power[$a$, $b$]'</dt> <dt>'$a$ ^ $b$'</dt> <dd>represents $a$ raised to the power of $b$. </dl> >> 4 ^ (1/2) = 2 >> 4 ^ (1/3) = 2 ^ (2 / 3) >> 3^123 = 48519278097689642681155855396759336072749841943521979872827 >> (y ^ 2) ^ (1/2) = Sqrt[y ^ 2] >> (y ^ 2) ^ 3 = y ^ 6 >> Plot[Evaluate[Table[x^y, {y, 1, 5}]], {x, -1.5, 1.5}, AspectRatio -> 1] = -Graphics- Use a decimal point to force numeric evaluation: >> 4.0 ^ (1/3) = 1.58740105196819947 'Power' has default value 1 for its second argument: >> DefaultValues[Power] = {HoldPattern[Default[Power, 2]] :> 1} >> a /. x_ ^ n_. :> {x, n} = {a, 1} 'Power' can be used with complex numbers: >> (1.5 + 1.0 I) ^ 3.5 = -3.68294005782191823 + 6.9513926640285049 I >> (1.5 + 1.0 I) ^ (3.5 + 1.5 I) = -3.19181629045628082 + 0.645658509416156807 I #> 1/0 : Infinite expression (division by zero) encountered. = ComplexInfinity #> Sqrt[-3+2. I] = 0.550250522700337511 + 1.81735402102397062 I #> Sqrt[-3+2 I] = Sqrt[-3 + 2 I] #> (3/2+1/2I)^2 = 2 + 3 I / 2 #> I ^ I = I ^ I #> 2 ^ 2.0 = 4. #> Pi ^ 4. = 97.4090910340024372 """ operator = '^' precedence = 590 attributes = ('Listable', 'NumericFunction', 'OneIdentity') grouping = 'Right' default_formats = False sympy_name = 'Pow' messages = { 'infy': "Infinite expression (division by zero) encountered.", } defaults = { 2: '1', } formats = { Expression('Power', Expression('Pattern', Symbol('x'), Expression('Blank')), Rational(1, 2)): 'HoldForm[Sqrt[x]]', (('InputForm', 'OutputForm'), 'x_ ^ y_'): ( 'Infix[{HoldForm[x], HoldForm[y]}, "^", 590, Right]'), ('', 'x_ ^ y_'): ( 'PrecedenceForm[Superscript[OuterPrecedenceForm[HoldForm[x], 590],' ' HoldForm[y]], 590]'), ('', 'x_ ^ y_?Negative'): ( 'HoldForm[Divide[1, #]]&[If[y==-1, HoldForm[x], HoldForm[x]^-y]]'), } rules = { } def apply(self, items, evaluation): 'Power[items__]' items_sequence = items.get_sequence() if len(items_sequence) == 2: x, y = items_sequence else: return Expression('Power', *items_sequence) if y.get_int_value() == 1: return x elif x.get_int_value() == 1: return x elif y.get_int_value() == 0: if x.get_int_value() == 0: evaluation.message('Power', 'indet', Expression('Power', x, y)) return Symbol('Indeterminate') else: return Integer(1) elif x.has_form('Power', 2) and isinstance(y, Integer): return Expression('Power', x.leaves[0], Expression('Times', x.leaves[1], y)) elif x.has_form('Times', None) and isinstance(y, Integer): return Expression('Times', *[ Expression('Power', leaf, y) for leaf in x.leaves]) elif (isinstance(x, Number) and isinstance(y, Number) and not (x.is_inexact() or y.is_inexact())): sym_x, sym_y = x.to_sympy(), y.to_sympy() try: if sympy.re(sym_y) >= 0: result = sym_x ** sym_y else: if sym_x == 0: evaluation.message('Power', 'infy') return Symbol('ComplexInfinity') result = sympy.Integer(1) / (sym_x ** (-sym_y)) if isinstance(result, sympy.Pow): result = result.simplify() args = [from_sympy(expr) for expr in result.as_base_exp()] result = Expression('Power', *args) result = result.evaluate_leaves(evaluation) return result return from_sympy(result) except ValueError: return Expression('Power', x, y) except ZeroDivisionError: evaluation.message('Power', 'infy') return Symbol('ComplexInfinity') elif (isinstance(x, Number) and isinstance(y, Number) and (x.is_inexact() or y.is_inexact())): try: prec = min_prec(x, y) with mpmath.workprec(prec): mp_x = sympy2mpmath(x.to_sympy(), prec) mp_y = sympy2mpmath(y.to_sympy(), prec) result = mp_x ** mp_y if isinstance(result, mpmath.mpf): return Real(str(result), prec) elif isinstance(result, mpmath.mpc): return Complex(str(result.real), str(result.imag), prec) except ZeroDivisionError: evaluation.message('Power', 'infy') return Symbol('ComplexInfinity') else: numerified_items = items.numerify(evaluation) return Expression('Power', *numerified_items.get_sequence())
def options_to_rules(options): items = sorted(options.iteritems()) return [Expression('Rule', Symbol(name), value) for name, value in items]
def apply(self, expr, form, evaluation): 'MatchQ[expr_, form_]' if match(expr, form, evaluation): return Symbol("True") return Symbol("False")
def apply_empty(self, evaluation): 'SeedRandom[]' with RandomEnv(evaluation) as rand: rand.seed() return Symbol('Null')
def apply(self, expr, evaluation): 'ValueQ[expr_]' evaluated_expr = expr.evaluate(evaluation) if expr.same(evaluated_expr): return Symbol('False') return Symbol('True')
def apply_novar(self, s, evaluation): "MinimalPolynomial[s_]" x = Symbol("#1") return self.apply(s, x, evaluation)
def get_functions(self, prefix="apply", is_pymodule=False): functions = list(super(Predefined, self).get_functions(prefix)) if prefix == "apply" and hasattr(self, "evaluate"): functions.append((Symbol(self.get_name()), self.evaluate)) return functions
def apply_novar(self, s, evaluation): 'MinimalPolynomial[s_]' x = Symbol('#1') return self.apply(s, x, evaluation)
def apply(self, vars, expr, evaluation): "Compile[vars_, expr_]" from mathics.builtin.compile import ( _compile, int_type, real_type, bool_type, CompileArg, CompileError, ) # _Complex not implemented permitted_types = { Expression("Blank", Symbol("Integer")): int_type, Expression("Blank", Symbol("Real")): real_type, Symbol("True"): bool_type, Symbol("False"): bool_type, } if not vars.has_form("List", None): return evaluation.message("Compile", "invars") args = [] names = [] for var in vars.get_leaves(): if isinstance(var, Symbol): symb = var name = symb.get_name() typ = real_type elif var.has_form("List", 2): symb, typ = var.get_leaves() if isinstance(symb, Symbol) and typ in permitted_types: name = symb.get_name() typ = permitted_types[typ] else: return evaluation.message("Compile", "invar", var) else: return evaluation.message("Compile", "invar", var) # check for duplicate names if name in names: return evaluation.message("Compile", "fdup", symb, vars) else: names.append(name) args.append(CompileArg(name, typ)) try: cfunc = _compile(expr, args) except CompileError: cfunc = None if cfunc is None: try: def _pythonized_mathics_expr(*x): inner_evaluation = Evaluation(definitions=evaluation.definitions) vars = dict(list(zip(names, x[: len(names)]))) pyexpr = expr.replace_vars(vars) pyexpr = Expression("N", pyexpr).evaluate(inner_evaluation) res = pyexpr.to_python(n_evaluation=inner_evaluation) return res # TODO: check if we can use numba to compile this... cfunc = _pythonized_mathics_expr except Exception: cfunc = None if cfunc is None: evaluation.message("Compile", "comperr", expr) args = Expression("List", *names) return Expression("Function", args, expr) code = CompiledCode(cfunc, args) arg_names = Expression("List", *(Symbol(arg.name) for arg in args)) return Expression("CompiledFunction", arg_names, expr, code)
def from_sympy(self, sympy_name, leaves): return Expression('Power', Symbol('E'), leaves[0])
def set_ownvalue(self, name, value): from .expression import Symbol from .rules import Rule name = self.lookup_name(name) self.add_rule(name, Rule(Symbol(name), value))
def to_sympy(self, expr): if expr == Symbol('System`Degree'): return sympy.pi / 180
def from_sympy(expr): from mathics.builtin import sympy_to_mathics from mathics.core.expression import (Symbol, Integer, Rational, Real, Complex, String, Expression) from sympy.core import numbers, function, symbol if isinstance(expr, (tuple, list)): return Expression('List', *[from_sympy(item) for item in expr]) if isinstance(expr, int): return Integer(expr) if isinstance(expr, float): return Real(expr) if isinstance(expr, complex): return Complex(expr.real, expr.imag) if isinstance(expr, str): return String(expr) if expr is None: return Symbol('Null') if isinstance(expr, sympy.Matrix): return Expression( 'List', *[ Expression('List', *[from_sympy(item) for item in row]) for row in expr.tolist() ]) if expr.is_Atom: name = None if expr.is_Symbol: name = unicode(expr) if isinstance(expr, symbol.Dummy): name = name + ('__Dummy_%d' % expr.dummy_index) return Symbol(name, sympy_dummy=expr) if (( not name.startswith(sympy_symbol_prefix) or # noqa name.startswith(sympy_slot_prefix)) and name.startswith('C')): return Expression('C', int(name[1:])) if name.startswith(sympy_symbol_prefix): name = name[len(sympy_symbol_prefix):] if name.startswith(sympy_slot_prefix): index = name[len(sympy_slot_prefix):] return Expression('Slot', int(index)) elif expr.is_NumberSymbol: name = unicode(expr) if name is not None: builtin = sympy_to_mathics.get(name) if builtin is not None: name = builtin.get_name() return Symbol(name) elif isinstance(expr, (numbers.Infinity, numbers.ComplexInfinity)): return Symbol(expr.__class__.__name__) elif isinstance(expr, numbers.NegativeInfinity): return Expression('Times', Integer(-1), Symbol('Infinity')) elif isinstance(expr, numbers.ImaginaryUnit): return Complex(0, 1) elif isinstance(expr, numbers.Integer): return Integer(expr.p) elif isinstance(expr, numbers.Rational): if expr.q == 0: if expr.p > 0: return Symbol('Infinity') elif expr.p < 0: return Expression('Times', Integer(-1), Symbol('Infinity')) else: assert expr.p == 0 return Symbol('Indeterminate') return Rational(expr.p, expr.q) elif isinstance(expr, numbers.Float): return Real(expr) elif isinstance(expr, numbers.NaN): return Symbol('Indeterminate') elif isinstance(expr, function.FunctionClass): return Symbol(unicode(expr)) elif expr.is_number and all([x.is_Number for x in expr.as_real_imag()]): # Hack to convert 3 * I to Complex[0, 3] return Complex(*[from_sympy(arg) for arg in expr.as_real_imag()]) elif expr.is_Add: return Expression('Plus', *sorted([from_sympy(arg) for arg in expr.args])) elif expr.is_Mul: return Expression('Times', *sorted([from_sympy(arg) for arg in expr.args])) elif expr.is_Pow: return Expression('Power', *[from_sympy(arg) for arg in expr.args]) elif expr.is_Equality: return Expression('Equal', *[from_sympy(arg) for arg in expr.args]) elif isinstance(expr, SympyExpression): # print "SympyExpression: %s" % expr return expr.expr elif isinstance(expr, sympy.RootSum): return Expression('RootSum', from_sympy(expr.poly), from_sympy(expr.fun)) elif isinstance(expr, sympy.PurePoly): coeffs = expr.coeffs() monoms = expr.monoms() result = [] for coeff, monom in zip(coeffs, monoms): factors = [] if coeff != 1: factors.append(from_sympy(coeff)) for index, exp in enumerate(monom): if exp != 0: slot = Expression('Slot', index + 1) if exp == 1: factors.append(slot) else: factors.append( Expression('Power', slot, from_sympy(exp))) if factors: result.append(Expression('Times', *factors)) else: result.append(Integer(1)) return Expression('Function', Expression('Plus', *result)) elif isinstance(expr, sympy.Lambda): vars = [ sympy.Symbol('%s%d' % (sympy_slot_prefix, index + 1)) for index in range(len(expr.variables)) ] return Expression('Function', from_sympy(expr(*vars))) elif expr.is_Function or isinstance( expr, (sympy.Integral, sympy.Derivative, sympy.Sum, sympy.Product)): if isinstance(expr, sympy.Integral): name = 'Integral' elif isinstance(expr, sympy.Derivative): name = 'Derivative' else: name = expr.func.__name__ if name.startswith(sympy_symbol_prefix): name = name[len(sympy_symbol_prefix):] args = [from_sympy(arg) for arg in expr.args] builtin = sympy_to_mathics.get(name) if builtin is not None: name = builtin.get_name() args = builtin.from_sympy(args) return Expression(Symbol(name), *args) elif isinstance(expr, sympy.Tuple): return Expression('List', *[from_sympy(arg) for arg in expr.args]) # elif isinstance(expr, sympy.Sum): # return Expression('Sum', ) elif isinstance(expr, sympy.LessThan): return Expression('LessEqual', [from_sympy(arg) for arg in expr.args]) elif isinstance(expr, sympy.StrictLessThan): return Expression('Less', [from_sympy(arg) for arg in expr.args]) elif isinstance(expr, sympy.GreaterThan): return Expression('GreaterEqual', [from_sympy(arg) for arg in expr.args]) elif isinstance(expr, sympy.StrictGreaterThan): return Expression('Greater', [from_sympy(arg) for arg in expr.args]) elif isinstance(expr, sympy.Unequality): return Expression('Unequal', [from_sympy(arg) for arg in expr.args]) elif isinstance(expr, sympy.Equality): return Expression('Equal', [from_sympy(arg) for arg in expr.args]) else: raise ValueError("Unknown SymPy expression: %s" % expr)
def apply(self, items, evaluation): 'Power[items__]' items_sequence = items.get_sequence() if len(items_sequence) == 2: x, y = items_sequence else: return Expression('Power', *items_sequence) if y.get_int_value() == 1: return x elif x.get_int_value() == 1: return x elif y.get_int_value() == 0: if x.get_int_value() == 0: evaluation.message('Power', 'indet', Expression('Power', x, y)) return Symbol('Indeterminate') else: return Integer(1) elif x.has_form('Power', 2) and isinstance(y, Integer): return Expression('Power', x.leaves[0], Expression('Times', x.leaves[1], y)) elif x.has_form('Times', None) and isinstance(y, Integer): return Expression('Times', *[ Expression('Power', leaf, y) for leaf in x.leaves]) elif (isinstance(x, Number) and isinstance(y, Number) and not (x.is_inexact() or y.is_inexact())): sym_x, sym_y = x.to_sympy(), y.to_sympy() try: if sympy.re(sym_y) >= 0: result = sym_x ** sym_y else: if sym_x == 0: evaluation.message('Power', 'infy') return Symbol('ComplexInfinity') result = sympy.Integer(1) / (sym_x ** (-sym_y)) if isinstance(result, sympy.Pow): result = result.simplify() args = [from_sympy(expr) for expr in result.as_base_exp()] result = Expression('Power', *args) result = result.evaluate_leaves(evaluation) return result return from_sympy(result) except ValueError: return Expression('Power', x, y) except ZeroDivisionError: evaluation.message('Power', 'infy') return Symbol('ComplexInfinity') elif (isinstance(x, Number) and isinstance(y, Number) and (x.is_inexact() or y.is_inexact())): try: prec = min_prec(x, y) with mpmath.workprec(prec): mp_x = sympy2mpmath(x.to_sympy(), prec) mp_y = sympy2mpmath(y.to_sympy(), prec) result = mp_x ** mp_y if isinstance(result, mpmath.mpf): return Real(str(result), prec) elif isinstance(result, mpmath.mpc): return Complex(str(result.real), str(result.imag), prec) except ZeroDivisionError: evaluation.message('Power', 'infy') return Symbol('ComplexInfinity') else: numerified_items = items.numerify(evaluation) return Expression('Power', *numerified_items.get_sequence())
def lhs(expr): return Expression('Format', expr, Symbol(format))
class DensityPlot(Builtin): """ <dl> <dt>'DensityPlot[$f$, {$x$, $xmin$, $xmax$}, {$y$, $ymin$, $ymax$}]' <dd>plots a density plot of $f$ with $x$ ranging from $xmin$ to $xmax$ and $y$ ranging from $ymin$ to $ymax$. </dl> >> DensityPlot[x ^ 2 + 1 / y, {x, -1, 1}, {y, 1, 4}] = -Graphics- """ from graphics import Graphics attributes = ('HoldAll', ) options = Graphics.options.copy() options.update({ 'Axes': 'False', 'AspectRatio': '1', 'Frame': 'True', 'ColorFunction': 'Automatic', 'ColorFunctionScaling': 'True', }) def apply(self, f, x, xstart, xstop, y, ystart, ystop, evaluation, options): 'DensityPlot[f_, {x_Symbol, xstart_, xstop_}, {y_Symbol, ystart_, ystop_}, OptionsPattern[DensityPlot]]' x = x.get_name() y = y.get_name() color_function = self.get_option(options, 'ColorFunction', evaluation, pop=True) color_function_scaling = self.get_option(options, 'ColorFunctionScaling', evaluation, pop=True) color_function_min = color_function_max = None if color_function.get_name() == 'Automatic': color_function = String('LakeColors') if color_function.get_string_value(): func = Expression( 'ColorData', color_function.get_string_value()).evaluate(evaluation) if func.has_form('ColorDataFunction', 4): color_function_min = func.leaves[2].leaves[0].get_real_value() color_function_max = func.leaves[2].leaves[1].get_real_value() color_function = Expression( 'Function', Expression(func.leaves[3], Expression('Slot', 1))) else: evaluation.message('DensityPlot', 'color', func) return if color_function.has_form('ColorDataFunction', 4): color_function_min = color_function.leaves[2].leaves[ 0].get_real_value() color_function_max = color_function.leaves[2].leaves[ 1].get_real_value() color_function_scaling = color_function_scaling.is_true() try: xstart, xstop, ystart, ystop = [ value.to_number(n_evaluation=evaluation) for value in (xstart, xstop, ystart, ystop) ] except NumberError, exc: expr = Expression('DensityPlot', f, Expression('List', x, xstart, xstop), Expression('List', y, ystart, ystop), *options_to_rules(options)) evaluation.message('DensityPlot', 'plln', exc.value, expr) return #print "Initialized" stored = {} def eval_f(x_value, y_value): value = stored.get((x_value, y_value), False) if value == False: value = dynamic_scoping(f.evaluate, { x: Real(x_value), y: Real(y_value) }, evaluation) value = chop(value).get_real_value() value = float(value) stored[(x_value, y_value)] = value return value v_borders = [None, None] triangles = [] eps = 0.01 def triangle(x1, y1, x2, y2, x3, y3, depth=None): if depth is None: x1, x2, x3 = [ xstart + value * (xstop - xstart) for value in (x1, x2, x3) ] y1, y2, y3 = [ ystart + value * (ystop - ystart) for value in (y1, y2, y3) ] depth = 0 v1, v2, v3 = eval_f(x1, y1), eval_f(x2, y2), eval_f(x3, y3) for v in (v1, v2, v3): if v_borders[0] is None or v < v_borders[0]: v_borders[0] = v if v_borders[1] is None or v > v_borders[1]: v_borders[1] = v if v1 is None or v2 is None or v3 is None: return limit = (v_borders[1] - v_borders[0]) * eps if depth < 2: if abs(v1 - v2) > limit: triangle(x1, y1, x3, y3, (x1 + x2) / 2, (y1 + y2) / 2, depth + 1) triangle(x2, y2, x3, y3, (x1 + x2) / 2, (y1 + y2) / 2, depth + 1) return if abs(v2 - v3) > limit: triangle(x1, y1, x2, y2, (x2 + x3) / 2, (y2 + y3) / 2, depth + 1) triangle(x1, y1, x3, y3, (x2 + x3) / 2, (y2 + y3) / 2, depth + 1) return if abs(v1 - v3) > limit: triangle(x2, y2, x1, y1, (x1 + x3) / 2, (y1 + y3) / 2, depth + 1) triangle(x2, y2, x3, y3, (x1 + x3) / 2, (y1 + y3) / 2, depth + 1) return triangles.append([(x1, y1, v1), (x2, y2, v2), (x3, y3, v3)]) points = 7 num = points * 1.0 for xi in range(points): for yi in range(points): triangle(xi / num, yi / num, (xi + 1) / num, (yi + 1) / num, (xi + 1) / num, yi / num) triangle(xi / num, yi / num, (xi + 1) / num, (yi + 1) / num, xi / num, (yi + 1) / num) v_min = v_max = None #if color_function_scaling: for t in triangles: for tx, ty, v in t: if v_min is None or v < v_min: v_min = v if v_max is None or v > v_max: v_max = v v_range = v_max - v_min if v_range == 0: v_range = 1 if color_function.has_form('ColorDataFunction', 4): color_func = color_function.leaves[3] else: color_func = color_function if color_function_scaling and color_function_min is not None and color_function_max is not None: color_function_range = color_function_max - color_function_min colors = {} def eval_color(x, y, v): #v_lookup = int(v * 100) #if color_function_scaling: v_scaled = (v - v_min) / v_range if color_function_scaling and color_function_min is not None and color_function_max is not None: v_color_scaled = color_function_min + v_scaled * color_function_range else: v_color_scaled = v v_lookup = int( v_scaled * 100 + 0.5) # calculate and store 100 different shades max. value = colors.get(v_lookup) if value is None: #print "Calc" #print "Scale" #print "Expression" #print "Calc color for %f" % v_scaled value = Expression(color_func, Real(v_color_scaled)) #print "Evaluate %s" % value value = value.evaluate(evaluation) #value = Expression('RGBColor', Real(0.5), Real(0.5), Real(0.5)) #print "Set" colors[v_lookup] = value return value #print "Points" points = [] vertex_colors = [] for p1, p2, p3 in triangles: #print "Triangle %s,%s,%s" % (p1, p2, p3) c1, c2, c3 = eval_color(*p1), eval_color(*p2), eval_color(*p3) #print "Append" points.append( Expression('List', Expression('List', *p1[:2]), Expression('List', *p2[:2]), Expression('List', *p3[:2]))) vertex_colors.append(Expression('List', c1, c2, c3)) #print "Polygon" polygon = Expression( 'Polygon', Expression('List', *points), Expression('Rule', Symbol('VertexColors'), Expression('List', *vertex_colors))) #print "Result" result = Expression('Graphics', polygon, *options_to_rules(options)) #print "Return" return result
def apply(self, expr, form, evaluation): "CoefficientList[expr_, form_]" vars = [form] if not form.has_form("List", None) else [ v for v in form.leaves ] # check form is not a variable for v in vars: if not (isinstance(v, Symbol)) and not (isinstance(v, Expression)): return evaluation.message("CoefficientList", "ivar", v) # special cases for expr and form e_null = expr == Symbol("Null") f_null = form == Symbol("Null") if expr == Integer(0): return Expression("List") elif e_null and f_null: return Expression("List", Integer(0), Integer(0)) elif e_null and not f_null: return Expression("List", Symbol("Null")) elif f_null: return Expression("List", expr) elif form.has_form("List", 0): return expr sympy_expr = expr.to_sympy() sympy_vars = [v.to_sympy() for v in vars] if not sympy_expr.is_polynomial(*[x for x in sympy_vars]): return evaluation.message("CoefficientList", "poly", expr) try: sympy_poly, sympy_opt = sympy.poly_from_expr( sympy_expr, sympy_vars) dimensions = [ sympy_poly.degree(x) if x in sympy_poly.gens else 0 for x in sympy_vars ] # single & multiple variables cases if not form.has_form("List", None): return Expression( "List", *[ _coefficient(self.__class__.__name__, expr, form, Integer(n), evaluation) for n in range(dimensions[0] + 1) ]) elif form.has_form("List", 1): form = form.leaves[0] return Expression( "List", *[ _coefficient(self.__class__.__name__, expr, form, Integer(n), evaluation) for n in range(dimensions[0] + 1) ]) else: def _nth(poly, dims, exponents): if not dims: return from_sympy(poly.coeff_monomial(exponents)) leaves = [] first_dim = dims[0] for i in range(first_dim + 1): exponents.append(i) subs = _nth(poly, dims[1:], exponents) leaves.append(subs) exponents.pop() result = Expression("List", *leaves) return result return _nth(sympy_poly, dimensions, []) except sympy.PolificationFailed: return evaluation.message("CoefficientList", "poly", expr)
def options_to_rules(options, filter=None): items = sorted(options.items()) if filter: items = [(name, value) for name, value in items if strip_context(name) in filter.keys()] return [Expression('Rule', Symbol(name), value) for name, value in items]
def p_symbol(self, args): 'expr : symbol' args[0] = Symbol(args[1])
def construct_graphics(self, triangles, mesh_points, v_min, v_max, options, evaluation): mesh_option = self.get_option(options, 'Mesh', evaluation) mesh = mesh_option.to_python() color_function = self.get_option(options, 'ColorFunction', evaluation, pop=True) color_function_scaling = self.get_option(options, 'ColorFunctionScaling', evaluation, pop=True) color_function_min = color_function_max = None if color_function.get_name() == 'Automatic': color_function = String('LakeColors') if color_function.get_string_value(): func = Expression('ColorData', color_function.get_string_value()).evaluate(evaluation) if func.has_form('ColorDataFunction', 4): color_function_min = func.leaves[2].leaves[0].get_real_value() color_function_max = func.leaves[2].leaves[1].get_real_value() color_function = Expression('Function', Expression(func.leaves[3], Expression('Slot', 1))) else: evaluation.message('DensityPlot', 'color', func) return if color_function.has_form('ColorDataFunction', 4): color_function_min = color_function.leaves[2].leaves[0].get_real_value() color_function_max = color_function.leaves[2].leaves[1].get_real_value() color_function_scaling = color_function_scaling.is_true() v_range = v_max - v_min if v_range == 0: v_range = 1 if color_function.has_form('ColorDataFunction', 4): color_func = color_function.leaves[3] else: color_func = color_function if color_function_scaling and color_function_min is not None and color_function_max is not None: color_function_range = color_function_max - color_function_min colors = {} def eval_color(x, y, v): v_scaled = (v - v_min) / v_range if color_function_scaling and color_function_min is not None and color_function_max is not None: v_color_scaled = color_function_min + v_scaled * color_function_range else: v_color_scaled = v v_lookup = int(v_scaled * 100 + 0.5) # calculate and store 100 different shades max. value = colors.get(v_lookup) if value is None: value = Expression(color_func, Real(v_color_scaled)) value = value.evaluate(evaluation) colors[v_lookup] = value return value points = [] vertex_colors = [] graphics = [] for p1, p2, p3 in triangles: c1, c2, c3 = eval_color(*p1), eval_color(*p2), eval_color(*p3) points.append(Expression('List', Expression('List', *p1[:2]), Expression('List', *p2[:2]), Expression('List', *p3[:2]))) vertex_colors.append(Expression('List', c1, c2, c3)) graphics.append(Expression('Polygon', Expression('List', *points), Expression('Rule', Symbol('VertexColors'), Expression('List', *vertex_colors)))) if mesh == 'Full': for xi in range(len(mesh_points)): line = [] for yi in range(len(mesh_points[xi])): line.append(Expression('List', mesh_points[xi][yi][0], mesh_points[xi][yi][1])) graphics.append(Expression('Line', Expression('List', *line))) elif mesh == 'All': for p1, p2, p3 in triangles: line = [from_python(p1[:2]), from_python(p2[:2]), from_python(p3[:2])] graphics.append(Expression('Line', Expression('List', *line))) return graphics
def contribute(self, definitions, is_pymodule=False): from mathics.core.parser import parse_builtin_rule if is_pymodule: name = "PyMathics`" + self.get_name(short=True) else: name = self.get_name() options = {} option_syntax = "Warn" for option, value in self.options.items(): if option == "$OptionSyntax": option_syntax = value continue option = ensure_context(option) options[option] = parse_builtin_rule(value) if option.startswith("System`"): # Create a definition for the option's symbol. # Otherwise it'll be created in Global` when it's # used, so it won't work. if option not in definitions.builtin: definitions.builtin[option] = Definition(name=name, attributes=set()) # Check if the given options are actually supported by the Builtin. # If not, we might issue an optx error and abort. Using '$OptionSyntax' # in your Builtin's 'options', you can specify the exact behaviour # using one of the following values: # - 'Strict': warn and fail with unsupported options # - 'Warn': warn about unsupported options, but continue # - 'Ignore': allow unsupported options, do not warn if option_syntax in ("Strict", "Warn", "System`Strict", "System`Warn"): def check_options(options_to_check, evaluation): name = self.get_name() for key, value in options_to_check.items(): short_key = strip_context(key) if not has_option(options, short_key, evaluation): evaluation.message( name, "optx", Expression("Rule", short_key, value), strip_context(name), ) if option_syntax in ("Strict", "System`Strict"): return False return True elif option_syntax in ("Ignore", "System`Ignore"): check_options = None else: raise ValueError("illegal option mode %s; check $OptionSyntax." % option_syntax) rules = [] definition_class = (PyMathicsDefinitions() if is_pymodule else SystemDefinitions()) for pattern, function in self.get_functions(is_pymodule=is_pymodule): rules.append( BuiltinRule(name, pattern, function, check_options, system=not is_pymodule)) for pattern, replace in self.rules.items(): if not isinstance(pattern, BaseExpression): pattern = pattern % {"name": name} pattern = parse_builtin_rule(pattern, definition_class) replace = replace % {"name": name} # FIXME: Should system=True be system=not is_pymodule ? rules.append( Rule(pattern, parse_builtin_rule(replace), system=True)) box_rules = [] if name != "System`MakeBoxes": new_rules = [] for rule in rules: if rule.pattern.get_head_name() == "System`MakeBoxes": box_rules.append(rule) else: new_rules.append(rule) rules = new_rules def extract_forms(name, pattern): # Handle a tuple of (forms, pattern) as well as a pattern # on the left-hand side of a format rule. 'forms' can be # an empty string (=> the rule applies to all forms), or a # form name (like 'System`TraditionalForm'), or a sequence # of form names. def contextify_form_name(f): # Handle adding 'System`' to a form name, unless it's # '' (meaning the rule applies to all forms). return "" if f == "" else ensure_context(f) if isinstance(pattern, tuple): forms, pattern = pattern if isinstance(forms, str): forms = [contextify_form_name(forms)] else: forms = [contextify_form_name(f) for f in forms] else: forms = [""] return forms, pattern formatvalues = {"": []} for pattern, function in self.get_functions("format_"): forms, pattern = extract_forms(name, pattern) for form in forms: if form not in formatvalues: formatvalues[form] = [] formatvalues[form].append( BuiltinRule(name, pattern, function, None, system=True)) for pattern, replace in self.formats.items(): forms, pattern = extract_forms(name, pattern) for form in forms: if form not in formatvalues: formatvalues[form] = [] if not isinstance(pattern, BaseExpression): pattern = pattern % {"name": name} pattern = parse_builtin_rule(pattern) replace = replace % {"name": name} formatvalues[form].append( Rule(pattern, parse_builtin_rule(replace), system=True)) for form, formatrules in formatvalues.items(): formatrules.sort() messages = [ Rule( Expression("MessageName", Symbol(name), String(msg)), String(value), system=True, ) for msg, value in self.messages.items() ] messages.append( Rule( Expression("MessageName", Symbol(name), String("optx")), String("`1` is not a supported option for `2`[]."), system=True, )) if name == "System`MakeBoxes": attributes = [] else: attributes = ["System`Protected"] attributes += list(ensure_context(a) for a in self.attributes) options = {} for option, value in self.options.items(): option = ensure_context(option) options[option] = parse_builtin_rule(value) if option.startswith("System`"): # Create a definition for the option's symbol. # Otherwise it'll be created in Global` when it's # used, so it won't work. if option not in definitions.builtin: definitions.builtin[option] = Definition(name=name, attributes=set()) defaults = [] for spec, value in self.defaults.items(): value = parse_builtin_rule(value) pattern = None if spec is None: pattern = Expression("Default", Symbol(name)) elif isinstance(spec, int): pattern = Expression("Default", Symbol(name), Integer(spec)) if pattern is not None: defaults.append(Rule(pattern, value, system=True)) definition = Definition( name=name, rules=rules, formatvalues=formatvalues, messages=messages, attributes=attributes, options=options, defaultvalues=defaults, ) if is_pymodule: definitions.pymathics[name] = definition else: definitions.builtin[name] = definition makeboxes_def = definitions.builtin["System`MakeBoxes"] for rule in box_rules: makeboxes_def.add_rule(rule)
def get_result(self, items): return Symbol('Null')
def apply_words(self, words, evaluation, options): 'WordCloud[words_List, OptionsPattern[%(name)s]]' ignore_case = self.get_option(options, 'IgnoreCase', evaluation) == Symbol('True') freq = dict() for word in words.leaves: if not isinstance(word, String): return py_word = word.get_string_value() if ignore_case: key = py_word.lower() else: key = py_word record = freq.get(key, None) if record is None: freq[key] = [py_word, 1] else: record[1] += 1 max_items = self.get_option(options, 'MaxItems', evaluation) if isinstance(max_items, Integer): py_max_items = max_items.get_int_value() else: py_max_items = 200 image_size = self.get_option(options, 'ImageSize', evaluation) if image_size == Symbol('Automatic'): py_image_size = (800, 600) elif image_size.get_head_name() == 'System`List' and len( image_size.leaves) == 2: py_image_size = [] for leaf in image_size.leaves: if not isinstance(leaf, Integer): return py_image_size.append(leaf.get_int_value()) elif isinstance(image_size, Integer): size = image_size.get_int_value() py_image_size = (size, size) else: return # inspired by http://minimaxir.com/2016/05/wordclouds/ import random import os def color_func(word, font_size, position, orientation, random_state=None, **kwargs): return self.default_colors[random.randint(0, 7)] font_base_path = os.path.dirname( os.path.abspath(__file__)) + '/../fonts/' font_path = os.path.realpath(font_base_path + 'AmaticSC-Bold.ttf') if not os.path.exists(font_path): font_path = None from wordcloud import WordCloud wc = WordCloud(width=py_image_size[0], height=py_image_size[1], font_path=font_path, max_font_size=300, mode='RGB', background_color='white', max_words=py_max_items, color_func=color_func, random_state=42, stopwords=set()) wc.generate_from_frequencies(freq.values()) image = wc.to_image() return Image(numpy.array(image), 'RGB')
def apply(self, evaluation): 'Quit[]' evaluation.definitions.set_user_definitions({}) return Symbol('Null')
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 assign_elementary(self, lhs, rhs, evaluation, tags=None, upset=False): name = lhs.get_head_name() if name in system_symbols('OwnValues', 'DownValues', 'SubValues', 'UpValues', 'NValues', 'Options', 'DefaultValues', 'Attributes', 'Messages'): if len(lhs.leaves) != 1: evaluation.message_args(name, len(lhs.leaves), 1) return False tag = lhs.leaves[0].get_name() if not tag: evaluation.message(name, 'sym', lhs.leaves[0], 1) return False if tags is not None and tags != [tag]: evaluation.message(name, 'tag', Symbol(name), Symbol(tag)) return False if (name != 'System`Attributes' and 'System`Protected' # noqa in evaluation.definitions.get_attributes(tag)): evaluation.message(name, 'wrsym', Symbol(tag)) return False if name == 'System`Options': option_values = rhs.get_option_values(evaluation) if option_values is None: evaluation.message(name, 'options', rhs) return False evaluation.definitions.set_options(tag, option_values) elif name == 'System`Attributes': attributes = get_symbol_list( rhs, lambda item: evaluation.message(name, 'sym', item, 1)) if attributes is None: return False if 'System`Locked' in evaluation.definitions.get_attributes( tag): evaluation.message(name, 'locked', Symbol(tag)) return False evaluation.definitions.set_attributes(tag, attributes) else: rules = rhs.get_rules_list() if rules is None: evaluation.message(name, 'vrule', lhs, rhs) return False evaluation.definitions.set_values(tag, name, rules) return True form = '' nprec = None default = False message = False allow_custom_tag = False focus = lhs if name == 'System`N': if len(lhs.leaves) not in (1, 2): evaluation.message_args('N', len(lhs.leaves), 1, 2) return False if len(lhs.leaves) == 1: nprec = Symbol('MachinePrecision') else: nprec = lhs.leaves[1] focus = lhs.leaves[0] lhs = Expression('N', focus, nprec) elif name == 'System`MessageName': if len(lhs.leaves) != 2: evaluation.message_args('MessageName', len(lhs.leaves), 2) return False focus = lhs.leaves[0] message = True elif name == 'System`Default': if len(lhs.leaves) not in (1, 2, 3): evaluation.message_args('Default', len(lhs.leaves), 1, 2, 3) return False focus = lhs.leaves[0] default = True elif name == 'System`Format': if len(lhs.leaves) not in (1, 2): evaluation.message_args('Format', len(lhs.leaves), 1, 2) return False if len(lhs.leaves) == 2: form = lhs.leaves[1].get_name() if not form: evaluation.message('Format', 'fttp', lhs.leaves[1]) return False else: form = system_symbols('StandardForm', 'TraditionalForm', 'OutputForm', 'TeXForm', 'MathMLForm') lhs = focus = lhs.leaves[0] else: allow_custom_tag = True focus = focus.evaluate_leaves(evaluation) if tags is None and not upset: name = focus.get_lookup_name() if not name: evaluation.message(self.get_name(), 'setraw', focus) return False tags = [name] elif upset: if allow_custom_tag: tags = [] if focus.is_atom(): evaluation.message(self.get_name(), 'normal') return False for leaf in focus.leaves: name = leaf.get_lookup_name() tags.append(name) else: tags = [focus.get_lookup_name()] else: allowed_names = [focus.get_lookup_name()] if allow_custom_tag: for leaf in focus.get_leaves(): allowed_names.append(leaf.get_lookup_name()) for name in tags: if name not in allowed_names: evaluation.message(self.get_name(), 'tagnfd', Symbol(name)) return False ignore_protection = False rhs_int_value = rhs.get_int_value() lhs_name = lhs.get_name() if lhs_name == 'System`$RecursionLimit': # if (not rhs_int_value or rhs_int_value < 20) and not # rhs.get_name() == 'System`Infinity': if (not rhs_int_value or rhs_int_value < 20 or rhs_int_value > settings.MAX_RECURSION_DEPTH): # nopep8 evaluation.message('$RecursionLimit', 'limset', rhs) return False try: set_recursionlimit(rhs_int_value) except OverflowError: # TODO: Message return False ignore_protection = True elif lhs_name == 'System`$ModuleNumber': if not rhs_int_value or rhs_int_value <= 0: evaluation.message('$ModuleNumber', 'set', rhs) return False ignore_protection = True elif lhs_name in ('System`$Line', 'System`$HistoryLength'): if rhs_int_value is None or rhs_int_value < 0: evaluation.message(lhs_name, 'intnn', rhs) return False ignore_protection = True elif lhs_name == 'System`$RandomState': # TODO: allow setting of legal random states! # (but consider pickle's insecurity!) evaluation.message('$RandomState', 'rndst', rhs) return False elif lhs_name == 'System`$Context': new_context = rhs.get_string_value() if new_context is None or not valid_context_name( new_context, allow_initial_backquote=True): evaluation.message(lhs_name, 'cxset', rhs) return False # With $Context in Mathematica you can do some strange # things: e.g. with $Context set to Global`, something # like: # $Context = "`test`"; newsym # is accepted and creates Global`test`newsym. # Implement this behaviour by interpreting # $Context = "`test`" # as # $Context = $Context <> "test`" # if new_context.startswith('`'): new_context = (evaluation.definitions.get_current_context() + new_context.lstrip('`')) evaluation.definitions.set_current_context(new_context) ignore_protection = True return True elif lhs_name == 'System`$ContextPath': context_path = [s.get_string_value() for s in rhs.get_leaves()] if rhs.has_form('List', None) and all( valid_context_name(s) for s in context_path): evaluation.definitions.set_context_path(context_path) ignore_protection = True return True else: evaluation.message(lhs_name, 'cxlist', rhs) return False rhs_name = rhs.get_head_name() if rhs_name == 'System`Condition': if len(rhs.leaves) != 2: evaluation.message_args('Condition', len(rhs.leaves), 2) return False else: lhs = Expression('Condition', lhs, rhs.leaves[1]) rhs = rhs.leaves[0] rule = Rule(lhs, rhs) count = 0 defs = evaluation.definitions for tag in tags: if (not ignore_protection and 'System`Protected' # noqa in evaluation.definitions.get_attributes(tag)): if lhs.get_name() == tag: evaluation.message(self.get_name(), 'wrsym', Symbol(tag)) else: evaluation.message(self.get_name(), 'write', Symbol(tag), lhs) continue count += 1 if form: defs.add_format(tag, rule, form) elif nprec: defs.add_nvalue(tag, rule) elif default: defs.add_default(tag, rule) elif message: defs.add_message(tag, rule) else: if upset: defs.add_rule(tag, rule, position='up') else: defs.add_rule(tag, rule) if count == 0: return False return True
def yield_func(vars, rest): raise StopGenerator_MatchQ(Symbol("True"))
def format_definition(self, symbol, evaluation, grid=True): 'StandardForm,TraditionalForm,OutputForm: Definition[symbol_]' lines = [] def print_rule(rule, up=False, lhs=lambda l: l, rhs=lambda r: r): evaluation.check_stopped() if isinstance(rule, Rule): r = rhs( rule.replace.replace_vars({ 'System`Definition': Expression('HoldForm', Symbol('Definition')) })) lines.append( Expression( 'HoldForm', Expression(up and 'UpSet' or 'Set', lhs(rule.pattern.expr), r))) name = symbol.get_name() if not name: evaluation.message('Definition', 'sym', symbol, 1) return attributes = evaluation.definitions.get_attributes(name) definition = evaluation.definitions.get_user_definition(name, create=False) all = evaluation.definitions.get_definition(name) if attributes: attributes = list(attributes) attributes.sort() lines.append( Expression( 'HoldForm', Expression( 'Set', Expression('Attributes', symbol), Expression( 'List', *(Symbol(attribute) for attribute in attributes))))) if definition is not None and 'System`ReadProtected' not in attributes: for rule in definition.ownvalues: print_rule(rule) for rule in definition.downvalues: print_rule(rule) for rule in definition.subvalues: print_rule(rule) for rule in definition.upvalues: print_rule(rule, up=True) for rule in definition.nvalues: print_rule(rule) formats = sorted(definition.formatvalues.items()) for format, rules in formats: for rule in rules: def lhs(expr): return Expression('Format', expr, Symbol(format)) def rhs(expr): if expr.has_form('Infix', None): expr = Expression( Expression('HoldForm', expr.head), *expr.leaves) return Expression('InputForm', expr) print_rule(rule, lhs=lhs, rhs=rhs) for rule in all.defaultvalues: print_rule(rule) if all.options: options = sorted(all.options.items()) lines.append( Expression( 'HoldForm', Expression( 'Set', Expression('Options', symbol), Expression( 'List', *(Expression('Rule', Symbol(name), value) for name, value in options))))) if grid: if lines: return Expression( 'Grid', Expression('List', *(Expression('List', line) for line in lines)), Expression('Rule', Symbol('ColumnAlignments'), Symbol('Left'))) else: return Symbol('Null') else: for line in lines: evaluation.print_out(Expression('InputForm', line)) return Symbol('Null')
def apply_2(self, n, b, evaluation, nr_elements=None, pos=None): "RealDigits[n_?NumericQ, b_Integer]" expr = Expression("RealDigits", n) rational_no = ( True if isinstance(n, Rational) else False ) # it is used for checking whether the input n is a rational or not py_b = b.get_int_value() if isinstance(n, (Expression, Symbol, Rational)): pos_len = abs(pos) + 1 if pos is not None and pos < 0 else 1 if nr_elements is not None: n = Expression( "N", n, int(mpmath.log(py_b**(nr_elements + pos_len), 10)) + 1).evaluate(evaluation) else: if rational_no: n = Expression("N", n).evaluate(evaluation) else: return evaluation.message("RealDigits", "ndig", expr) py_n = abs(n.value) if not py_b > 1: return evaluation.message("RealDigits", "rbase", py_b) if isinstance(py_n, complex): return evaluation.message("RealDigits", "realx", expr) if isinstance(n, Integer): display_len = (int(mpmath.floor(mpmath.log(py_n, py_b))) if py_n != 0 and py_n != 1 else 1) else: display_len = int( Expression( "N", Expression( "Round", Expression( "Divide", Expression("Precision", py_n), Expression("Log", 10, py_b), ), ), ).evaluate(evaluation).to_python()) exp = int(mpmath.ceil(mpmath.log( py_n, py_b))) if py_n != 0 and py_n != 1 else 1 if py_n == 0 and nr_elements is not None: exp = 0 digits = [] if not py_b == 10: digits = convert_float_base(py_n, py_b, display_len - exp) # truncate all the leading 0's i = 0 while digits and digits[i] == 0: i += 1 digits = digits[i:] if not isinstance(n, Integer): if len(digits) > display_len: digits = digits[:display_len - 1] else: # drop any leading zeroes for x in str(py_n): if x != "." and (digits or x != "0"): digits.append(x) if pos is not None: temp = exp exp = pos + 1 move = temp - 1 - pos if move <= 0: digits = [0] * abs(move) + digits else: digits = digits[abs(move):] display_len = display_len - move list_str = Expression("List") for x in digits: if x == "e" or x == "E": break # Convert to Mathics' list format list_str.leaves.append(from_python(int(x))) if not rational_no: while len(list_str.leaves) < display_len: list_str.leaves.append(from_python(0)) if nr_elements is not None: # display_len == nr_elements if len(list_str.leaves) >= nr_elements: # Truncate, preserving the digits on the right list_str = list_str.leaves[:nr_elements] else: if isinstance(n, Integer): while len(list_str.leaves) < nr_elements: list_str.leaves.append(from_python(0)) else: # Adding Indeterminate if the length is greater than the precision while len(list_str.leaves) < nr_elements: list_str.leaves.append( from_python(Symbol("Indeterminate"))) return Expression("List", list_str, exp)
def create_infix(items, operator, prec, grouping): if len(items) == 1: return items[0] else: return Expression('Infix', Expression('List', *items), String(operator), prec, Symbol(grouping))