#! /usr/bin/env python # -*- coding: utf-8 -*- # vim:fenc=utf-8 # # Copyright © 2017 lafrite # # Distributed under terms of the MIT license. """ Expression """ from ..core import AssocialTree, Tree, compute, typing from .renders import renders class Expression(object): """ Expression class :example: >>> e = Expression.from_str("2+3*4") >>> e2 = e.simplify() >>> print(e2) 14 >>> for s in e2.explain(): ... print(s) 2 + 3 * 4 2 + 12 14 """ RENDER = 'txt' def __init__(self, tree, ancestor=None): """ """ self._tree = tree self._ancestor = ancestor @classmethod def from_str(cls, string): """ Initiate the expression from a string :param string: String to parse to generate the Expression :returns: the expression """ t = Tree.from_str(string) return cls(t) @classmethod def random(self, template, conditions = [], shuffle = False): """ Initiate randomly the expression :param template: the template of the expression :param conditions: conditions on randomly generate variable :param shuffle: allowing to shuffle the tree :returns: TODO """ pass @classmethod def set_render(cls, render): """ Define default render function :param render: render function Tree -> str :example: >>> Expression.RENDER 'txt' >>> e = Expression.from_str("2+3*4") >>> print(e) 2 + 3 * 4 >>> Expression.set_render('tex') >>> Expression.RENDER 'tex' >>> print(e) 2 + 3 \\times 4 """ cls.RENDER = render def __str__(self): return renders[self.RENDER](self._tree) def __repr__(self): return f"" def balance(self): """ Balance selt._tree in order to optimize end tree number # TODO: their will be issue with / which is not commutative |lun. oct. 1 15:03:21 CEST 2018 :return: optmized version of self :example: >>> t = Expression.from_str("1+2+3+4+5+6+7+8+9") >>> print(t._tree) + > + | > + | | > + | | | > + | | | | > + | | | | | > + | | | | | | > + | | | | | | | > 1 | | | | | | | > 2 | | | | | | > 3 | | | | | > 4 | | | | > 5 | | | > 6 | | > 7 | > 8 > 9 >>> t.balance() >>> print(t._tree) + > + | > + | | > 1 | | > 2 | > + | | > 3 | | > 4 > + | > + | | > 5 | | > 6 | > + | | > 7 | | > + | | | > 8 | | | > 9 >>> t = Expression.from_str("1+2+3+4+5*6*7*8*9") >>> print(t._tree) + > + | > + | | > + | | | > 1 | | | > 2 | | > 3 | > 4 > * | > * | | > * | | | > * | | | | > 5 | | | | > 6 | | | > 7 | | > 8 | > 9 >>> t.balance() >>> print(t._tree) + > + | > 1 | > 2 > + | > 3 | > + | | > 4 | | > * | | | > * | | | | > 5 | | | | > 6 | | | > * | | | | > 7 | | | | > * | | | | | > 8 | | | | | > 9 """ self._tree = AssocialTree.from_any_tree(self._tree).balance() def simplify(self, optimize=True): """ Compute as much as possible the expression :param optimize: bool to optimize tree when it's possible :return: an expression :example: >>> e = Expression.from_str("2+3*4") >>> e >>> f = e.simplify() >>> f >>> f._ancestor """ if optimize: try: self.balance() except AttributeError: pass try: t = self._tree.apply_on_last_level(compute, typing) except AttributeError: return self except NotImplementedError: return self else: e = Expression(t, ancestor=self) return e.simplify(optimize=optimize) def explain(self): """ Yield every calculus step which have lead to self :example: >>> e = Expression.from_str("2+3*4") >>> f = e.simplify() >>> for s in f.explain(): ... print(s) 2 + 3 * 4 2 + 12 14 >>> e = Expression.from_str("1+2+3+4+5+6+7+8+9") >>> f = e.simplify() >>> for s in f.explain(): ... print(s) 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 3 + 7 + 11 + 7 + 17 10 + 11 + 24 10 + 35 45 >>> e = Expression.from_str("1+2+3+4+5+6+7+8+9") >>> f_no_balance = e.simplify(optimize=False) >>> for s in f_no_balance.explain(): ... print(s) 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 3 + 3 + 4 + 5 + 6 + 7 + 8 + 9 6 + 4 + 5 + 6 + 7 + 8 + 9 10 + 5 + 6 + 7 + 8 + 9 15 + 6 + 7 + 8 + 9 21 + 7 + 8 + 9 28 + 8 + 9 36 + 9 45 >>> e = Expression.from_str("1+2+3+4+5*6*7*8*9") >>> f = e.simplify() >>> for s in f.explain(): ... print(s) 1 + 2 + 3 + 4 + 5 * 6 * 7 * 8 * 9 3 + 3 + 4 + 30 * 7 * 72 6 + 4 + 30 * 504 6 + 4 + 15120 6 + 15124 15130 >>> e = Expression.from_str("1+2+3+4+5*6*7*8*9") >>> f_no_balance = e.simplify(optimize=False) >>> for s in f_no_balance.explain(): ... print(s) 1 + 2 + 3 + 4 + 5 * 6 * 7 * 8 * 9 3 + 3 + 4 + 30 * 7 * 8 * 9 6 + 4 + 210 * 8 * 9 10 + 1680 * 9 10 + 15120 15130 """ try: yield from self._ancestor.explain() except AttributeError: yield self else: yield self # ----------------------------- # Reglages pour 'vim' # vim:set autoindent expandtab tabstop=4 shiftwidth=4: # cursor: 16 del