diff --git a/mapytex/calculus/API/expression.py b/mapytex/calculus/API/expression.py index d06a608..abb0044 100644 --- a/mapytex/calculus/API/expression.py +++ b/mapytex/calculus/API/expression.py @@ -11,6 +11,7 @@ Expression """ from ..core import AssocialTree, Tree, compute, typing, TypingError +from .tokens import factory from .renders import renders class Expression(object): @@ -79,6 +80,7 @@ class Expression(object): 'tex' >>> print(e) 2 + 3 \\times 4 + >>> Expression.set_render('txt') """ cls.RENDER = render @@ -218,7 +220,7 @@ class Expression(object): """ Set ancestor """ self._ancestor = ancestor - def simplify(self, optimize=True): + def _simplify(self, optimize=True): """ Compute as much as possible the expression :param optimize: bool to optimize tree when it's possible @@ -227,8 +229,8 @@ class Expression(object): :example: >>> e = Expression.from_str("2+3*4") >>> e - - >>> f = e.simplify() + + >>> f = e._simplify() >>> f >>> f._ancestor @@ -249,7 +251,26 @@ class Expression(object): return typed_exp else: comp_exp.set_ancestor(self) - return comp_exp.simplify(optimize=optimize) + return comp_exp._simplify(optimize=optimize) + + 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 + + """ + self._child = self._simplify(optimize=optimize) + return factory(self._child, ancestor=self._child._ancestor) def explain(self): """ Yield every calculus step which have lead to self diff --git a/mapytex/calculus/API/tokens/__init__.py b/mapytex/calculus/API/tokens/__init__.py new file mode 100644 index 0000000..e202939 --- /dev/null +++ b/mapytex/calculus/API/tokens/__init__.py @@ -0,0 +1,53 @@ +#! /usr/bin/env python +# -*- coding: utf-8 -*- +# vim:fenc=utf-8 +# +# Copyright © 2017 lafrite +# +# Distributed under terms of the MIT license. + +""" +Tokens represents MathObject at API level + +""" +from ...core.MO.mo import MO, MOnumber, MOstr +from ...core.MO.fraction import MOFraction +from ...core.MO.monomial import MOstrPower, MOMonomial +from ...core.MO.polynomial import MOpolynomial +from decimal import Decimal as _Decimal + +from .number import Integer, Decimal, Fraction +from .polynomial import Polynomial, Linear, Quadratic + +__all__ = ["factory"] + +def factory(exp, name="", ancestor=None): + """ Transform a Expression with on MathObject (from core) to a appropriate token (from API) + """ + mo = exp._tree + if not isinstance(mo, MO): + raise TypeError(f"Can't build Token from not computed Expression (got {mo})") + if isinstance(mo, MOnumber): + if isinstance(mo.value, int): + return Integer(mo, name, ancestor) + elif isinstance(mo.value, _Decimal): + return Decimal(mo, name, ancestor) + else: + raise TypeError(f"Can't build from MOnumber ({mo}) neither int nor decimal") + + elif isinstance(mo, MOFraction): + if isinstance(mo._denominator, MOnumber) and \ + isinstance(mo._numerator, MOnumber): + return Fraction(mo, name, ancestor) + else: + raise TypeError(f"Can't build from MOFraction ({mo}) numerator and denominator are not MOnumber") + + elif isinstance(mo, (MOstr, MOstrPower, MOMonomial, MOpolynomial)): + raise TypeError(f"Can't build Polynom yet") + else: + raise TypeError(f"{type(mo)} is unknown MathObject") + +# ----------------------------- +# Reglages pour 'vim' +# vim:set autoindent expandtab tabstop=4 shiftwidth=4: +# cursor: 16 del diff --git a/mapytex/calculus/API/tokens/number.py b/mapytex/calculus/API/tokens/number.py index b3b212b..608cd4a 100644 --- a/mapytex/calculus/API/tokens/number.py +++ b/mapytex/calculus/API/tokens/number.py @@ -11,7 +11,8 @@ Tokens representing interger and decimal """ from .token import Token -from ...core.MO import MOnumber, MOFraction +from ...core.MO.mo import MOnumber +from ...core.MO.fraction import MOFraction from decimal import Decimal as _Decimal __all__ = ["Integer", "Decimal"] @@ -20,13 +21,13 @@ class Integer(Token): """ Token representing a integer """ - def __init__(self, mo, name=""): + def __init__(self, mo, name="", ancestor=None): if not isinstance(mo, MOnumber): raise TypeError if not isinstance(mo.value, int): raise TypeError - Token.__init__(self, mo, name) + Token.__init__(self, mo, name, ancestor) self._mathtype = 'entier' @classmethod @@ -37,13 +38,13 @@ class Decimal(Token): """ Token representing a decimal """ - def __init__(self, mo, name=""): + def __init__(self, mo, name="", ancestor=None): if not isinstance(mo, MOnumber): raise TypeError if not isinstance(mo.value, _Decimal): raise TypeError - Token.__init__(self, mo, name) + Token.__init__(self, mo, name, ancestor) self._mathtype = 'décimal' @classmethod @@ -54,7 +55,7 @@ class Fraction(Token): """ Token representing a fraction """ - def __init__(self, mo, name=""): + def __init__(self, mo, name="", ancestor=None): if not isinstance(mo, MOFraction): raise TypeError if not isinstance(mo._numerator, MOnumber): @@ -62,7 +63,7 @@ class Fraction(Token): if not isinstance(mo._denominator, MOnumber): raise TypeError - Token.__init__(self, mo, name) + Token.__init__(self, mo, name, ancestor) self._mathtype = 'fraction' @classmethod diff --git a/mapytex/calculus/API/tokens/polynomial.py b/mapytex/calculus/API/tokens/polynomial.py index e1764ff..ff8c9a6 100644 --- a/mapytex/calculus/API/tokens/polynomial.py +++ b/mapytex/calculus/API/tokens/polynomial.py @@ -7,7 +7,7 @@ # Distributed under terms of the MIT license. """ -Tokens representing interger and decimal +Tokens representing polynomials functions """ from .token import Token @@ -18,13 +18,13 @@ class Polynomial(Token): """ Token representing a polynomial """ - def __init__(self, mo, name=""): + def __init__(self, mo, name="", ancestor=None): if not isinstance(mo, MOpolynomial): raise TypeError if not isinstance(mo.value, int): raise TypeError - Token.__init__(self, mo, name) + Token.__init__(self, mo, name, ancestor) self._mathtype = 'polynome' @classmethod @@ -43,6 +43,40 @@ class Polynomial(Token): """ Call a Polynomial to evaluate itself on value """ pass +class Linear(Token): + + """ Token representing a linear """ + + def __init__(self, mo, name="", ancestor=None): + if not isinstance(mo, MOpolynomial): + raise TypeError + if not isinstance(mo.value, int): + raise TypeError + + Token.__init__(self, mo, name, ancestor) + self._mathtype = 'affine' + + @classmethod + def random(cls): + raise NotImplemented + +class Quadratic(Token): + + """ Token representing a quadratic """ + + def __init__(self, mo, name="", ancestor=None): + if not isinstance(mo, MOpolynomial): + raise TypeError + if not isinstance(mo.value, int): + raise TypeError + + Token.__init__(self, mo, name, ancestor) + self._mathtype = 'polynome du 2nd degré' + + @classmethod + def random(cls): + raise NotImplemented + # ----------------------------- # Reglages pour 'vim' diff --git a/mapytex/calculus/API/tokens/token.py b/mapytex/calculus/API/tokens/token.py index 7eda189..9aa481b 100644 --- a/mapytex/calculus/API/tokens/token.py +++ b/mapytex/calculus/API/tokens/token.py @@ -10,20 +10,61 @@ Tokens: practical envelop of math object """ +from ..renders import renders class Token(object): """ Token: practical envelop of an math object """ - def __init__(self, mo, name=""): + RENDER = 'txt' + + def __init__(self, mo, name="", ancestor = None): self._mo = mo self.name = name self._mathtype = None + self._ancestor = ancestor @classmethod def random(cls): raise NotImplemented + def explain(self): + """ Yield every calculus step which have lead to self + + :example: + >>> from mapytex.calculus.API import Expression + >>> e = Expression.from_str("2+3*4") + >>> f = e.simplify() + >>> f + + >>> for s in f.explain(): + ... print(s) + 2 + 3 * 4 + 2 + 12 + 14 + """ + try: + yield from self._ancestor.explain() + yield self + except AttributeError: + yield self + + def __repr__(self): + return f"<{self.__class__.__name__} {self.__txt__}>" + + def __str__(self): + return renders[self.RENDER](self._mo) + + @property + def __txt__(self): + return self._mo.__txt__ + + @property + def __tex__(self): + return self._mo.__tex__ + + + # -----------------------------