From 09b04d2703781ed2ee16965b62c3e91bfbe8b25b Mon Sep 17 00:00:00 2001 From: Bertrand Benjamin Date: Tue, 14 May 2019 06:55:56 +0200 Subject: [PATCH] Style: apply black --- mapytex/calculus/API/expression.py | 14 ++- mapytex/calculus/API/renders.py | 8 +- mapytex/calculus/API/tokens/__init__.py | 31 ++++-- mapytex/calculus/API/tokens/number.py | 91 ++++++++-------- mapytex/calculus/API/tokens/polynomial.py | 9 +- mapytex/calculus/API/tokens/token.py | 7 +- mapytex/calculus/core/MO/atoms.py | 16 ++- mapytex/calculus/core/MO/exceptions.py | 1 + mapytex/calculus/core/MO/fraction.py | 11 +- mapytex/calculus/core/MO/mo.py | 5 +- mapytex/calculus/core/MO/monomial.py | 19 ++-- mapytex/calculus/core/MO/polynomial.py | 11 +- mapytex/calculus/core/arithmetic.py | 8 +- mapytex/calculus/core/compute/__init__.py | 22 ++-- mapytex/calculus/core/compute/add.py | 27 ++++- mapytex/calculus/core/compute/divide.py | 13 ++- mapytex/calculus/core/compute/exceptions.py | 5 + mapytex/calculus/core/compute/filters.py | 23 ++-- mapytex/calculus/core/compute/minus.py | 9 +- mapytex/calculus/core/compute/multiply.py | 112 +++++++++++++------- mapytex/calculus/core/compute/power.py | 9 +- mapytex/calculus/core/coroutine.py | 10 +- mapytex/calculus/core/operator.py | 28 ++--- mapytex/calculus/core/random/int_gene.py | 62 ++++++----- mapytex/calculus/core/renders/tree2tex.py | 32 +++--- mapytex/calculus/core/renders/tree2txt.py | 36 ++++--- mapytex/calculus/core/str2.py | 51 ++++++--- mapytex/calculus/core/tree.py | 88 ++++++++------- mapytex/calculus/core/tree_tools.py | 5 + mapytex/calculus/core/typing/__init__.py | 30 +++--- mapytex/calculus/core/typing/add.py | 84 +++++++++------ mapytex/calculus/core/typing/divide.py | 1 + mapytex/calculus/core/typing/exceptions.py | 2 + mapytex/calculus/core/typing/multiply.py | 5 + mapytex/calculus/core/typing/power.py | 2 +- 35 files changed, 533 insertions(+), 354 deletions(-) diff --git a/mapytex/calculus/API/expression.py b/mapytex/calculus/API/expression.py index 722d414..19a7808 100644 --- a/mapytex/calculus/API/expression.py +++ b/mapytex/calculus/API/expression.py @@ -14,6 +14,7 @@ from ..core import AssocialTree, Tree, compute, typing, TypingError from .tokens import factory from .renders import renders + class Expression(object): """ @@ -32,7 +33,7 @@ class Expression(object): 14 """ - RENDER = 'txt' + RENDER = "txt" def __init__(self, tree, ancestor=None): """ @@ -76,7 +77,7 @@ class Expression(object): return cls(t) @classmethod - def random(self, template, conditions = [], shuffle = False): + def random(self, template, conditions=[], shuffle=False): """ Initiate randomly the expression :param template: the template of the expression @@ -128,6 +129,7 @@ class Expression(object): >>> print(e._order()) x + 5x + 6x^3 + 2x^2 + 4x^2 + 1 + 3 """ + def signature(leaf): try: leaf.node @@ -138,7 +140,7 @@ class Expression(object): return type(leaf) else: try: - typed_leaf = typing(leaf.node, leaf.left_value, leaf.right_value) + typed_leaf = typing(leaf.node, leaf.left_value, leaf.right_value) return typed_leaf.signature except (AttributeError, NotImplementedError, TypingError): return type(leaf) @@ -148,8 +150,9 @@ class Expression(object): except AttributeError: return self - organised = AssocialTree.from_any_tree(self._tree).\ - organise_by(signature, recursive=True, exclude_nodes=exclude_nodes) + organised = AssocialTree.from_any_tree(self._tree).organise_by( + signature, recursive=True, exclude_nodes=exclude_nodes + ) return Expression(organised) def _optimize(self, exclude_nodes=["/", "**"]): @@ -380,6 +383,7 @@ class Expression(object): else: yield self + # ----------------------------- # Reglages pour 'vim' # vim:set autoindent expandtab tabstop=4 shiftwidth=4: diff --git a/mapytex/calculus/API/renders.py b/mapytex/calculus/API/renders.py index 828206c..831e4b0 100644 --- a/mapytex/calculus/API/renders.py +++ b/mapytex/calculus/API/renders.py @@ -12,6 +12,7 @@ Expression """ from ..core import tree2txt, tree2tex + def _txt(mo_tree): """ txt render for MOs or Trees""" try: @@ -24,6 +25,7 @@ def _txt(mo_tree): except AttributeError: return str(mo_tree) + def _tex(mo_tree): """ Tex render for MOs or Trees""" try: @@ -36,10 +38,8 @@ def _tex(mo_tree): except AttributeError: return str(mo_tree) -renders = { - 'txt': _txt, - 'tex': _tex, -} + +renders = {"txt": _txt, "tex": _tex} # ----------------------------- # Reglages pour 'vim' diff --git a/mapytex/calculus/API/tokens/__init__.py b/mapytex/calculus/API/tokens/__init__.py index 6876a8f..2d83125 100644 --- a/mapytex/calculus/API/tokens/__init__.py +++ b/mapytex/calculus/API/tokens/__init__.py @@ -21,6 +21,7 @@ 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) @@ -67,22 +68,31 @@ def factory(exp, name="", ancestor=None): 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): + if isinstance(mo._denominator, MOnumber) and isinstance( + mo._numerator, MOnumber + ): return Fraction.from_mo(mo, name, ancestor) - raise TypeError(f"Can't build from MOFraction ({mo}) numerator and denominator are not MOnumber") + raise TypeError( + f"Can't build from MOFraction ({mo}) numerator and denominator are not MOnumber" + ) elif 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})") - if isinstance(mo, MOstr) or \ - (isinstance(mo, MOMonomial) and mo.power.value == 1) or \ - (isinstance(mo, MOpolynomial) and mo.power.value == 1): + raise TypeError( + f"Can't build Polynom over something else than a letter (got {mo._variable})" + ) + if ( + isinstance(mo, MOstr) + or (isinstance(mo, MOMonomial) and mo.power.value == 1) + or (isinstance(mo, MOpolynomial) and mo.power.value == 1) + ): return Linear.from_mo(mo, name, ancestor) - elif (isinstance(mo, MOstrPower) and mo.power.value == 2) or \ - (isinstance(mo, MOMonomial) and mo.power.value == 2) or \ - (isinstance(mo, MOpolynomial) and mo.power.value == 2): + elif ( + (isinstance(mo, MOstrPower) and mo.power.value == 2) + or (isinstance(mo, MOMonomial) and mo.power.value == 2) + or (isinstance(mo, MOpolynomial) and mo.power.value == 2) + ): return Quadratic.from_mo(mo, name, ancestor) else: return Polynomial.from_mo(mo, name, ancestor) @@ -90,6 +100,7 @@ def factory(exp, name="", ancestor=None): else: raise TypeError(f"{type(mo)} is unknown MathObject") + # ----------------------------- # Reglages pour 'vim' # vim:set autoindent expandtab tabstop=4 shiftwidth=4: diff --git a/mapytex/calculus/API/tokens/number.py b/mapytex/calculus/API/tokens/number.py index e19d457..8a03731 100644 --- a/mapytex/calculus/API/tokens/number.py +++ b/mapytex/calculus/API/tokens/number.py @@ -19,6 +19,7 @@ from ...core.MO.fraction import MOFraction __all__ = ["Integer", "Decimal"] + class Integer(Token): """ Token representing a integer @@ -41,7 +42,7 @@ class Integer(Token): mo = a Token.__init__(self, mo, name, ancestor) - self._mathtype = 'entier' + self._mathtype = "entier" @classmethod def from_mo(cls, mo, name="", ancestor=None): @@ -53,13 +54,9 @@ class Integer(Token): return cls(mo, name, ancestor) @classmethod - def random(cls, - name = "", - min_value = -10, - max_value = 10, - rejected = [0, 1], - accept_callbacks=[], - ): + def random( + cls, name="", min_value=-10, max_value=10, rejected=[0, 1], accept_callbacks=[] + ): """ Generate a random Integer :param name: name of the Integer @@ -69,11 +66,11 @@ class Integer(Token): :param accept_callbacks: list of function for value acceptation """ - candidate = filter_random(min_value, max_value, - rejected, accept_callbacks) + candidate = filter_random(min_value, max_value, rejected, accept_callbacks) return Integer(candidate, name) + class Decimal(Token): """ Token representing a decimal @@ -98,27 +95,28 @@ class Decimal(Token): else: mo = a - self._mathtype = 'décimal' + self._mathtype = "décimal" Token.__init__(self, mo, name, ancestor) @classmethod def from_mo(cls, mo, name="", ancestor=None): if not isinstance(mo, MOnumber): raise TypeError - if not isinstance(mo.value, _Decimal): + if not isinstance(mo.value, _Decimal): raise TypeError return cls(mo, name, ancestor) @classmethod - def random(cls, - name= "", - min_value = -10, - max_value = 10, - digits = 2, - rejected = [0, 1], - reject_callbacks=[], - ): + def random( + cls, + name="", + min_value=-10, + max_value=10, + digits=2, + rejected=[0, 1], + reject_callbacks=[], + ): """ Generate a random Decimal :param name: name of the Integer @@ -131,10 +129,10 @@ class Decimal(Token): """ conditions = [lambda x: x in rejected] + reject_callbacks - float_cand = (max_value - min_value)*random() + min_value + float_cand = (max_value - min_value) * random() + min_value candidate = _Decimal(f"{float_cand:.{digits}f}") while any(c(candidate) for c in conditions): - float_cand = (max_value - min_value)*random() + min_value + float_cand = (max_value - min_value) * random() + min_value candidate = _Decimal(f"{float_cand:.{digits}f}") return Decimal(candidate, name) @@ -152,39 +150,44 @@ class Fraction(Token): def __init__(self, a, name="", ancestor=None): if not isinstance(a, MO): if isinstance(a, str): - num, denom = a.split('/') + num, denom = a.split("/") mo = MOFraction(int(num), int(denom)) else: raise TypeError else: mo = a - self._mathtype = 'fraction' + self._mathtype = "fraction" Token.__init__(self, mo, name, ancestor) @classmethod def from_mo(cls, mo, name="", ancestor=None): if not isinstance(mo, MOFraction): raise TypeError - if not isinstance(mo._numerator, MOnumber): + if not isinstance(mo._numerator, MOnumber): raise TypeError - if not isinstance(mo._denominator, MOnumber): + if not isinstance(mo._denominator, MOnumber): raise TypeError return cls(mo, name, ancestor) @classmethod - def random(cls, - name="", - fix_num="", - min_num=-10, max_num=10, rejected_num=[0], - accept_num_callbacks=[], - fix_denom="", - min_denom=-10, max_denom=10, rejected_denom=[0, 1, -1], - accept_denom_callbacks=[], - irreductible=False, - not_integer=True - ): + def random( + cls, + name="", + fix_num="", + min_num=-10, + max_num=10, + rejected_num=[0], + accept_num_callbacks=[], + fix_denom="", + min_denom=-10, + max_denom=10, + rejected_denom=[0, 1, -1], + accept_denom_callbacks=[], + irreductible=False, + not_integer=True, + ): """ Generate a random Fraction :param name: Name of the fraction @@ -202,9 +205,7 @@ class Fraction(Token): :param not_integer: can the generated fraction be egal to an interger """ if fix_num == "": - num = filter_random(min_num, max_num, - rejected_num, - accept_num_callbacks) + num = filter_random(min_num, max_num, rejected_num, accept_num_callbacks) else: num = fix_num @@ -212,17 +213,21 @@ class Fraction(Token): accept_callbacks = accept_denom_callbacks if irreductible: + def prime_with_num(denom): return gcd(num, denom) == 1 + accept_callbacks.append(prime_with_num) if not_integer: + def not_divise_num(denom): return num % denom != 0 + accept_callbacks.append(not_divise_num) - denom = filter_random(min_denom, max_denom, - rejected_denom, - accept_callbacks) + denom = filter_random( + min_denom, max_denom, rejected_denom, accept_callbacks + ) else: denom = fix_denom diff --git a/mapytex/calculus/API/tokens/polynomial.py b/mapytex/calculus/API/tokens/polynomial.py index 36e10fa..72070f1 100644 --- a/mapytex/calculus/API/tokens/polynomial.py +++ b/mapytex/calculus/API/tokens/polynomial.py @@ -15,6 +15,7 @@ from ...core.MO import MO __all__ = ["Polynomial", "Quadratic", "Linear"] + class Polynomial(Token): """ Token representing a polynomial """ @@ -29,7 +30,7 @@ class Polynomial(Token): mo = a Token.__init__(self, mo, name, ancestor) - self._mathtype = 'polynome' + self._mathtype = "polynome" @classmethod def from_mo(cls, mo, name="", ancestor=None): @@ -52,6 +53,7 @@ class Polynomial(Token): """ Call a Polynomial to evaluate itself on value """ pass + class Linear(Polynomial): """ Token representing a linear """ @@ -59,12 +61,13 @@ class Linear(Polynomial): def __init__(self, mo, name="", ancestor=None): Polynomial.__init__(self, mo, name, ancestor) - self._mathtype = 'affine' + self._mathtype = "affine" @classmethod def random(cls): raise NotImplemented + class Quadratic(Polynomial): """ Token representing a quadratic """ @@ -72,7 +75,7 @@ class Quadratic(Polynomial): def __init__(self, mo, name="", ancestor=None): Polynomial.__init__(self, mo, name, ancestor) - self._mathtype = 'polynome du 2nd degré' + self._mathtype = "polynome du 2nd degré" @classmethod def random(cls): diff --git a/mapytex/calculus/API/tokens/token.py b/mapytex/calculus/API/tokens/token.py index dff9d0d..63871ff 100644 --- a/mapytex/calculus/API/tokens/token.py +++ b/mapytex/calculus/API/tokens/token.py @@ -12,13 +12,14 @@ Tokens: practical envelop of math object """ from ..renders import renders + class Token(object): """ Token: practical envelop of an math object """ - RENDER = 'txt' + RENDER = "txt" - def __init__(self, mo, name="", ancestor = None): + def __init__(self, mo, name="", ancestor=None): self._mo = mo self.name = name self._mathtype = None @@ -71,6 +72,7 @@ class Token(object): from ..expression import Expression from ...core import Tree from . import factory + if not isinstance(other, Token): _other = factory(other) else: @@ -165,6 +167,7 @@ class Token(object): """ return self._operate(other, "/") + # ----------------------------- # Reglages pour 'vim' # vim:set autoindent expandtab tabstop=4 shiftwidth=4: diff --git a/mapytex/calculus/core/MO/atoms.py b/mapytex/calculus/core/MO/atoms.py index c222437..3e42a81 100644 --- a/mapytex/calculus/core/MO/atoms.py +++ b/mapytex/calculus/core/MO/atoms.py @@ -15,6 +15,7 @@ from ..coroutine import coroutine, STOOOP __all__ = ["moify", "MOnumber", "MOstr"] + @coroutine def moify(target): """ Coroutine which try to convert a parsed token into an MO @@ -47,6 +48,7 @@ def moify(target): except STOOOP as err: yield target_.throw(err) + @total_ordering class MOnumber(Atom): @@ -116,8 +118,10 @@ class MOnumber(Atom): elif isinstance(value, float): Atom.__init__(self, Decimal(value)) else: - raise MOError("The value of an MOnumber need to be a int, a float or a Decimal", - f"(got {type(value)})") + raise MOError( + "The value of an MOnumber need to be a int, a float or a Decimal", + f"(got {type(value)})", + ) self._signature = "scalar" @@ -215,9 +219,13 @@ class MOstr(Atom): val = value if not isinstance(val, str): - raise MOError(f"An MOstr should be initiate with a string - the unknown, got {val}") + raise MOError( + f"An MOstr should be initiate with a string - the unknown, got {val}" + ) if len(val) != 1: - raise MOError(f"An MOstr should be initiate with a single caracter string, got {val}") + raise MOError( + f"An MOstr should be initiate with a single caracter string, got {val}" + ) if not val.isalpha(): raise MOError(f"An MOstr should be initiate with a alpha string, got {val}") diff --git a/mapytex/calculus/core/MO/exceptions.py b/mapytex/calculus/core/MO/exceptions.py index ec498d4..7275ce0 100644 --- a/mapytex/calculus/core/MO/exceptions.py +++ b/mapytex/calculus/core/MO/exceptions.py @@ -10,6 +10,7 @@ Exceptions for core tools """ + class MOError(Exception): pass diff --git a/mapytex/calculus/core/MO/fraction.py b/mapytex/calculus/core/MO/fraction.py index aa2aa0e..eb338b2 100644 --- a/mapytex/calculus/core/MO/fraction.py +++ b/mapytex/calculus/core/MO/fraction.py @@ -11,6 +11,7 @@ from .mo import Molecule, MO __all__ = ["MOFraction"] + class MOFraction(Molecule): """ Fraction math object""" @@ -42,10 +43,7 @@ class MOFraction(Molecule): """ _numerator = MO.factory(numerator) _denominator = MO.factory(denominator) - base_tree = Tree("/", - _numerator, - _denominator, - ) + base_tree = Tree("/", _numerator, _denominator) if negative: tree = Tree("-", None, base_tree) else: @@ -71,9 +69,8 @@ class MOFraction(Molecule): def inverse(self): """ return the inverse fraction """ - return MOFraction(self._denominator, - self._numerator, - self.negative) + return MOFraction(self._denominator, self._numerator, self.negative) + # ----------------------------- # Reglages pour 'vim' diff --git a/mapytex/calculus/core/MO/mo.py b/mapytex/calculus/core/MO/mo.py index b5c0a12..91c043c 100644 --- a/mapytex/calculus/core/MO/mo.py +++ b/mapytex/calculus/core/MO/mo.py @@ -12,6 +12,7 @@ from ..renders import tree2txt, tree2tex __all__ = ["MO"] + class MO(ABC): """MO for math object @@ -50,7 +51,6 @@ class MO(ABC): return Atom.factory(value) - @abstractmethod def content(self): """ content of the mo """ @@ -97,6 +97,7 @@ class MO(ABC): """ return self._signature + class Atom(MO): """ Base Math Object with only one component. @@ -196,8 +197,6 @@ class Molecule(MO): return tree2tex(self._tree) - - # ----------------------------- # Reglages pour 'vim' # vim:set autoindent expandtab tabstop=4 shiftwidth=4: diff --git a/mapytex/calculus/core/MO/monomial.py b/mapytex/calculus/core/MO/monomial.py index 8eba5aa..f9d7017 100644 --- a/mapytex/calculus/core/MO/monomial.py +++ b/mapytex/calculus/core/MO/monomial.py @@ -13,6 +13,7 @@ from .exceptions import MOError __all__ = ["MOMonomial"] + class MOstrPower(Molecule): """ Power of a MOstr """ @@ -68,10 +69,7 @@ class MOstrPower(Molecule): raise MOError("The power of a monomial should be a integer") self._power = _power - _tree = Tree("^", - self._variable, - self._power, - ) + _tree = Tree("^", self._variable, self._power) Molecule.__init__(self, _tree) @@ -113,6 +111,7 @@ class MOstrPower(Molecule): """ return f"monome{self.power}" + class MOMonomial(Molecule): """ Monomial math object""" @@ -164,7 +163,9 @@ class MOMonomial(Molecule): if coefficient == 0: raise MOError("The coefficient of a monomial should not be 0") elif coefficient == 1: - raise MOError("The coefficient of a monomial should not be 1, it is a MOstrPower or MOstr") + raise MOError( + "The coefficient of a monomial should not be 1, it is a MOstrPower or MOstr" + ) self._coefficient = _coefficient _variable = MO.factory(variable) @@ -174,7 +175,9 @@ class MOMonomial(Molecule): elif isinstance(_variable, MOstr): _power = MO.factory(power) else: - raise MOError(f"variable need to be a MOstrPower or a MOstr. Got {type(variable)}.") + raise MOError( + f"variable need to be a MOstrPower or a MOstr. Got {type(variable)}." + ) self._variable = _variable self._power = _power @@ -187,10 +190,8 @@ class MOMonomial(Molecule): except AttributeError: _tree = Tree("*", self._coefficient, self.strpower) - Molecule.__init__(self, _tree) - def __str__(self): if self._coefficient != -1: return super(MOMonomial, self).__str__() @@ -244,6 +245,7 @@ class MOMonomial(Molecule): @property def degree(self): return self._power.value + @property def signature(self): """ Name of the mo in the API @@ -256,6 +258,7 @@ class MOMonomial(Molecule): """ return f"monome{self.power}" + # ----------------------------- # Reglages pour 'vim' # vim:set autoindent expandtab tabstop=4 shiftwidth=4: diff --git a/mapytex/calculus/core/MO/polynomial.py b/mapytex/calculus/core/MO/polynomial.py index 5b1bcd1..bb286df 100644 --- a/mapytex/calculus/core/MO/polynomial.py +++ b/mapytex/calculus/core/MO/polynomial.py @@ -14,6 +14,7 @@ from .monomial import MOMonomial, MOstrPower __all__ = ["MOpolynomial"] + class MOpolynomial(Molecule): """ MO polynomial""" @@ -45,11 +46,13 @@ class MOpolynomial(Molecule): self._variable = _variable if isinstance(coefs, dict): - _coefs = {MO.factory(d): MO.factory(c) for (d, c) in coefs.items() - if c != 0 } + _coefs = { + MO.factory(d): MO.factory(c) for (d, c) in coefs.items() if c != 0 + } elif isinstance(coefs, list): - _coefs = {MO.factory(d): MO.factory(c) for (d, c) in enumerate(coefs) - if c != 0 } + _coefs = { + MO.factory(d): MO.factory(c) for (d, c) in enumerate(coefs) if c != 0 + } else: raise TypeError("Coefs needs to be a dictionnary or a list") self._coefs = _coefs diff --git a/mapytex/calculus/core/arithmetic.py b/mapytex/calculus/core/arithmetic.py index 65580d5..b7b2e48 100644 --- a/mapytex/calculus/core/arithmetic.py +++ b/mapytex/calculus/core/arithmetic.py @@ -2,7 +2,7 @@ # encoding: utf-8 -__all__ = ['gcd'] +__all__ = ["gcd"] def gcd(a, b): @@ -28,7 +28,7 @@ def gcd(a, b): pos_a, _a = (a >= 0), abs(a) pos_b, _b = (b >= 0), abs(b) - gcd_sgn = (-1 + 2 * (pos_a or pos_b)) + gcd_sgn = -1 + 2 * (pos_a or pos_b) except TypeError: _a = a _b = b @@ -48,6 +48,7 @@ def gcd(a, b): else: return gcd_sgn * gcd(min(_a, _b), c) + def lcm(a, b): """Compute lcm(a,b) @@ -69,7 +70,8 @@ def lcm(a, b): """ return (a * b) // gcd(a, b) -if __name__ == '__main__': + +if __name__ == "__main__": print(gcd(3, 15)) print(gcd(3, 15)) print(gcd(-15, -3)) diff --git a/mapytex/calculus/core/compute/__init__.py b/mapytex/calculus/core/compute/__init__.py index 69b0a54..b764ffb 100644 --- a/mapytex/calculus/core/compute/__init__.py +++ b/mapytex/calculus/core/compute/__init__.py @@ -25,15 +25,10 @@ from ..MO.polynomial import MOpolynomial from itertools import product from tabulate import tabulate -MOS = [ MOnumber, MOstr, MOFraction, MOstrPower, MOMonomial, MOpolynomial] +MOS = [MOnumber, MOstr, MOFraction, MOstrPower, MOMonomial, MOpolynomial] + +OPERATIONS = {"+": add, "-": minus, "*": multiply, "/": divide, "^": power} -OPERATIONS = { - "+": add, - "-": minus, - "*": multiply, - "/": divide, - "^": power, - } def compute(node, left_v, right_v): """ @@ -60,6 +55,7 @@ def compute(node, left_v, right_v): return operation(left_v, right_v) + def compute_capacities(node): """ Test an operation through all MOs @@ -72,21 +68,19 @@ def compute_capacities(node): """ op = OPERATIONS[node] - lines = [[node] + [mo.__name__ for mo in MOS]] + lines = [[node] + [mo.__name__ for mo in MOS]] for left_mo in MOS: - lines.append( - [left_mo.__name__] + \ - [(left_mo, i) in op.funcs for i in MOS] - ) + lines.append([left_mo.__name__] + [(left_mo, i) in op.funcs for i in MOS]) return lines + def describe_compute(): """ Explain which operation are handle by compue """ ans = "Implemented compute operations among MOs" for op in OPERATIONS: ans += "\n" - ans += tabulate(compute_capacities(op), tablefmt='grid') + ans += tabulate(compute_capacities(op), tablefmt="grid") return ans diff --git a/mapytex/calculus/core/compute/add.py b/mapytex/calculus/core/compute/add.py index 9569ddc..db0c0be 100644 --- a/mapytex/calculus/core/compute/add.py +++ b/mapytex/calculus/core/compute/add.py @@ -29,6 +29,7 @@ add_doc = """ Adding MOs add = Dispatcher("add", doc=add_doc) + def add_filter(left, right): """ Automatic add on MO @@ -59,6 +60,7 @@ def add_filter(left, right): except AttributeError: pass + @add.register(MOnumber, MOnumber) @special_case(add_filter) def monumber_monumber(left, right): @@ -72,6 +74,7 @@ def monumber_monumber(left, right): """ return MO.factory(left.value + right.value) + @add.register(MOnumber, MOFraction) @special_case(add_filter) def monumber_mofraction(left, right): @@ -87,6 +90,7 @@ def monumber_mofraction(left, right): left_fraction = MOFraction(left, MOnumber(1)) return Tree("+", left_fraction, right) + @add.register(MOFraction, MOnumber) @special_case(add_filter) def mofraction_monumber(left, right): @@ -103,6 +107,7 @@ def mofraction_monumber(left, right): right_fraction = MOFraction(right, MOnumber(1)) return Tree("+", left, right_fraction) + @add.register(MOFraction, MOFraction) @special_case(add_filter) def mofraction_mofraction(left, right): @@ -200,6 +205,7 @@ def mofraction_mofraction(left, right): return Tree("+", left_frac, right_frac) + @add.register(MOstr, MOstr) @special_case(add_filter) def mostr_mostr(left, right): @@ -215,6 +221,7 @@ def mostr_mostr(left, right): raise NotImplementedError("Can't add 2 MOstr with not same letter") return MOMonomial(2, left) + @add.register(MOstrPower, MOstrPower) @special_case(add_filter) def mostrpower_mostrpower(left, right): @@ -230,6 +237,7 @@ def mostrpower_mostrpower(left, right): raise NotImplementedError("Can't add 2 MOstrPower with not same power") return MOMonomial(2, left.variable, left.power) + @add.register((MOnumber, MOFraction), MOpolynomial) @special_case(add_filter) def moscalar_mopolynomial(left, right): @@ -254,7 +262,8 @@ def moscalar_mopolynomial(left, right): right_top = [mo for deg, mo in right.monomials.items() if deg > 0][::-1] adds = right_top + [Tree("+", left, right_const)] - return Tree.from_list('+', adds) + return Tree.from_list("+", adds) + @add.register(MOpolynomial, (MOnumber, MOFraction)) @special_case(add_filter) @@ -280,7 +289,8 @@ def mopolynomial_moscalar(left, right): left_top = [mo for deg, mo in left.monomials.items() if deg > 0][::-1] adds = left_top + [Tree("+", left_const, right)] - return Tree.from_list('+', adds) + return Tree.from_list("+", adds) + @add.register(MOstr, MOpolynomial) @special_case(add_filter) @@ -313,6 +323,7 @@ def mostr_mopolynomial(left, right): return Tree.from_list("+", adds) + @add.register(MOpolynomial, MOstr) @special_case(add_filter) def mopolynomial_mostr(left, right): @@ -344,6 +355,7 @@ def mopolynomial_mostr(left, right): return Tree.from_list("+", adds) + @add.register(MOstrPower, MOpolynomial) @special_case(add_filter) def mostrpower_mopolynomial(left, right): @@ -387,6 +399,7 @@ def mostrpower_mopolynomial(left, right): return Tree.from_list("+", adds) + @add.register(MOpolynomial, MOstrPower) @special_case(add_filter) def mopolynomial_mostrpower(left, right): @@ -431,6 +444,7 @@ def mopolynomial_mostrpower(left, right): return Tree.from_list("+", adds) + @add.register(MOMonomial, MOpolynomial) @special_case(add_filter) def momonomial_mopolynomial(left, right): @@ -474,6 +488,7 @@ def momonomial_mopolynomial(left, right): return Tree.from_list("+", adds) + @add.register(MOpolynomial, MOMonomial) @special_case(add_filter) def mopolynomial_momonomial(left, right): @@ -517,6 +532,7 @@ def mopolynomial_momonomial(left, right): return Tree.from_list("+", adds) + @add.register(MOpolynomial, MOpolynomial) @special_case(add_filter) def mopolynomial_mopolynomial(left, right): @@ -563,7 +579,7 @@ def mopolynomial_mopolynomial(left, right): | > 2 """ - common_degree = set(left.monomials.keys()).intersection(right.monomials.keys()) + common_degree = set(left.monomials.keys()).intersection(right.monomials.keys()) if not common_degree: raise NotImplementedError("No degree in common, no calculus to do") @@ -573,6 +589,7 @@ def mopolynomial_mopolynomial(left, right): return Tree.from_list("+", list(merge_monomials.values())[::-1]) + @add.register(MOstr, MOMonomial) @special_case(add_filter) def mostr_momonomial(left, right): @@ -593,6 +610,7 @@ def mostr_momonomial(left, right): add_scal = Tree("+", 1, right.coefficient) return Tree("*", add_scal, left) + @add.register(MOMonomial, MOstr) @special_case(add_filter) def momonomial_mostr(left, right): @@ -613,6 +631,7 @@ def momonomial_mostr(left, right): add_scal = Tree("+", left.coefficient, 1) return Tree("*", add_scal, right) + @add.register(MOstrPower, MOMonomial) @special_case(add_filter) def mostrpower_momonomial(left, right): @@ -633,6 +652,7 @@ def mostrpower_momonomial(left, right): add_scal = Tree("+", 1, right.coefficient) return Tree("*", add_scal, left) + @add.register(MOMonomial, MOstrPower) @special_case(add_filter) def momonomial_mostrpower(left, right): @@ -653,6 +673,7 @@ def momonomial_mostrpower(left, right): add_scal = Tree("+", left.coefficient, 1) return Tree("*", add_scal, right) + @add.register(MOMonomial, MOMonomial) @special_case(add_filter) def momonomial_momonomial(left, right): diff --git a/mapytex/calculus/core/compute/divide.py b/mapytex/calculus/core/compute/divide.py index a9a65f7..d61321e 100644 --- a/mapytex/calculus/core/compute/divide.py +++ b/mapytex/calculus/core/compute/divide.py @@ -28,6 +28,7 @@ divide_doc = """ Dividing MOs divide = Dispatcher("divide", doc=divide_doc) + def divide_filter(left, right): """ Automatic divide on MO @@ -62,6 +63,7 @@ def divide_filter(left, right): except TypeError: pass + @divide.register(MOnumber, MOnumber) @special_case(divide_filter) def monumber_monumber(left, right): @@ -78,11 +80,13 @@ def monumber_monumber(left, right): ... NotImplementedError: Can't divide 2 int. Need to create a Fraction instead """ - if type(left.value) in [float, Decimal] or \ - type(right.value) in [float, Decimal]: + if type(left.value) in [float, Decimal] or type(right.value) in [float, Decimal]: return MO.factory(left.value / right.value) else: - raise NotImplementedError("Can't divide 2 int. Need to create a Fraction instead") + raise NotImplementedError( + "Can't divide 2 int. Need to create a Fraction instead" + ) + @divide.register(MOnumber, MOFraction) @special_case(divide_filter) @@ -103,6 +107,7 @@ def monumber_mofraction(left, right): """ return Tree("*", left, right.inverse()) + @divide.register(MOFraction, MOnumber) @special_case(divide_filter) def mofraction_monumber(left, right): @@ -119,6 +124,7 @@ def mofraction_monumber(left, right): right_fraction = MOFraction(MOnumber(1), right) return Tree("*", left, right_fraction) + @divide.register(MOFraction, MOFraction) @special_case(divide_filter) def mofraction_mofraction(left, right): @@ -134,6 +140,7 @@ def mofraction_mofraction(left, right): """ return Tree("*", left, right.inverse()) + # ----------------------------- # Reglages pour 'vim' # vim:set autoindent expandtab tabstop=4 shiftwidth=4: diff --git a/mapytex/calculus/core/compute/exceptions.py b/mapytex/calculus/core/compute/exceptions.py index e980ea5..7d554c4 100644 --- a/mapytex/calculus/core/compute/exceptions.py +++ b/mapytex/calculus/core/compute/exceptions.py @@ -10,18 +10,23 @@ Exceptions for computing """ + class ComputeError(Exception): pass + class AddError(ComputeError): pass + class MinusError(ComputeError): pass + class MultiplyError(ComputeError): pass + class DivideError(ComputeError): pass diff --git a/mapytex/calculus/core/compute/filters.py b/mapytex/calculus/core/compute/filters.py index fd4a2c8..41fad56 100644 --- a/mapytex/calculus/core/compute/filters.py +++ b/mapytex/calculus/core/compute/filters.py @@ -13,6 +13,7 @@ Decorator to filter MO before operate from functools import wraps from .exceptions import ComputeError + def args_are(left_type, right_type): """ Decorator which filter arguments type @@ -21,21 +22,27 @@ def args_are(left_type, right_type): :returns: a decorator which will allow only some type """ + def type_filter(func): @wraps(func) def filtered_func(left, right): if not isinstance(left, left_type): - raise ComputeError("Wrong type for left argument" - f"Require {left_type}, got {left.__class__.__name__}" - ) + raise ComputeError( + "Wrong type for left argument" + f"Require {left_type}, got {left.__class__.__name__}" + ) if not isinstance(right, right_type): - raise ComputeError("Wrong type for right argument" - f"Require {right_type}, got {right.__class__.__name__}" - ) + raise ComputeError( + "Wrong type for right argument" + f"Require {right_type}, got {right.__class__.__name__}" + ) return func(left, right) + return filtered_func + return type_filter + def special_case(filter): """ Decorate operation to filter special cases before call the function @@ -43,6 +50,7 @@ def special_case(filter): :returns: decorator """ + def decorator(func): @wraps(func) def _func(left, right): @@ -50,9 +58,12 @@ def special_case(filter): if ans is None: return func(left, right) return ans + return _func + return decorator + # ----------------------------- # Reglages pour 'vim' # vim:set autoindent expandtab tabstop=4 shiftwidth=4: diff --git a/mapytex/calculus/core/compute/minus.py b/mapytex/calculus/core/compute/minus.py index 95aef90..1e8f6b5 100644 --- a/mapytex/calculus/core/compute/minus.py +++ b/mapytex/calculus/core/compute/minus.py @@ -28,6 +28,7 @@ minus_doc = """ Opposite of a MO minus = Dispatcher("minus", doc=minus_doc) + @minus.register(type(None), MOnumber) def monumber(_, right): """ @@ -37,7 +38,8 @@ def monumber(_, right): """ - return MO.factory(- right.value) + return MO.factory(-right.value) + @minus.register(type(None), MOFraction) def mofraction(_, right): @@ -84,6 +86,7 @@ def mofraction(_, right): return MOFraction(right._numerator, right._denominator, True) + @minus.register(type(None), MOstr) def mostr(_, right): """ Opposite of 'x' is '-x' @@ -95,6 +98,7 @@ def mostr(_, right): """ return MOMonomial(-1, right) + @minus.register(type(None), MOstrPower) def mostrpower(_, right): """ Opposite of 'x^n' is '-x^n' @@ -106,6 +110,7 @@ def mostrpower(_, right): """ return MOMonomial(-1, right.variable, right.power) + @minus.register(type(None), MOMonomial) def momonomial(_, right): """ Opposite of 'ax^n' is '-ax^n' @@ -121,6 +126,7 @@ def momonomial(_, right): coef = Tree("-", None, right.coefficient) return Tree("*", coef, right.strpower) + @minus.register(type(None), MOpolynomial) def mopolynomial(_, right): """ Opposite of a polynomial @@ -133,6 +139,7 @@ def mopolynomial(_, right): neg_coefs = {p: -c.value for (p, c) in right.coefficients.items()} return MOpolynomial(right.variable, neg_coefs) + # ----------------------------- # Reglages pour 'vim' # vim:set autoindent expandtab tabstop=4 shiftwidth=4: diff --git a/mapytex/calculus/core/compute/multiply.py b/mapytex/calculus/core/compute/multiply.py index 586a28a..880439c 100644 --- a/mapytex/calculus/core/compute/multiply.py +++ b/mapytex/calculus/core/compute/multiply.py @@ -28,6 +28,7 @@ multiply_doc = """ Multiply MOs multiply = Dispatcher("multiply", doc=multiply_doc) + def multiply_filter(left, right): """ Automatic multiply on MO @@ -68,6 +69,7 @@ def multiply_filter(left, right): except TypeError: pass + @multiply.register(MOnumber, MOnumber) @special_case(multiply_filter) def monumber_monumber(left, right): @@ -81,6 +83,7 @@ def monumber_monumber(left, right): """ return MO.factory(left.value * right.value) + @multiply.register(MOnumber, MOFraction) @special_case(multiply_filter) def monumber_mofraction(left, right): @@ -108,6 +111,7 @@ def monumber_mofraction(left, right): num = Tree("*", left, right.numerator) return Tree("/", num, right._denominator) + @multiply.register(MOFraction, MOnumber) @special_case(multiply_filter) def mofraction_monumber(left, right): @@ -125,6 +129,7 @@ def mofraction_monumber(left, right): num = Tree("*", left.numerator, right) return Tree("/", num, left._denominator) + @multiply.register(MOFraction, MOFraction) @special_case(multiply_filter) def mofraction_mofraction(left, right): @@ -145,6 +150,7 @@ def mofraction_mofraction(left, right): denom = Tree("*", left.denominator, right.denominator) return Tree("/", num, denom) + @multiply.register((MOnumber, MOFraction), MOMonomial) @special_case(multiply_filter) def moscalar_monomonial(left, right): @@ -161,8 +167,9 @@ def moscalar_monomonial(left, right): > x^4 """ - coefficient = Tree('*', left, right.coefficient) - return Tree('*', coefficient, right.strpower) + coefficient = Tree("*", left, right.coefficient) + return Tree("*", coefficient, right.strpower) + @multiply.register(MOMonomial, (MOnumber, MOFraction)) @special_case(multiply_filter) @@ -180,8 +187,9 @@ def monomonial_moscalar(left, right): > x^4 """ - coefficient = Tree('*', right, left.coefficient) - return Tree('*', coefficient, left.strpower) + coefficient = Tree("*", right, left.coefficient) + return Tree("*", coefficient, left.strpower) + @multiply.register(MOstr, MOstrPower) @special_case(multiply_filter) @@ -200,9 +208,12 @@ def mostr_mostrpower(left, right): NotImplementedError: Can't multiply MOstr and MOstrPower if they don'thave same variable (got x and y) """ if left.variable != right.variable: - raise NotImplementedError("Can't multiply MOstr and MOstrPower if they don't" - f"have same variable (got {left.variable} and {right.variable})") - return MOstrPower(left.variable, right.power.value+1) + raise NotImplementedError( + "Can't multiply MOstr and MOstrPower if they don't" + f"have same variable (got {left.variable} and {right.variable})" + ) + return MOstrPower(left.variable, right.power.value + 1) + @multiply.register(MOstrPower, MOstr) @special_case(multiply_filter) @@ -221,9 +232,12 @@ def mostr_mostrpower(left, right): NotImplementedError: Can't multiply MOstr and MOstrPower if they don'thave same variable (got x and y) """ if left.variable != right.variable: - raise NotImplementedError("Can't multiply MOstr and MOstrPower if they don't" - f"have same variable (got {left.variable} and {right.variable})") - return MOstrPower(left.variable, left.power.value+1) + raise NotImplementedError( + "Can't multiply MOstr and MOstrPower if they don't" + f"have same variable (got {left.variable} and {right.variable})" + ) + return MOstrPower(left.variable, left.power.value + 1) + @multiply.register(MOstr, MOstr) @special_case(multiply_filter) @@ -243,10 +257,13 @@ def mostr_mostr(left, right): NotImplementedError: Can't multiply MOstr and MOstr if they don'thave same variable (got y and x) """ if left.variable != right.variable: - raise NotImplementedError("Can't multiply MOstr and MOstr if they don't" - f"have same variable (got {left.variable} and {right.variable})") + raise NotImplementedError( + "Can't multiply MOstr and MOstr if they don't" + f"have same variable (got {left.variable} and {right.variable})" + ) return MOstrPower(left.variable, 2) + @multiply.register(MOstrPower, MOstrPower) @special_case(multiply_filter) def mostr_mostrpower(left, right): @@ -268,11 +285,14 @@ def mostr_mostrpower(left, right): NotImplementedError: Can't multiply MOstrPower and MOstrPower if they don'thave same variable (got x and y) """ if left.variable != right.variable: - raise NotImplementedError("Can't multiply MOstrPower and MOstrPower if they don't" - f"have same variable (got {left.variable} and {right.variable})") + raise NotImplementedError( + "Can't multiply MOstrPower and MOstrPower if they don't" + f"have same variable (got {left.variable} and {right.variable})" + ) power = Tree("+", left.power, right.power) return Tree("^", left.variable, power) + @multiply.register(MOstrPower, MOMonomial) @special_case(multiply_filter) def mostrpower_momonomial(left, right): @@ -296,12 +316,15 @@ def mostrpower_momonomial(left, right): NotImplementedError: Can't multiply MOstrPower and Monomial if they don'thave same variable (got x and y) """ if left.variable != right.variable: - raise NotImplementedError("Can't multiply MOstrPower and Monomial if they don't" - f"have same variable (got {left.variable} and {right.variable})") + raise NotImplementedError( + "Can't multiply MOstrPower and Monomial if they don't" + f"have same variable (got {left.variable} and {right.variable})" + ) power = Tree("+", left.power, right.power) monome = Tree("^", left.variable, power) return Tree("*", right.coefficient, monome) + @multiply.register(MOMonomial, MOstrPower) @special_case(multiply_filter) def momonomial_mostr(left, right): @@ -326,12 +349,15 @@ def momonomial_mostr(left, right): """ if left.variable != right.variable: - raise NotImplementedError("Can't multiply MOstrPower and Monomial if they don't" - f"have same variable (got {left.variable} and {right.variable})") + raise NotImplementedError( + "Can't multiply MOstrPower and Monomial if they don't" + f"have same variable (got {left.variable} and {right.variable})" + ) power = Tree("+", left.power, right.power) monome = Tree("^", left.variable, power) return Tree("*", left.coefficient, monome) + @multiply.register(MOstr, MOMonomial) @special_case(multiply_filter) def mostr_momonomial(left, right): @@ -349,9 +375,12 @@ def mostr_momonomial(left, right): NotImplementedError: Can't multiply MOstr and Monomial if they don'thave same variable (got x and y) """ if left.variable != right.variable: - raise NotImplementedError("Can't multiply MOstr and Monomial if they don't" - f"have same variable (got {left.variable} and {right.variable})") - return MOMonomial(right.coefficient, right.variable, right.power.value+1) + raise NotImplementedError( + "Can't multiply MOstr and Monomial if they don't" + f"have same variable (got {left.variable} and {right.variable})" + ) + return MOMonomial(right.coefficient, right.variable, right.power.value + 1) + @multiply.register(MOMonomial, MOstr) @special_case(multiply_filter) @@ -371,9 +400,12 @@ def momonomial_mostr(left, right): """ if left.variable != right.variable: - raise NotImplementedError("Can't multiply MOstr and Monomial if they don't" - f"have same variable (got {left.variable} and {right.variable})") - return MOMonomial(left.coefficient, left.variable, left.power.value+1) + raise NotImplementedError( + "Can't multiply MOstr and Monomial if they don't" + f"have same variable (got {left.variable} and {right.variable})" + ) + return MOMonomial(left.coefficient, left.variable, left.power.value + 1) + @multiply.register(MOMonomial, MOMonomial) @special_case(multiply_filter) @@ -401,15 +433,17 @@ def momonomial_momonomial(left, right): """ if left.variable != right.variable: - raise NotImplementedError("Can't multiply MOMonomial and Monomial if they don't" - f"have same variable (got {left.variable} and {right.variable})") + raise NotImplementedError( + "Can't multiply MOMonomial and Monomial if they don't" + f"have same variable (got {left.variable} and {right.variable})" + ) powers = Tree("+", left.power, right.power) monome = Tree("^", left.variable, powers) coefs = Tree("*", left.coefficient, right.coefficient) return Tree("*", coefs, monome) -@multiply.register((MOnumber, MOFraction, MOstr, MOstrPower, MOMonomial), \ - MOpolynomial) + +@multiply.register((MOnumber, MOFraction, MOstr, MOstrPower, MOMonomial), MOpolynomial) @special_case(multiply_filter) def lotsmo_mopolynomial(left, right): """ Multiply a scalar and a MOMonomial @@ -492,13 +526,11 @@ def lotsmo_mopolynomial(left, right): """ - coefs = [Tree("*", left, monom) \ - for monom in list(right.monomials.values())[::-1]\ - ] + coefs = [Tree("*", left, monom) for monom in list(right.monomials.values())[::-1]] return Tree.from_list("+", coefs) -@multiply.register(MOpolynomial, \ - (MOnumber, MOFraction, MOstr, MOstrPower, MOMonomial)) + +@multiply.register(MOpolynomial, (MOnumber, MOFraction, MOstr, MOstrPower, MOMonomial)) @special_case(multiply_filter) def mopolynomial_lotsmo(left, right): """ Multiply a MOpolynomial with nearly everything @@ -581,11 +613,10 @@ def mopolynomial_lotsmo(left, right): | | > 3x^2 """ - coefs = [Tree("*", monom, right) \ - for monom in list(left.monomials.values())[::-1] \ - ] + coefs = [Tree("*", monom, right) for monom in list(left.monomials.values())[::-1]] return Tree.from_list("+", coefs) + @multiply.register(MOpolynomial, MOpolynomial) @special_case(multiply_filter) def mopolynomial_mopolynomial(left, right): @@ -619,10 +650,11 @@ def mopolynomial_mopolynomial(left, right): | | | > 4 """ - coefs = [Tree("*", l_monom, r_monom) \ - for l_monom in list(left.monomials.values())[::-1] \ - for r_monom in list(right.monomials.values())[::-1] \ - ] + coefs = [ + Tree("*", l_monom, r_monom) + for l_monom in list(left.monomials.values())[::-1] + for r_monom in list(right.monomials.values())[::-1] + ] return Tree.from_list("+", coefs) diff --git a/mapytex/calculus/core/compute/power.py b/mapytex/calculus/core/compute/power.py index a57e287..cae5723 100644 --- a/mapytex/calculus/core/compute/power.py +++ b/mapytex/calculus/core/compute/power.py @@ -28,6 +28,7 @@ power_doc = """ Power of MOs power = Dispatcher("power", doc=power_doc) + def power_filter(left, right): """ Automatic power on MO @@ -60,6 +61,7 @@ def power_filter(left, right): except TypeError: pass + @power.register(MOnumber, MOnumber) @special_case(power_filter) def monumber_monumber(left, right): @@ -73,6 +75,7 @@ def monumber_monumber(left, right): """ return MO.factory(left.value ** right.value) + @power.register(MOFraction, MOnumber) @special_case(power_filter) def mofraction_monumber(left, right): @@ -93,6 +96,7 @@ def mofraction_monumber(left, right): denom = Tree("^", left.denominator, right) return Tree("/", num, denom) + @power.register(MOstrPower, MOnumber) @special_case(power_filter) def mostrpower_monumber(left, right): @@ -110,6 +114,7 @@ def mostrpower_monumber(left, right): power = Tree("*", left.power, right) return Tree("^", left.variable, power) + @power.register(MOMonomial, MOnumber) @special_case(power_filter) def mostrpower_monumber(left, right): @@ -133,6 +138,7 @@ def mostrpower_monumber(left, right): strpower = Tree("^", left.variable, power) return Tree("*", coef, strpower) + @power.register(MOpolynomial, MOnumber) @special_case(power_filter) def mopolynomial_monumber(left, right): @@ -145,8 +151,7 @@ def mopolynomial_monumber(left, right): > 3x^2 - 2x + 1 > 3x^2 - 2x + 1 """ - return Tree.from_list("*", [left]*right.value) - + return Tree.from_list("*", [left] * right.value) # ----------------------------- diff --git a/mapytex/calculus/core/coroutine.py b/mapytex/calculus/core/coroutine.py index b0e54fd..a485a7a 100644 --- a/mapytex/calculus/core/coroutine.py +++ b/mapytex/calculus/core/coroutine.py @@ -14,17 +14,23 @@ from functools import wraps __all__ = ["coroutine", "STOOOP", "RESTAAART"] + def coroutine(func): @wraps(func) def start(*args, **kwargs): cr = func(*args, **kwargs) next(cr) return cr + return start -class STOOOP(Exception): pass -class RESTAAART(Exception): pass +class STOOOP(Exception): + pass + + +class RESTAAART(Exception): + pass # ----------------------------- diff --git a/mapytex/calculus/core/operator.py b/mapytex/calculus/core/operator.py index c3d9fc9..fabb95b 100644 --- a/mapytex/calculus/core/operator.py +++ b/mapytex/calculus/core/operator.py @@ -8,32 +8,20 @@ __all__ = ["OperatorError", "OPERATORS", "is_operator"] + class OperatorError(Exception): pass + OPERATORS = { - "+": {'repr': "+", - 'arity': 2, - 'precedence': 0, - }, - "-": {'repr': "-", - 'arity': 1, - 'precedence': 1, - }, - "*": {'repr': "*", - 'arity': 2, - 'precedence': 2, - }, - "/": {'repr': "/", - 'arity': 2, - 'precedence': 3, - }, - "^": {'repr': "^", - 'arity': 2, - 'precedence': 4, - }, + "+": {"repr": "+", "arity": 2, "precedence": 0}, + "-": {"repr": "-", "arity": 1, "precedence": 1}, + "*": {"repr": "*", "arity": 2, "precedence": 2}, + "/": {"repr": "/", "arity": 2, "precedence": 3}, + "^": {"repr": "^", "arity": 2, "precedence": 4}, } + def is_operator(string): """ Return whether a string is an operator or not diff --git a/mapytex/calculus/core/random/int_gene.py b/mapytex/calculus/core/random/int_gene.py index 79d01cb..b33d40b 100644 --- a/mapytex/calculus/core/random/int_gene.py +++ b/mapytex/calculus/core/random/int_gene.py @@ -14,11 +14,8 @@ import random __all__ = ["reject_random", "filter_random", "FilterRandom"] -def reject_random(min_value = -10, - max_value = 10, - rejected = [0, 1], - accept_callbacks=[], - ): + +def reject_random(min_value=-10, max_value=10, rejected=[0, 1], accept_callbacks=[]): """ Generate a random integer with the rejection method :param name: name of the Integer @@ -61,11 +58,8 @@ def reject_random(min_value = -10, return candidate -def filter_random(min_value = -10, - max_value = 10, - rejected = [0, 1], - accept_callbacks=[], - ): + +def filter_random(min_value=-10, max_value=10, rejected=[0, 1], accept_callbacks=[]): """ Generate a random integer by filtering then choosing a candidate :param name: name of the Integer @@ -99,37 +93,44 @@ def filter_random(min_value = -10, >>> filter_random() 6 """ - candidates = set(range(min_value, max_value+1)) + candidates = set(range(min_value, max_value + 1)) candidates = {c for c in candidates if c not in rejected} - candidates = [candidate for candidate in candidates \ - if all(c(candidate) for c in accept_callbacks)] + candidates = [ + candidate + for candidate in candidates + if all(c(candidate) for c in accept_callbacks) + ] if len(candidates) == 0: - raise OverflowError("There is no candidates for this range and those conditions") + raise OverflowError( + "There is no candidates for this range and those conditions" + ) return random.choice(candidates) + class FilterRandom(object): """ Integer random generator which filter then choose candidate """ + # TODO: Faire un cache pour éviter de reconstruire les listes à chaque fois |ven. déc. 21 19:07:42 CET 2018 - def __init__(self, - rejected = [0, 1], - accept_callbacks=[], - min_value = -10, - max_value = 10, - ): + def __init__( + self, rejected=[0, 1], accept_callbacks=[], min_value=-10, max_value=10 + ): self.conditions = (lambda x: x not in rejected,) + tuple(accept_callbacks) self._min = min_value self._max = max_value - candidates = set(range(self._min, self._max+1)) + candidates = set(range(self._min, self._max + 1)) - self._candidates = { candidate for candidate in candidates \ - if all(c(candidate) for c in self.conditions) } + self._candidates = { + candidate + for candidate in candidates + if all(c(candidate) for c in self.conditions) + } def add_candidates(self, low, high): """ Add candidates between low and high to _candidates """ @@ -144,13 +145,16 @@ class FilterRandom(object): else: useless_high = True - if not(useless_low and useless_high): - candidates = set(range(low, high+1)) + if not (useless_low and useless_high): + candidates = set(range(low, high + 1)) - self._candidates = self._candidates.union({ - candidate for candidate in candidates \ - if all(c(candidate) for c in self.conditions) \ - }) + self._candidates = self._candidates.union( + { + candidate + for candidate in candidates + if all(c(candidate) for c in self.conditions) + } + ) def candidates(self, min_value=-10, max_value=10): """ Return candidates between min_value and max_value """ diff --git a/mapytex/calculus/core/renders/tree2tex.py b/mapytex/calculus/core/renders/tree2tex.py index 8643303..84d41d5 100644 --- a/mapytex/calculus/core/renders/tree2tex.py +++ b/mapytex/calculus/core/renders/tree2tex.py @@ -8,7 +8,8 @@ from mapytex.calculus.core.operator import OPERATORS -__all__ = ['tree2tex'] +__all__ = ["tree2tex"] + def plus2tex(left, right): r""" + rendering @@ -51,6 +52,7 @@ def plus2tex(left, right): return f"{left_} {right_}" + def minus2tex(left, right): r""" - rendering @@ -64,7 +66,7 @@ def minus2tex(left, right): """ try: right_need_parenthesis = False - if OPERATORS[right.node]["precedence"] < OPERATORS['-']["precedence"]: + if OPERATORS[right.node]["precedence"] < OPERATORS["-"]["precedence"]: right_need_parenthesis = True except AttributeError: right_ = right.__tex__ @@ -76,6 +78,7 @@ def minus2tex(left, right): return f"- {right_}" + def mul2tex(left, right): r""" * rendering @@ -101,14 +104,16 @@ def mul2tex(left, right): right_ = render_with_parenthesis(right, "*") display_time = True - if (right_[0].isalpha() and (left_.isnumeric() or left_.isdecimal())) or \ - right_[0] == '(': - display_time = False + if (right_[0].isalpha() and (left_.isnumeric() or left_.isdecimal())) or right_[ + 0 + ] == "(": + display_time = False if display_time: return f"{left_} \\times {right_}" return f"{left_}{right_}" + def div2tex(left, right): r""" / rendering @@ -137,6 +142,7 @@ def div2tex(left, right): return "\\frac{" + left_ + "}{" + right_ + "}" + def pow2tex(left, right): r""" ^ rendering @@ -159,7 +165,7 @@ def pow2tex(left, right): """ try: left_need_parenthesis = False - if OPERATORS[left.node]["precedence"] < OPERATORS['^']["precedence"]: + if OPERATORS[left.node]["precedence"] < OPERATORS["^"]["precedence"]: left_need_parenthesis = True except AttributeError: left_ = left.__tex__ @@ -185,7 +191,10 @@ def render_with_parenthesis(subtree, operator): subtree.node except AttributeError: try: - if OPERATORS[subtree.MAINOP]["precedence"] < OPERATORS[operator]["precedence"]: + if ( + OPERATORS[subtree.MAINOP]["precedence"] + < OPERATORS[operator]["precedence"] + ): subtree_need_parenthesis = True except (AttributeError, KeyError): pass @@ -200,13 +209,8 @@ def render_with_parenthesis(subtree, operator): return subtree_ -OPERATOR2TEX = { - "+": plus2tex, - "-": minus2tex, - "*": mul2tex, - "/": div2tex, - "^": pow2tex, -} +OPERATOR2TEX = {"+": plus2tex, "-": minus2tex, "*": mul2tex, "/": div2tex, "^": pow2tex} + def tree2tex(tree): r""" Convert a tree into its tex version diff --git a/mapytex/calculus/core/renders/tree2txt.py b/mapytex/calculus/core/renders/tree2txt.py index 680bac3..a58cc62 100644 --- a/mapytex/calculus/core/renders/tree2txt.py +++ b/mapytex/calculus/core/renders/tree2txt.py @@ -8,7 +8,8 @@ from ..operator import OPERATORS -__all__ = ['tree2txt'] +__all__ = ["tree2txt"] + def plus2txt(left, right): """ + rendering @@ -41,6 +42,7 @@ def plus2txt(left, right): return f"{left_} {right_}" + def minus2txt(left, right): """ - rendering @@ -54,7 +56,7 @@ def minus2txt(left, right): """ try: right_need_parenthesis = False - if OPERATORS[right.node]["precedence"] < OPERATORS['-']["precedence"]: + if OPERATORS[right.node]["precedence"] < OPERATORS["-"]["precedence"]: right_need_parenthesis = True except AttributeError: right_ = right.__txt__ @@ -66,6 +68,7 @@ def minus2txt(left, right): return f"- {right_}" + def mul2txt(left, right): """ * rendering @@ -96,9 +99,9 @@ def mul2txt(left, right): if right_[0].isalpha(): # TODO: C'est bien beurk en dessous... |ven. déc. 21 12:03:07 CET 2018 - if type(left).__name__ == 'MOnumber': + if type(left).__name__ == "MOnumber": display_time = False - elif right_[0] == '(': + elif right_[0] == "(": display_time = False if display_time: @@ -106,6 +109,7 @@ def mul2txt(left, right): else: return f"{left_}{right_}" + def div2txt(left, right): """ / rendering @@ -125,7 +129,7 @@ def div2txt(left, right): """ try: left_need_parenthesis = False - if OPERATORS[left.node]["precedence"] < OPERATORS['/']["precedence"]: + if OPERATORS[left.node]["precedence"] < OPERATORS["/"]["precedence"]: left_need_parenthesis = True except AttributeError: left_ = left.__txt__ @@ -136,7 +140,7 @@ def div2txt(left, right): left_ = tree2txt(left) try: right_need_parenthesis = False - if OPERATORS[right.node]["precedence"] < OPERATORS['/']["precedence"]: + if OPERATORS[right.node]["precedence"] < OPERATORS["/"]["precedence"]: right_need_parenthesis = True except AttributeError: right_ = right.__txt__ @@ -148,6 +152,7 @@ def div2txt(left, right): return f"{left_} / {right_}" + def pow2txt(left, right): """ ^ rendering @@ -169,7 +174,7 @@ def pow2txt(left, right): try: right_need_parenthesis = False - if OPERATORS[right.node]["precedence"] < OPERATORS['^']["precedence"]: + if OPERATORS[right.node]["precedence"] < OPERATORS["^"]["precedence"]: right_need_parenthesis = True except AttributeError: right_ = right.__txt__ @@ -181,13 +186,17 @@ def pow2txt(left, right): return f"{left_}^{right_}" + def render_with_parenthesis(subtree, operator): subtree_need_parenthesis = False try: subtree.node except AttributeError: try: - if OPERATORS[subtree.MAINOP]["precedence"] < OPERATORS[operator]["precedence"]: + if ( + OPERATORS[subtree.MAINOP]["precedence"] + < OPERATORS[operator]["precedence"] + ): subtree_need_parenthesis = True except (AttributeError, KeyError): pass @@ -201,13 +210,9 @@ def render_with_parenthesis(subtree, operator): return f"({subtree_})" return subtree_ -OPERATOR2TXT = { - "+": plus2txt, - "-": minus2txt, - "*": mul2txt, - "/": div2txt, - "^": pow2txt, -} + +OPERATOR2TXT = {"+": plus2txt, "-": minus2txt, "*": mul2txt, "/": div2txt, "^": pow2txt} + def tree2txt(tree): """ Convert a tree into its txt version @@ -224,6 +229,7 @@ def tree2txt(tree): '2 + 3 * 4' """ from ..tree import Tree + if not isinstance(tree, Tree): raise ValueError(f"Can only render a Tree (got {type(tree).__name__}: {tree})") return OPERATOR2TXT[tree.node](tree.left_value, tree.right_value) diff --git a/mapytex/calculus/core/str2.py b/mapytex/calculus/core/str2.py index 0630db0..7ba8772 100644 --- a/mapytex/calculus/core/str2.py +++ b/mapytex/calculus/core/str2.py @@ -16,7 +16,8 @@ from .coroutine import * from .operator import is_operator from .MO import moify -__all__ = ["str2", ] +__all__ = ["str2"] + class ParsingError(Exception): pass @@ -44,6 +45,7 @@ def maybe_it_is(cara): >>> it_is_iuo("uo") False """ + def func(c): if c == cara: return True @@ -51,20 +53,25 @@ def maybe_it_is(cara): return "maybe" else: return False + return func + def something_in(cara_list): """ Return a function which sais whether a caracter is in cara_list or not """ + def func(c): if c in cara_list: return True else: return False + return func + @coroutine -def lookfor(condition, replace = lambda x:''.join(x)): +def lookfor(condition, replace=lambda x: "".join(x)): """ Sink which is looking for term and yield replace founded patern with the lenght of the accumulation. @@ -165,7 +172,7 @@ def lookfor(condition, replace = lambda x:''.join(x)): else: if c is not None: acc.append(c) - found = condition(''.join([str(i) for i in acc])) + found = condition("".join([str(i) for i in acc])) if found == "maybe": ans = "maybe" elif found: @@ -175,6 +182,7 @@ def lookfor(condition, replace = lambda x:''.join(x)): ans = False acc = [] + @coroutine def remember_lookfor(lookfor): """ Coroutine which remember sent value before the lookfor finds something @@ -235,8 +243,9 @@ def remember_lookfor(lookfor): acc.append(c) ans = False + @coroutine -def concurent_broadcast(target, lookfors = []): +def concurent_broadcast(target, lookfors=[]): """ Coroutine which broadcasts multiple lookfor coroutines and reinitializes them when one found something @@ -316,6 +325,7 @@ def concurent_broadcast(target, lookfors = []): target_.send(i) yield target_.throw(err) + @coroutine def missing_times(target): """ Coroutine which send a "*" when it's missing @@ -379,15 +389,14 @@ def missing_times(target): previous = None if isinstance(tok, str): - if tok == '(': + if tok == "(": target_.send("*") - elif not is_operator(tok) and tok != ')': + elif not is_operator(tok) and tok != ")": target_.send("*") - if isinstance(tok, int) or \ - (isinstance(tok, str) and \ - not is_operator(tok) and \ - not tok == '('): + if isinstance(tok, int) or ( + isinstance(tok, str) and not is_operator(tok) and not tok == "(" + ): previous = tok target_.send(tok) @@ -395,6 +404,7 @@ def missing_times(target): except STOOOP as err: yield target_.throw(err) + @coroutine def lookforNumbers(target): """ Coroutine which parse numbers @@ -467,12 +477,12 @@ def lookforNumbers(target): try: int(tok) except ValueError: - if tok == '.': + if tok == ".": if current.replace("-", "", 1).isdigit(): current += tok else: raise ParsingError(f"Can't build decimal with '{current}'") - elif tok == '-': + elif tok == "-": if current == "": current = tok elif current == ("("): @@ -489,13 +499,15 @@ def lookforNumbers(target): target_.send(typifiy_numbers(current)) except InvalidOperation: target_.send(current) - target_.send('+') + target_.send("+") current = tok else: if current == "": current = tok elif is_operator(current) and is_operator(tok): - raise ParsingError(f"Can't parse with 2 operators next to each other") + raise ParsingError( + f"Can't parse with 2 operators next to each other" + ) else: try: target_.send(typifiy_numbers(current)) @@ -522,6 +534,7 @@ def lookforNumbers(target): target_.send(current) yield target_.throw(err) + def typifiy_numbers(number): """ Transform a str number into a integer or a decimal """ try: @@ -529,6 +542,7 @@ def typifiy_numbers(number): except ValueError: return Decimal(number) + @coroutine def pparser(target): """ Parenthesis parser sink @@ -565,6 +579,7 @@ def pparser(target): except STOOOP as err: yield target_.throw(err) + @coroutine def list_sink(): """ Testing sink for coroutines @@ -588,6 +603,7 @@ def list_sink(): except STOOOP: yield ans + def str2(sink, convert_to_mo=True): """ Return a pipeline which parse an expression with the sink as an endpont @@ -776,13 +792,16 @@ def str2(sink, convert_to_mo=True): """ lfop = lookfor(is_operator) operator_corout = partial(concurent_broadcast, lookfors=[lfop]) + def pipeline(expression): if convert_to_mo: - str2_corout = lookforNumbers(operator_corout(missing_times(moify(pparser(sink))))) + str2_corout = lookforNumbers( + operator_corout(missing_times(moify(pparser(sink)))) + ) else: str2_corout = lookforNumbers(operator_corout(missing_times(pparser(sink)))) - for i in expression.replace(" ",""): + for i in expression.replace(" ", ""): str2_corout.send(i) a = str2_corout.throw(STOOOP) diff --git a/mapytex/calculus/core/tree.py b/mapytex/calculus/core/tree.py index 5a4f4d9..b7a1737 100644 --- a/mapytex/calculus/core/tree.py +++ b/mapytex/calculus/core/tree.py @@ -9,10 +9,7 @@ Tree class """ -from .tree_tools import (to_nested_parenthesis, - postfix_concatenate, - show_tree, - ) +from .tree_tools import to_nested_parenthesis, postfix_concatenate, show_tree from .coroutine import coroutine, STOOOP from .str2 import str2 from .operator import OPERATORS, is_operator @@ -20,7 +17,7 @@ from .operator import OPERATORS, is_operator __all__ = ["Tree", "MutableTree"] -class Tree(): +class Tree: """ Binary tree @@ -118,9 +115,8 @@ class Tree(): except TypeError: raise ValueError("Nested parenthesis are not composed of lists") - if nested_len != 2 and \ - num_len != 2: - raise ValueError("Nested parenthesis don't have right shape") + if nested_len != 2 and num_len != 2: + raise ValueError("Nested parenthesis don't have right shape") node = nested_parenthesis[0] @@ -185,8 +181,8 @@ class Tree(): l_value = leafs[0] r_value = cls.from_list(node, leafs[1:]) else: - l_value = cls.from_list(node, leafs[:len_leafs//2]) - r_value = cls.from_list(node, leafs[len_leafs//2:]) + l_value = cls.from_list(node, leafs[: len_leafs // 2]) + r_value = cls.from_list(node, leafs[len_leafs // 2 :]) return cls(node, l_value, r_value) @classmethod @@ -241,9 +237,10 @@ class Tree(): left_value = tree.left_value right_value = tree.right_value - if node is None or \ - right_value is None: - raise TypeError(f"Tree can't have empty node or leaf. Got node = {node} and right_value = {right_value}") + if node is None or right_value is None: + raise TypeError( + f"Tree can't have empty node or leaf. Got node = {node} and right_value = {right_value}" + ) try: left_value.IMLEAF @@ -336,16 +333,14 @@ class Tree(): left_is_leaf = 0 try: - left_applied = self.left_value.\ - apply_on_last_level(function) + left_applied = self.left_value.apply_on_last_level(function) except AttributeError: left_applied = self.left_value left_is_leaf = 1 right_is_leaf = 0 try: - right_applied = self.right_value.\ - apply_on_last_level(function) + right_applied = self.right_value.apply_on_last_level(function) except AttributeError: right_applied = self.right_value right_is_leaf = 1 @@ -401,7 +396,7 @@ class Tree(): except NotImplementedError: return Tree(self.node, left_value, right_value) - def get_leafs(self, callback=lambda x:x): + def get_leafs(self, callback=lambda x: x): """ Generator which yield all the leaf value of the tree. Callback act on every leaf. @@ -424,7 +419,7 @@ class Tree(): except AttributeError: yield callback(self.right_value) - def get_nodes(self, callback=lambda x:x): + def get_nodes(self, callback=lambda x: x): """ Generator which yield all nodes of the tree. Callback act on every nodes. @@ -653,7 +648,7 @@ class Tree(): else: return self.left_value - def balance(self, exclude_nodes = []): + def balance(self, exclude_nodes=[]): """ Recursively balance the tree without permutting different nodes :return: balanced tree @@ -836,22 +831,22 @@ class Tree(): except AttributeError: r_depth = 1 - if l_depth > r_depth+1 and\ - self.node == self.left_value.node and \ - self.node not in exclude_nodes: + if ( + l_depth > r_depth + 1 + and self.node == self.left_value.node + and self.node not in exclude_nodes + ): new_left = self.left_value.long_branch - new_right = Tree(self.node, - self.left_value.short_branch, - self.right_value) + new_right = Tree(self.node, self.left_value.short_branch, self.right_value) return Tree(self.node, new_left, new_right).balance(exclude_nodes) - if r_depth > l_depth+1 and\ - self.node == self.right_value.node and \ - self.node not in exclude_nodes: + if ( + r_depth > l_depth + 1 + and self.node == self.right_value.node + and self.node not in exclude_nodes + ): new_right = self.right_value.long_branch - new_left = Tree(self.node, - self.left_value, - self.right_value.short_branch) + new_left = Tree(self.node, self.left_value, self.right_value.short_branch) return Tree(self.node, new_left, new_right).balance(exclude_nodes) try: @@ -874,10 +869,8 @@ class MutableTree(Tree): It is used to build a new tree before fixing it into a Tree """ - def __init__(self, - node = None, - left_value = None, - right_value = None): + + def __init__(self, node=None, left_value=None, right_value=None): """ Initiate a tree with potentialy None values @@ -1024,7 +1017,10 @@ class MutableTree(Tree): try: ans.set_node(c) except ValueError: - if OPERATORS[c]["precedence"] > OPERATORS[ans.node]["precedence"]: + if ( + OPERATORS[c]["precedence"] + > OPERATORS[ans.node]["precedence"] + ): # the operation has to be done first if nested_tree is not None: b_tree = cls(c, nested_tree, None) @@ -1124,7 +1120,9 @@ class MutableTree(Tree): try: self.right_value.append(value) except AttributeError: - raise ValueError("The right branch is full, use append_top or append_bot") + raise ValueError( + "The right branch is full, use append_top or append_bot" + ) def append(self, value): """ Append the value at the bottom of the tree. @@ -1196,7 +1194,7 @@ class MutableTree(Tree): > None """ - #self_cp = MutableTree.from_any_tree(self) + # self_cp = MutableTree.from_any_tree(self) self_cp = MutableTree() self_cp.set_node(self.node) self_cp.set_left_value(self.left_value) @@ -1272,6 +1270,7 @@ class AssocialTree(Tree): """ Tree which concider every subtree with a node different from itself as a Leaf """ + def map_on_leaf(self, function): """ Map on leafs a function @@ -1492,10 +1491,9 @@ class AssocialTree(Tree): t = Tree.from_list(self.node, balanced_leafs) return t - def organise_by(self, - signature=lambda x: type(x), - recursive=True, - exclude_nodes=[]): + def organise_by( + self, signature=lambda x: type(x), recursive=True, exclude_nodes=[] + ): """ Reoganise AssocialTree base on self order and groups by signature :param signature: grouping function (default type) @@ -1648,11 +1646,11 @@ class AssocialTree(Tree): except AttributeError: return leaf - return AssocialTree.from_any_tree(tree).\ - map_on_leaf(contaminate_organise) + return AssocialTree.from_any_tree(tree).map_on_leaf(contaminate_organise) return tree + if __name__ == "__main__": a = MutableTree.from_str("(1+2)*3") print(a) diff --git a/mapytex/calculus/core/tree_tools.py b/mapytex/calculus/core/tree_tools.py index dbdf1aa..41d0696 100644 --- a/mapytex/calculus/core/tree_tools.py +++ b/mapytex/calculus/core/tree_tools.py @@ -17,6 +17,7 @@ __all__ = [] # Functions on (op, left, right) + def to_nested_parenthesis(op, left, right): """ Get nested form for arguments @@ -27,6 +28,7 @@ def to_nested_parenthesis(op, left, right): """ return (op, (left, right)) + def infix_str_concatenate(op, left, right): """ Concatenate arguments placing op on the middle. @@ -37,6 +39,7 @@ def infix_str_concatenate(op, left, right): """ return f"{left} {op} {right}" + def postfix_concatenate(op, left, right): """ Concatenate arguments placing op on the middle. @@ -61,6 +64,7 @@ def postfix_concatenate(op, left, right): return left_tokens + right_tokens + [op] + def show_tree(op, left, right, sep="|", node_caracter=">"): """ Shape argument to make nice Tree display @@ -85,6 +89,7 @@ def show_tree(op, left, right, sep="|", node_caracter=">"): right_slided = leaf_suffix.join(str(right).splitlines()) return node_suffix.join([op, left_slided, right_slided]) + # ----------------------------- # Reglages pour 'vim' # vim:set autoindent expandtab tabstop=4 shiftwidth=4: diff --git a/mapytex/calculus/core/typing/__init__.py b/mapytex/calculus/core/typing/__init__.py index 045de4f..2e60bc8 100644 --- a/mapytex/calculus/core/typing/__init__.py +++ b/mapytex/calculus/core/typing/__init__.py @@ -12,6 +12,7 @@ Typing with MO from .exceptions import TypingError from .add import add + # from .minus import minus from .multiply import multiply from .divide import divide @@ -25,18 +26,18 @@ from ..MO.polynomial import MOpolynomial from itertools import product from tabulate import tabulate -MOS = [ MOnumber, MOstr, MOFraction, MOstrPower, MOMonomial, MOpolynomial] +MOS = [MOnumber, MOstr, MOFraction, MOstrPower, MOMonomial, MOpolynomial] OPERATIONS = { - "+": add, - # "-": minus, - "*": multiply, - "/": divide, - "^": power, - } + "+": add, + # "-": minus, + "*": multiply, + "/": divide, + "^": power, +} -def typing(node, left_v, right_v,\ - raiseTypingError = True): + +def typing(node, left_v, right_v, raiseTypingError=True): """ Typing a try base on his root node @@ -47,6 +48,7 @@ def typing(node, left_v, right_v,\ raise NotImplementedError(f"Unknown operation ({node}) in typing") return operation(left_v, right_v) + def typing_capacities(node): """ Test an operation through all MOs @@ -59,21 +61,19 @@ def typing_capacities(node): """ op = OPERATIONS[node] - lines = [[node] + [mo.__name__ for mo in MOS]] + lines = [[node] + [mo.__name__ for mo in MOS]] for left_mo in MOS: - lines.append( - [left_mo.__name__] + \ - [(left_mo, i) in op.funcs for i in MOS] - ) + lines.append([left_mo.__name__] + [(left_mo, i) in op.funcs for i in MOS]) return lines + def describe_typing(): """ Explain which operations are handle by typing """ ans = "Implemented typing operations among MOs\n" for op in OPERATIONS: ans += "\n" - ans += tabulate(typing_capacities(op), tablefmt='grid') + ans += tabulate(typing_capacities(op), tablefmt="grid") return ans diff --git a/mapytex/calculus/core/typing/add.py b/mapytex/calculus/core/typing/add.py index 57ca763..dc4842b 100644 --- a/mapytex/calculus/core/typing/add.py +++ b/mapytex/calculus/core/typing/add.py @@ -27,6 +27,7 @@ add_doc = """ Add MOs add = Dispatcher("add", doc=add_doc) + @add.register((MOnumber, MOFraction), MOstr) def moscalar_mostr(left, right): """ add a scalar with a letter to create a MOpolynomial @@ -41,6 +42,7 @@ def moscalar_mostr(left, right): """ return MOpolynomial(right, [left, 1]) + @add.register(MOstr, (MOnumber, MOFraction)) def mostr_moscalar(left, right): """ add a scalar with a letter to create a MOpolynomial @@ -55,6 +57,7 @@ def mostr_moscalar(left, right): """ return MOpolynomial(left, [right, 1]) + @add.register((MOnumber, MOFraction), MOstrPower) def moscalar_mostrpower(left, right): """ add a scalar with a letter to create a MOpolynomial @@ -69,6 +72,7 @@ def moscalar_mostrpower(left, right): """ return MOpolynomial(right.variable, {0: left, right.power: 1}) + @add.register(MOstrPower, (MOnumber, MOFraction)) def mostrpower_moscalar(left, right): """ add a scalar with a letter to create a MOpolynomial @@ -83,6 +87,7 @@ def mostrpower_moscalar(left, right): """ return MOpolynomial(left.variable, {0: right, left.power: 1}) + @add.register((MOnumber, MOFraction), MOMonomial) def moscalar_momonomial(left, right): """ add a scalar with a MOMonomial to create a MOpolynomial @@ -95,9 +100,8 @@ def moscalar_momonomial(left, right): >>> add(a, b) """ - return MOpolynomial(right.variable, - {right.power: right.coefficient, 0: left} - ) + return MOpolynomial(right.variable, {right.power: right.coefficient, 0: left}) + @add.register(MOMonomial, (MOnumber, MOFraction)) def momonial_moscalar(left, right): @@ -112,9 +116,8 @@ def momonial_moscalar(left, right): """ - return MOpolynomial(left.variable, - {0: right, left.power: left.coefficient} - ) + return MOpolynomial(left.variable, {0: right, left.power: left.coefficient}) + @add.register((MOnumber, MOFraction), MOpolynomial) def moscalar_mopolynomial(left, right): @@ -129,13 +132,16 @@ def moscalar_mopolynomial(left, right): """ if 0 in right.coefficients.keys(): - raise NotImplementedError(f"Polynomial with constant ({right.coefficients[0]}), calculus to do") + raise NotImplementedError( + f"Polynomial with constant ({right.coefficients[0]}), calculus to do" + ) new_coefs = {**right.coefficients} #! Need to be add at the end to be printed at the beginning new_coefs[0] = left return MOpolynomial(right.variable, new_coefs) + @add.register(MOpolynomial, (MOnumber, MOFraction)) def mopolynomial_moscalar(left, right): """ add a scalar with a MOpolynomial to create a MOpolynomial @@ -156,6 +162,7 @@ def mopolynomial_moscalar(left, right): new_coefs = {**new_coefs, **left.coefficients} return MOpolynomial(left.variable, new_coefs) + @add.register(MOstr, MOstr) def mostr_mostr(left, right): """ add 2 mostr @@ -167,7 +174,8 @@ def mostr_mostr(left, right): """ if left != right: raise NotImplementedError("Can't add 2 Mostr without same letter") - return MOMonomial(2, left) + return MOMonomial(2, left) + @add.register(MOstr, MOstrPower) def mostr_mostrpower(left, right): @@ -182,8 +190,9 @@ def mostr_mostrpower(left, right): """ if left != right.variable: - raise - return MOpolynomial(left , {1: 1, right.power: 1}) + raise + return MOpolynomial(left, {1: 1, right.power: 1}) + @add.register(MOstrPower, MOstr) def mostrpower_mostr(left, right): @@ -198,8 +207,9 @@ def mostrpower_mostr(left, right): """ if right != left.variable: - raise - return MOpolynomial(right , {1: 1, left.power: 1}) + raise + return MOpolynomial(right, {1: 1, left.power: 1}) + @add.register(MOstrPower, MOstrPower) def mostrpower_mostrpower(left, right): @@ -213,9 +223,12 @@ def mostrpower_mostrpower(left, right): if left.variable != right.variable: raise NotImplementedError("Can't add 2 Mostrpower without same letter") if left.power != right.power: - raise NotImplementedError("Can't add 2 Mostrpower with compute if not same degree") + raise NotImplementedError( + "Can't add 2 Mostrpower with compute if not same degree" + ) + + return MOMonomial(2, left.variable, left.power) - return MOMonomial(2, left.variable, left.power) @add.register(MOstr, MOpolynomial) def mostr_mopolynomial(left, right): @@ -234,6 +247,7 @@ def mostr_mopolynomial(left, right): new_coefs[1] = 1 return MOpolynomial(right.variable, new_coefs) + @add.register(MOpolynomial, MOstr) def mopolynomial_mostr(left, right): """ add a str with a MOpolynomial to create a MOpolynomial @@ -250,6 +264,7 @@ def mopolynomial_mostr(left, right): new_coefs = {**new_coefs, **left.coefficients} return MOpolynomial(left.variable, new_coefs) + @add.register(MOstrPower, MOpolynomial) def mostrpower_mopolynomial(left, right): """ add a strPower with a MOpolynomial to create a MOpolynomial @@ -267,6 +282,7 @@ def mostrpower_mopolynomial(left, right): new_coefs[left.power] = 1 return MOpolynomial(right.variable, new_coefs) + @add.register(MOpolynomial, MOstrPower) def mopolynomial_mostrpower(left, right): """ add a strPower with a MOpolynomial to create a MOpolynomial @@ -283,6 +299,7 @@ def mopolynomial_mostrpower(left, right): new_coefs = {**new_coefs, **left.coefficients} return MOpolynomial(left.variable, new_coefs) + @add.register(MOMonomial, MOpolynomial) def momonomial_mopolynomial(left, right): """ add a Monomial with a MOpolynomial to create a MOpolynomial @@ -300,6 +317,7 @@ def momonomial_mopolynomial(left, right): new_coefs[left.power] = left.coefficient return MOpolynomial(right.variable, new_coefs) + @add.register(MOpolynomial, MOMonomial) def mopolynomial_momonomial(left, right): """ add a Monomial with a MOpolynomial to create a MOpolynomial @@ -316,6 +334,7 @@ def mopolynomial_momonomial(left, right): new_coefs = {**new_coefs, **left.coefficients} return MOpolynomial(left.variable, new_coefs) + @add.register(MOpolynomial, MOpolynomial) def mopolynomial_mopolynomial(left, right): """ add a polynomial with a MOpolynomial to create a MOpolynomial @@ -327,13 +346,14 @@ def mopolynomial_mopolynomial(left, right): >>> add(b, a) """ - common_degree = set(left.monomials.keys()).intersection(right.monomials.keys()) + common_degree = set(left.monomials.keys()).intersection(right.monomials.keys()) if common_degree: raise NotImplementedError("Degree in common, need to compute") new_coefs = {**right.coefficients, **left.coefficients} return MOpolynomial(right.variable, new_coefs) + @add.register(MOstr, MOMonomial) def mostr_monomial(left, right): """ add a mostr with a MOMonomial to create a MOpolynomial @@ -346,9 +366,8 @@ def mostr_monomial(left, right): if right.power == 1: raise NotImplementedError("Monomial is deg 1, need to compute") - return MOpolynomial(right.variable, - {right.power: right.coefficient, 1: 1} - ) + return MOpolynomial(right.variable, {right.power: right.coefficient, 1: 1}) + @add.register(MOMonomial, MOstr) def monomial_mostr(left, right): @@ -362,9 +381,8 @@ def monomial_mostr(left, right): if left.power == 1: raise NotImplementedError("Monomial is deg 1, need to compute") - return MOpolynomial(left.variable, - {1: 1, left.power: left.coefficient} - ) + return MOpolynomial(left.variable, {1: 1, left.power: left.coefficient}) + @add.register(MOstrPower, MOMonomial) def mostrpower_monomial(left, right): @@ -376,11 +394,12 @@ def mostrpower_monomial(left, right): """ if left.power == right.power: - raise NotImplementedError("MostrPower and MOMonomial are same degree, need to compute") + raise NotImplementedError( + "MostrPower and MOMonomial are same degree, need to compute" + ) + + return MOpolynomial(right.variable, {right.power: right.coefficient, left.power: 1}) - return MOpolynomial(right.variable, - {right.power: right.coefficient, left.power: 1} - ) @add.register(MOMonomial, MOstrPower) def monomial_mostrpower(left, right): @@ -392,11 +411,12 @@ def monomial_mostrpower(left, right): """ if left.power == right.power: - raise NotImplementedError("MostrPower and MOMonomial are same degree, need to compute") + raise NotImplementedError( + "MostrPower and MOMonomial are same degree, need to compute" + ) + + return MOpolynomial(left.variable, {right.power: 1, left.power: left.coefficient}) - return MOpolynomial(left.variable, - {right.power: 1, left.power: left.coefficient} - ) @add.register(MOMonomial, MOMonomial) def monomial_momonomial(left, right): @@ -410,9 +430,9 @@ def monomial_momonomial(left, right): if left.power == right.power: raise NotImplementedError("MOMonomials are same degree, need to compute") - return MOpolynomial(left.variable, - {right.power: right.coefficient, left.power: left.coefficient} - ) + return MOpolynomial( + left.variable, {right.power: right.coefficient, left.power: left.coefficient} + ) # ----------------------------- diff --git a/mapytex/calculus/core/typing/divide.py b/mapytex/calculus/core/typing/divide.py index 8175eba..0d18973 100644 --- a/mapytex/calculus/core/typing/divide.py +++ b/mapytex/calculus/core/typing/divide.py @@ -24,6 +24,7 @@ divide_doc = """ Typing trees a divide root divide = Dispatcher("divide", doc=divide_doc) + @divide.register(MOnumber, MOnumber) def monumber_monumber(left, right): """ A divide tree with 2 MOnumbers is a MOFraction diff --git a/mapytex/calculus/core/typing/exceptions.py b/mapytex/calculus/core/typing/exceptions.py index 64efc60..bf9a55d 100644 --- a/mapytex/calculus/core/typing/exceptions.py +++ b/mapytex/calculus/core/typing/exceptions.py @@ -10,9 +10,11 @@ Exceptions for typing trees """ + class TypingError(Exception): pass + # ----------------------------- # Reglages pour 'vim' # vim:set autoindent expandtab tabstop=4 shiftwidth=4: diff --git a/mapytex/calculus/core/typing/multiply.py b/mapytex/calculus/core/typing/multiply.py index e21d6fd..24f356a 100644 --- a/mapytex/calculus/core/typing/multiply.py +++ b/mapytex/calculus/core/typing/multiply.py @@ -26,6 +26,7 @@ multiply_doc = """ Multiply MOs multiply = Dispatcher("multiply", doc=multiply_doc) + @multiply.register((MOnumber, MOFraction), MOstr) def moscalar_mostr(left, right): """ Multiply a scalar with a letter to create a MOMonomial @@ -40,6 +41,7 @@ def moscalar_mostr(left, right): """ return MOMonomial(left, right) + @multiply.register(MOstr, (MOnumber, MOFraction)) def mostr_moscalar(left, right): """ Multiply a scalar with a letter to create a MOMonomial @@ -54,6 +56,7 @@ def mostr_moscalar(left, right): """ return MOMonomial(right, left) + @multiply.register((MOnumber, MOFraction), MOstrPower) def moscalar_mostrpower(left, right): """ Multiply a scalar with a MOstrPower @@ -66,6 +69,7 @@ def moscalar_mostrpower(left, right): """ return MOMonomial(left, right) + @multiply.register(MOstrPower, (MOnumber, MOFraction)) def mostrpower_moscalar(left, right): """ Multiply a MOstrPower with a scalar @@ -78,6 +82,7 @@ def mostrpower_moscalar(left, right): """ return MOMonomial(right, left) + # ----------------------------- # Reglages pour 'vim' # vim:set autoindent expandtab tabstop=4 shiftwidth=4: diff --git a/mapytex/calculus/core/typing/power.py b/mapytex/calculus/core/typing/power.py index e647604..538f7f5 100644 --- a/mapytex/calculus/core/typing/power.py +++ b/mapytex/calculus/core/typing/power.py @@ -25,6 +25,7 @@ power_doc = """ Typing Power of MOs power = Dispatcher("power", doc=power_doc) + @power.register(MOstr, MOnumber) def mostr_monumber(left, right): """ Create MOstrPower over powered MOstr @@ -38,7 +39,6 @@ def mostr_monumber(left, right): return MOstrPower(left, right) - # ----------------------------- # Reglages pour 'vim' # vim:set autoindent expandtab tabstop=4 shiftwidth=4: