diff --git a/mapytex/calculus/API/tokens/__init__.py b/mapytex/calculus/API/tokens/__init__.py index ea66dc5..c048a4b 100644 --- a/mapytex/calculus/API/tokens/__init__.py +++ b/mapytex/calculus/API/tokens/__init__.py @@ -15,10 +15,12 @@ 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 functools import wraps from .token import Token __all__ = ["factory"] + def tokenify(mo, name="", ancestor=None): """ Transform a MO or a python builtin to the appropriate token @@ -51,11 +53,33 @@ def tokenify(mo, name="", ancestor=None): """ if isinstance(mo, MO): return _tokenify(mo, name, ancestor) - elif isinstance(mo, Token): - return _tokenify(mo._mo, name, ancestor) + + if isinstance(mo, Token): + if name == "": + _name = mo.name + else: + _name = name + if ancestor is None: + _ancestor = mo._ancestor + else: + _ancestor = ancestor + return _tokenify(mo._mo, _name, _ancestor) + return _tokenify(moify(mo), name, ancestor) +def to_be_token(func): + """ Decorator to ensure that the return value is a Token """ + @wraps(func) + def wrapped(*args, **kwds): + ans = func(*args, **kwds) + try: + return [tokenify(t) for t in ans] + except TypeError: + return tokenify(ans) + return wrapped + + def _tokenify(mo, name="", ancestor=None): """ Transform a MO (from core) to the appropriate token (from API) @@ -91,25 +115,28 @@ def _tokenify(mo, name="", ancestor=None): if isinstance(mo, MOnumber): if isinstance(mo.value, int): from .number import Integer + return Integer.from_mo(mo, name, ancestor) elif isinstance(mo.value, _Decimal): from .number import Decimal + return Decimal.from_mo(mo, name, ancestor) raise TypeError(f"Can't build from MOnumber ({mo}) neither int nor decimal") - elif isinstance(mo, MOFraction): + if isinstance(mo, MOFraction): if isinstance(mo._denominator, MOnumber) and isinstance( mo._numerator, MOnumber ): from .number import Fraction + return Fraction.from_mo(mo, name, ancestor) raise TypeError( f"Can't build from MOFraction ({mo}) numerator and denominator are not MOnumber" ) - elif isinstance(mo, (MOstr, MOstrPower, MOMonomial, MOpolynomial)): + if isinstance(mo, (MOstr, MOstrPower, MOMonomial, MOpolynomial)): if not isinstance(mo._variable, (MOstr, str)): raise TypeError( f"Can't build Polynom over something else than a letter (got {mo._variable})" @@ -120,6 +147,7 @@ def _tokenify(mo, name="", ancestor=None): or (isinstance(mo, MOpolynomial) and mo.power.value == 1) ): from .polynomial import Linear + return Linear.from_mo(mo, name, ancestor) elif ( (isinstance(mo, MOstrPower) and mo.power.value == 2) @@ -127,14 +155,14 @@ def _tokenify(mo, name="", ancestor=None): or (isinstance(mo, MOpolynomial) and mo.power.value == 2) ): from .polynomial import Quadratic + return Quadratic.from_mo(mo, name, ancestor) else: from .polynomial import Polynomial + return Polynomial.from_mo(mo, name, ancestor) - else: - raise TypeError(f"{type(mo)} is unknown MathObject") - + raise TypeError(f"{type(mo)} is unknown MathObject") def factory(exp, name="", ancestor=None): diff --git a/mapytex/calculus/API/tokens/polynomial.py b/mapytex/calculus/API/tokens/polynomial.py index 45edb1b..09af32c 100644 --- a/mapytex/calculus/API/tokens/polynomial.py +++ b/mapytex/calculus/API/tokens/polynomial.py @@ -12,6 +12,7 @@ Tokens representing polynomials functions """ from ..expression import Expression from .token import Token +from . import to_be_token from ...core.MO import MO from ...core.MO.atoms import moify @@ -60,6 +61,7 @@ class Polynomial(Token): """ Use Polynomial like if they were a dictionnary to set coefficients """ raise NotImplementedError("Can't set coefficient of a polynomial") + @to_be_token def __getitem__(self, key): """ Use Polynomial like if they were a dictionnary to get coefficients @@ -67,11 +69,11 @@ class Polynomial(Token): >>> from ...core.MO.polynomial import MOpolynomial >>> P = Polynomial(MOpolynomial('x', [1, 2, 3])) >>> P[0] - + >>> P[1] - + >>> P[2] - + >>> P[3] Traceback (most recent call last): ... @@ -128,9 +130,9 @@ class Linear(Polynomial): >>> P >>> P.a - + >>> P.b - + >>> P.differentiate() >>> P.roots @@ -158,14 +160,17 @@ class Linear(Polynomial): raise NotImplementedError @property + @to_be_token def a(self): return self[1] @property + @to_be_token def b(self): return self[0] @property + @to_be_token def roots(self): """ Get the root of the polynomial @@ -194,11 +199,11 @@ class Quadratic(Polynomial): >>> P >>> P.a - + >>> P.b - + >>> P.c - + >>> P.delta >>> for s in P.delta.explain(): @@ -231,6 +236,7 @@ class Quadratic(Polynomial): raise NotImplementedError @property + @to_be_token def a(self): try: return self[2] @@ -238,6 +244,7 @@ class Quadratic(Polynomial): return 0 @property + @to_be_token def b(self): try: return self[1] @@ -245,6 +252,7 @@ class Quadratic(Polynomial): return 0 @property + @to_be_token def c(self): try: return self[0] @@ -252,10 +260,12 @@ class Quadratic(Polynomial): return 0 @property + @to_be_token def delta(self): return Expression.from_str(f"{self.b}^2-4*{self.a}*{self.c}").simplify() @property + @to_be_token def roots(self): """ Roots of the polynom @@ -266,10 +276,10 @@ class Quadratic(Polynomial): [] >>> P = Quadratic(MOpolynomial('x', [4, -4, 1])) >>> P.roots - [2.0] + [] >>> P = Quadratic(MOpolynomial('x', [1, 0, -1])) >>> P.roots - [-1.0, 1.0] + [, ] """ if self.delta._mo < 0: return [] diff --git a/mapytex/calculus/core/MO/atoms.py b/mapytex/calculus/core/MO/atoms.py index f9b505d..67919f1 100644 --- a/mapytex/calculus/core/MO/atoms.py +++ b/mapytex/calculus/core/MO/atoms.py @@ -123,10 +123,13 @@ class MOnumber(Atom): """ if isinstance(value, Atom) and isinstance(value.value, (int, Decimal, float)): Atom.__init__(self, value.value) - elif isinstance(value, (int, Decimal)): + elif isinstance(value, (float, Decimal)): + if int(value) == value: + Atom.__init__(self, int(value)) + else: + Atom.__init__(self, Decimal(value)) + elif isinstance(value, int): Atom.__init__(self, value) - elif isinstance(value, float): - Atom.__init__(self, Decimal(value)) else: try: float(value) @@ -165,7 +168,7 @@ class MOnumber(Atom): >>> MOnumber(-3).__tex__ '- 3' """ - if self.value > 0: + if self.value >= 0: return str(self.value) return f"- {abs(self.value)}"