|
| 1 | +""" |
| 2 | +Example to show how new Format-directed Boxing might work. |
| 3 | +
|
| 4 | +This is a minimal example so we can discuss feasiblity. |
| 5 | +""" |
| 6 | +from mathics.builtin.forms.base import box |
| 7 | +from mathics.core.atoms import IntegerM1, Integer1, Integer2, Rational |
| 8 | +from mathics.core.expression import Expression |
| 9 | +from mathics.core.parser import parse, MathicsSingleLineFeeder |
| 10 | +from mathics.core.symbols import SymbolDivide |
| 11 | +from mathics.core.systemsymbols import ( |
| 12 | + SymbolFractionBox, |
| 13 | + SymbolMakeBoxes, |
| 14 | + SymbolPower, |
| 15 | + SymbolSqrt, |
| 16 | + SymbolStandardForm, |
| 17 | +) |
| 18 | +from mathics.session import MathicsSession |
| 19 | + |
| 20 | +session = MathicsSession(character_encoding="ASCII") |
| 21 | + |
| 22 | + |
| 23 | +# Hacky pseudo boxing rules. |
| 24 | +# Currently in MakeBox rule rewriting occurs via MakeBox rewrite rules |
| 25 | +# which are attached to various Builtin classes. |
| 26 | + |
| 27 | +# The rewrite is performed as a part of rewriting portion of Expression evaluation. |
| 28 | +# We probably want to segregate these rules from other kinds of rules. |
| 29 | +# |
| 30 | +# The below hacky code is to simulate the rule behavior for |
| 31 | +# just a few kinds of things so we don't have to hook into the |
| 32 | +# complex rewrite mechanism in use in general evaluation. The implementation we use |
| 33 | +# is just good enough for the new kinds of things we need. |
| 34 | +# It is not intended to be used in a final implementation. |
| 35 | + |
| 36 | + |
| 37 | +def fractionbox_fn(expr): |
| 38 | + # To be continued... |
| 39 | + return Expression(SymbolFractionBox, *expr.elements) |
| 40 | + |
| 41 | + |
| 42 | +def sqrtbox_fn(expr): |
| 43 | + return Expression(SymbolSqrt, expr.elements[0]) |
| 44 | + |
| 45 | + |
| 46 | +def powerbox_fn(expr): |
| 47 | + new_expr = expr.elements[0] |
| 48 | + if new_expr.elements[-1] == IntegerM1: |
| 49 | + return Expression(SymbolDivide, Integer1, new_expr.elements[0]) |
| 50 | + elif new_expr.elements[-1] in (Rational(1, 2), Integer1 * (Integer2**IntegerM1)): |
| 51 | + return Expression(SymbolSqrt, new_expr.elements[0]) |
| 52 | + return new_expr |
| 53 | + |
| 54 | + |
| 55 | +boxform_rules = { |
| 56 | + # SymbolTimes: fractionbox_fn, |
| 57 | + SymbolPower: powerbox_fn, |
| 58 | + SymbolSqrt: sqrtbox_fn, |
| 59 | +} |
| 60 | + |
| 61 | + |
| 62 | +def apply_formatvalues_rules(expr, evaluation): |
| 63 | + """ |
| 64 | + Hacky replacement for rules() found in Expression rewrite_apply_eval(). |
| 65 | + Note, we need to add builtin FormatValues() and the internals that go with that. |
| 66 | + """ |
| 67 | + if expr.elements[-1] not in (SymbolStandardForm,): # Or more generally $BoxForms |
| 68 | + # For other forms, there might be other transformations too, and this should |
| 69 | + # be discussed. |
| 70 | + # For simplicity, we will just handle a small number of $BoxForms rules |
| 71 | + return expr |
| 72 | + |
| 73 | + # Remove the Form from expression "expr" |
| 74 | + unboxed_expr = expr.elements[0] |
| 75 | + |
| 76 | + if unboxed_expr.head in boxform_rules: |
| 77 | + new_expr = boxform_rules[unboxed_expr.head](expr) |
| 78 | + return new_expr |
| 79 | + return unboxed_expr |
| 80 | + |
| 81 | + |
| 82 | +# Begin demo code. |
| 83 | + |
| 84 | +for expr_str in ( |
| 85 | + # FIXME; |
| 86 | + # "1 / x", # Show off "Division" boxing |
| 87 | + "a ^ b", # Show off "Power" boxing |
| 88 | + "Sqrt[a]", # "Square-root boxing" |
| 89 | + "a ^ (1/2)", # "Square-root boxing" |
| 90 | +): |
| 91 | + print("expression: ", expr_str) |
| 92 | + |
| 93 | + # Parse, but don't evaluate expression. |
| 94 | + expr = parse(session.definitions, MathicsSingleLineFeeder(expr_str)) |
| 95 | + print("Parsed expression: ", expr) |
| 96 | + |
| 97 | + # Here is how Mathics currently evaluates MakeBoxes |
| 98 | + boxed_expr = Expression(SymbolMakeBoxes, expr, SymbolStandardForm) |
| 99 | + print("Mathics MakeBoxes: ", boxed_expr) |
| 100 | + |
| 101 | + # Evaluate to get final printed/rendered form |
| 102 | + print("Eval'd Makeboxes: ", boxed_expr.evaluate(session.evaluation)) |
| 103 | + |
| 104 | + # Here is how Mathics might better box an expression. |
| 105 | + # First we apply MakeBox boxing transformation rules. |
| 106 | + # This handles expression rewriting. |
| 107 | + transformed_boxed_expr = apply_formatvalues_rules(boxed_expr, session.evaluation) |
| 108 | + |
| 109 | + boxed_expr2 = box(transformed_boxed_expr, session.evaluation, SymbolStandardForm) |
| 110 | + print("New MakeBoxes: ", boxed_expr2) |
| 111 | + print("-" * 30) |
| 112 | + print("") |
0 commit comments