Style: apply black

This commit is contained in:
Bertrand Benjamin 2019-05-14 06:55:56 +02:00
parent 7097801306
commit 09b04d2703
35 changed files with 533 additions and 354 deletions

View File

@ -14,6 +14,7 @@ from ..core import AssocialTree, Tree, compute, typing, TypingError
from .tokens import factory from .tokens import factory
from .renders import renders from .renders import renders
class Expression(object): class Expression(object):
""" """
@ -32,7 +33,7 @@ class Expression(object):
14 14
""" """
RENDER = 'txt' RENDER = "txt"
def __init__(self, tree, ancestor=None): def __init__(self, tree, ancestor=None):
""" """
@ -76,7 +77,7 @@ class Expression(object):
return cls(t) return cls(t)
@classmethod @classmethod
def random(self, template, conditions = [], shuffle = False): def random(self, template, conditions=[], shuffle=False):
""" Initiate randomly the expression """ Initiate randomly the expression
:param template: the template of the expression :param template: the template of the expression
@ -128,6 +129,7 @@ class Expression(object):
>>> print(e._order()) >>> print(e._order())
x + 5x + 6x^3 + 2x^2 + 4x^2 + 1 + 3 x + 5x + 6x^3 + 2x^2 + 4x^2 + 1 + 3
""" """
def signature(leaf): def signature(leaf):
try: try:
leaf.node leaf.node
@ -138,7 +140,7 @@ class Expression(object):
return type(leaf) return type(leaf)
else: else:
try: 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 return typed_leaf.signature
except (AttributeError, NotImplementedError, TypingError): except (AttributeError, NotImplementedError, TypingError):
return type(leaf) return type(leaf)
@ -148,8 +150,9 @@ class Expression(object):
except AttributeError: except AttributeError:
return self return self
organised = AssocialTree.from_any_tree(self._tree).\ organised = AssocialTree.from_any_tree(self._tree).organise_by(
organise_by(signature, recursive=True, exclude_nodes=exclude_nodes) signature, recursive=True, exclude_nodes=exclude_nodes
)
return Expression(organised) return Expression(organised)
def _optimize(self, exclude_nodes=["/", "**"]): def _optimize(self, exclude_nodes=["/", "**"]):
@ -380,6 +383,7 @@ class Expression(object):
else: else:
yield self yield self
# ----------------------------- # -----------------------------
# Reglages pour 'vim' # Reglages pour 'vim'
# vim:set autoindent expandtab tabstop=4 shiftwidth=4: # vim:set autoindent expandtab tabstop=4 shiftwidth=4:

View File

@ -12,6 +12,7 @@ Expression
""" """
from ..core import tree2txt, tree2tex from ..core import tree2txt, tree2tex
def _txt(mo_tree): def _txt(mo_tree):
""" txt render for MOs or Trees""" """ txt render for MOs or Trees"""
try: try:
@ -24,6 +25,7 @@ def _txt(mo_tree):
except AttributeError: except AttributeError:
return str(mo_tree) return str(mo_tree)
def _tex(mo_tree): def _tex(mo_tree):
""" Tex render for MOs or Trees""" """ Tex render for MOs or Trees"""
try: try:
@ -36,10 +38,8 @@ def _tex(mo_tree):
except AttributeError: except AttributeError:
return str(mo_tree) return str(mo_tree)
renders = {
'txt': _txt, renders = {"txt": _txt, "tex": _tex}
'tex': _tex,
}
# ----------------------------- # -----------------------------
# Reglages pour 'vim' # Reglages pour 'vim'

View File

@ -21,6 +21,7 @@ from .polynomial import Polynomial, Linear, Quadratic
__all__ = ["factory"] __all__ = ["factory"]
def factory(exp, name="", ancestor=None): def factory(exp, name="", ancestor=None):
""" Transform a Expression with on MathObject (from core) to a appropriate token (from API) """ 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") raise TypeError(f"Can't build from MOnumber ({mo}) neither int nor decimal")
elif isinstance(mo, MOFraction): elif isinstance(mo, MOFraction):
if isinstance(mo._denominator, MOnumber) and \ if isinstance(mo._denominator, MOnumber) and isinstance(
isinstance(mo._numerator, MOnumber): mo._numerator, MOnumber
):
return Fraction.from_mo(mo, name, ancestor) 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)): elif isinstance(mo, (MOstr, MOstrPower, MOMonomial, MOpolynomial)):
if not isinstance(mo._variable, (MOstr, str)): if not isinstance(mo._variable, (MOstr, str)):
raise TypeError(f"Can't build Polynom over something else than a letter (got {mo._variable})") raise TypeError(
if isinstance(mo, MOstr) or \ f"Can't build Polynom over something else than a letter (got {mo._variable})"
(isinstance(mo, MOMonomial) and mo.power.value == 1) or \ )
(isinstance(mo, MOpolynomial) and mo.power.value == 1): 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) return Linear.from_mo(mo, name, ancestor)
elif (isinstance(mo, MOstrPower) and mo.power.value == 2) or \ elif (
(isinstance(mo, MOMonomial) and mo.power.value == 2) or \ (isinstance(mo, MOstrPower) and mo.power.value == 2)
(isinstance(mo, MOpolynomial) 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) return Quadratic.from_mo(mo, name, ancestor)
else: else:
return Polynomial.from_mo(mo, name, ancestor) return Polynomial.from_mo(mo, name, ancestor)
@ -90,6 +100,7 @@ def factory(exp, name="", ancestor=None):
else: else:
raise TypeError(f"{type(mo)} is unknown MathObject") raise TypeError(f"{type(mo)} is unknown MathObject")
# ----------------------------- # -----------------------------
# Reglages pour 'vim' # Reglages pour 'vim'
# vim:set autoindent expandtab tabstop=4 shiftwidth=4: # vim:set autoindent expandtab tabstop=4 shiftwidth=4:

View File

@ -19,6 +19,7 @@ from ...core.MO.fraction import MOFraction
__all__ = ["Integer", "Decimal"] __all__ = ["Integer", "Decimal"]
class Integer(Token): class Integer(Token):
""" Token representing a integer """ Token representing a integer
@ -41,7 +42,7 @@ class Integer(Token):
mo = a mo = a
Token.__init__(self, mo, name, ancestor) Token.__init__(self, mo, name, ancestor)
self._mathtype = 'entier' self._mathtype = "entier"
@classmethod @classmethod
def from_mo(cls, mo, name="", ancestor=None): def from_mo(cls, mo, name="", ancestor=None):
@ -53,13 +54,9 @@ class Integer(Token):
return cls(mo, name, ancestor) return cls(mo, name, ancestor)
@classmethod @classmethod
def random(cls, def random(
name = "", cls, name="", min_value=-10, max_value=10, rejected=[0, 1], accept_callbacks=[]
min_value = -10, ):
max_value = 10,
rejected = [0, 1],
accept_callbacks=[],
):
""" Generate a random Integer """ Generate a random Integer
:param name: name of the Integer :param name: name of the Integer
@ -69,11 +66,11 @@ class Integer(Token):
:param accept_callbacks: list of function for value acceptation :param accept_callbacks: list of function for value acceptation
""" """
candidate = filter_random(min_value, max_value, candidate = filter_random(min_value, max_value, rejected, accept_callbacks)
rejected, accept_callbacks)
return Integer(candidate, name) return Integer(candidate, name)
class Decimal(Token): class Decimal(Token):
""" Token representing a decimal """ Token representing a decimal
@ -98,27 +95,28 @@ class Decimal(Token):
else: else:
mo = a mo = a
self._mathtype = 'décimal' self._mathtype = "décimal"
Token.__init__(self, mo, name, ancestor) Token.__init__(self, mo, name, ancestor)
@classmethod @classmethod
def from_mo(cls, mo, name="", ancestor=None): def from_mo(cls, mo, name="", ancestor=None):
if not isinstance(mo, MOnumber): if not isinstance(mo, MOnumber):
raise TypeError raise TypeError
if not isinstance(mo.value, _Decimal): if not isinstance(mo.value, _Decimal):
raise TypeError raise TypeError
return cls(mo, name, ancestor) return cls(mo, name, ancestor)
@classmethod @classmethod
def random(cls, def random(
name= "", cls,
min_value = -10, name="",
max_value = 10, min_value=-10,
digits = 2, max_value=10,
rejected = [0, 1], digits=2,
reject_callbacks=[], rejected=[0, 1],
): reject_callbacks=[],
):
""" Generate a random Decimal """ Generate a random Decimal
:param name: name of the Integer :param name: name of the Integer
@ -131,10 +129,10 @@ class Decimal(Token):
""" """
conditions = [lambda x: x in rejected] + reject_callbacks 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}") candidate = _Decimal(f"{float_cand:.{digits}f}")
while any(c(candidate) for c in conditions): 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}") candidate = _Decimal(f"{float_cand:.{digits}f}")
return Decimal(candidate, name) return Decimal(candidate, name)
@ -152,39 +150,44 @@ class Fraction(Token):
def __init__(self, a, name="", ancestor=None): def __init__(self, a, name="", ancestor=None):
if not isinstance(a, MO): if not isinstance(a, MO):
if isinstance(a, str): if isinstance(a, str):
num, denom = a.split('/') num, denom = a.split("/")
mo = MOFraction(int(num), int(denom)) mo = MOFraction(int(num), int(denom))
else: else:
raise TypeError raise TypeError
else: else:
mo = a mo = a
self._mathtype = 'fraction' self._mathtype = "fraction"
Token.__init__(self, mo, name, ancestor) Token.__init__(self, mo, name, ancestor)
@classmethod @classmethod
def from_mo(cls, mo, name="", ancestor=None): def from_mo(cls, mo, name="", ancestor=None):
if not isinstance(mo, MOFraction): if not isinstance(mo, MOFraction):
raise TypeError raise TypeError
if not isinstance(mo._numerator, MOnumber): if not isinstance(mo._numerator, MOnumber):
raise TypeError raise TypeError
if not isinstance(mo._denominator, MOnumber): if not isinstance(mo._denominator, MOnumber):
raise TypeError raise TypeError
return cls(mo, name, ancestor) return cls(mo, name, ancestor)
@classmethod @classmethod
def random(cls, def random(
name="", cls,
fix_num="", name="",
min_num=-10, max_num=10, rejected_num=[0], fix_num="",
accept_num_callbacks=[], min_num=-10,
fix_denom="", max_num=10,
min_denom=-10, max_denom=10, rejected_denom=[0, 1, -1], rejected_num=[0],
accept_denom_callbacks=[], accept_num_callbacks=[],
irreductible=False, fix_denom="",
not_integer=True min_denom=-10,
): max_denom=10,
rejected_denom=[0, 1, -1],
accept_denom_callbacks=[],
irreductible=False,
not_integer=True,
):
""" Generate a random Fraction """ Generate a random Fraction
:param name: Name of the 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 :param not_integer: can the generated fraction be egal to an interger
""" """
if fix_num == "": if fix_num == "":
num = filter_random(min_num, max_num, num = filter_random(min_num, max_num, rejected_num, accept_num_callbacks)
rejected_num,
accept_num_callbacks)
else: else:
num = fix_num num = fix_num
@ -212,17 +213,21 @@ class Fraction(Token):
accept_callbacks = accept_denom_callbacks accept_callbacks = accept_denom_callbacks
if irreductible: if irreductible:
def prime_with_num(denom): def prime_with_num(denom):
return gcd(num, denom) == 1 return gcd(num, denom) == 1
accept_callbacks.append(prime_with_num) accept_callbacks.append(prime_with_num)
if not_integer: if not_integer:
def not_divise_num(denom): def not_divise_num(denom):
return num % denom != 0 return num % denom != 0
accept_callbacks.append(not_divise_num) accept_callbacks.append(not_divise_num)
denom = filter_random(min_denom, max_denom, denom = filter_random(
rejected_denom, min_denom, max_denom, rejected_denom, accept_callbacks
accept_callbacks) )
else: else:
denom = fix_denom denom = fix_denom

View File

@ -15,6 +15,7 @@ from ...core.MO import MO
__all__ = ["Polynomial", "Quadratic", "Linear"] __all__ = ["Polynomial", "Quadratic", "Linear"]
class Polynomial(Token): class Polynomial(Token):
""" Token representing a polynomial """ """ Token representing a polynomial """
@ -29,7 +30,7 @@ class Polynomial(Token):
mo = a mo = a
Token.__init__(self, mo, name, ancestor) Token.__init__(self, mo, name, ancestor)
self._mathtype = 'polynome' self._mathtype = "polynome"
@classmethod @classmethod
def from_mo(cls, mo, name="", ancestor=None): def from_mo(cls, mo, name="", ancestor=None):
@ -52,6 +53,7 @@ class Polynomial(Token):
""" Call a Polynomial to evaluate itself on value """ """ Call a Polynomial to evaluate itself on value """
pass pass
class Linear(Polynomial): class Linear(Polynomial):
""" Token representing a linear """ """ Token representing a linear """
@ -59,12 +61,13 @@ class Linear(Polynomial):
def __init__(self, mo, name="", ancestor=None): def __init__(self, mo, name="", ancestor=None):
Polynomial.__init__(self, mo, name, ancestor) Polynomial.__init__(self, mo, name, ancestor)
self._mathtype = 'affine' self._mathtype = "affine"
@classmethod @classmethod
def random(cls): def random(cls):
raise NotImplemented raise NotImplemented
class Quadratic(Polynomial): class Quadratic(Polynomial):
""" Token representing a quadratic """ """ Token representing a quadratic """
@ -72,7 +75,7 @@ class Quadratic(Polynomial):
def __init__(self, mo, name="", ancestor=None): def __init__(self, mo, name="", ancestor=None):
Polynomial.__init__(self, mo, name, ancestor) Polynomial.__init__(self, mo, name, ancestor)
self._mathtype = 'polynome du 2nd degré' self._mathtype = "polynome du 2nd degré"
@classmethod @classmethod
def random(cls): def random(cls):

View File

@ -12,13 +12,14 @@ Tokens: practical envelop of math object
""" """
from ..renders import renders from ..renders import renders
class Token(object): class Token(object):
""" Token: practical envelop of an math 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._mo = mo
self.name = name self.name = name
self._mathtype = None self._mathtype = None
@ -71,6 +72,7 @@ class Token(object):
from ..expression import Expression from ..expression import Expression
from ...core import Tree from ...core import Tree
from . import factory from . import factory
if not isinstance(other, Token): if not isinstance(other, Token):
_other = factory(other) _other = factory(other)
else: else:
@ -165,6 +167,7 @@ class Token(object):
""" """
return self._operate(other, "/") return self._operate(other, "/")
# ----------------------------- # -----------------------------
# Reglages pour 'vim' # Reglages pour 'vim'
# vim:set autoindent expandtab tabstop=4 shiftwidth=4: # vim:set autoindent expandtab tabstop=4 shiftwidth=4:

View File

@ -15,6 +15,7 @@ from ..coroutine import coroutine, STOOOP
__all__ = ["moify", "MOnumber", "MOstr"] __all__ = ["moify", "MOnumber", "MOstr"]
@coroutine @coroutine
def moify(target): def moify(target):
""" Coroutine which try to convert a parsed token into an MO """ Coroutine which try to convert a parsed token into an MO
@ -47,6 +48,7 @@ def moify(target):
except STOOOP as err: except STOOOP as err:
yield target_.throw(err) yield target_.throw(err)
@total_ordering @total_ordering
class MOnumber(Atom): class MOnumber(Atom):
@ -116,8 +118,10 @@ class MOnumber(Atom):
elif isinstance(value, float): elif isinstance(value, float):
Atom.__init__(self, Decimal(value)) Atom.__init__(self, Decimal(value))
else: else:
raise MOError("The value of an MOnumber need to be a int, a float or a Decimal", raise MOError(
f"(got {type(value)})") "The value of an MOnumber need to be a int, a float or a Decimal",
f"(got {type(value)})",
)
self._signature = "scalar" self._signature = "scalar"
@ -215,9 +219,13 @@ class MOstr(Atom):
val = value val = value
if not isinstance(val, str): 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: 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(): if not val.isalpha():
raise MOError(f"An MOstr should be initiate with a alpha string, got {val}") raise MOError(f"An MOstr should be initiate with a alpha string, got {val}")

View File

@ -10,6 +10,7 @@
Exceptions for core tools Exceptions for core tools
""" """
class MOError(Exception): class MOError(Exception):
pass pass

View File

@ -11,6 +11,7 @@ from .mo import Molecule, MO
__all__ = ["MOFraction"] __all__ = ["MOFraction"]
class MOFraction(Molecule): class MOFraction(Molecule):
""" Fraction math object""" """ Fraction math object"""
@ -42,10 +43,7 @@ class MOFraction(Molecule):
""" """
_numerator = MO.factory(numerator) _numerator = MO.factory(numerator)
_denominator = MO.factory(denominator) _denominator = MO.factory(denominator)
base_tree = Tree("/", base_tree = Tree("/", _numerator, _denominator)
_numerator,
_denominator,
)
if negative: if negative:
tree = Tree("-", None, base_tree) tree = Tree("-", None, base_tree)
else: else:
@ -71,9 +69,8 @@ class MOFraction(Molecule):
def inverse(self): def inverse(self):
""" return the inverse fraction """ """ return the inverse fraction """
return MOFraction(self._denominator, return MOFraction(self._denominator, self._numerator, self.negative)
self._numerator,
self.negative)
# ----------------------------- # -----------------------------
# Reglages pour 'vim' # Reglages pour 'vim'

View File

@ -12,6 +12,7 @@ from ..renders import tree2txt, tree2tex
__all__ = ["MO"] __all__ = ["MO"]
class MO(ABC): class MO(ABC):
"""MO for math object """MO for math object
@ -50,7 +51,6 @@ class MO(ABC):
return Atom.factory(value) return Atom.factory(value)
@abstractmethod @abstractmethod
def content(self): def content(self):
""" content of the mo """ """ content of the mo """
@ -97,6 +97,7 @@ class MO(ABC):
""" """
return self._signature return self._signature
class Atom(MO): class Atom(MO):
""" Base Math Object with only one component. """ Base Math Object with only one component.
@ -196,8 +197,6 @@ class Molecule(MO):
return tree2tex(self._tree) return tree2tex(self._tree)
# ----------------------------- # -----------------------------
# Reglages pour 'vim' # Reglages pour 'vim'
# vim:set autoindent expandtab tabstop=4 shiftwidth=4: # vim:set autoindent expandtab tabstop=4 shiftwidth=4:

View File

@ -13,6 +13,7 @@ from .exceptions import MOError
__all__ = ["MOMonomial"] __all__ = ["MOMonomial"]
class MOstrPower(Molecule): class MOstrPower(Molecule):
""" Power of a MOstr """ """ Power of a MOstr """
@ -68,10 +69,7 @@ class MOstrPower(Molecule):
raise MOError("The power of a monomial should be a integer") raise MOError("The power of a monomial should be a integer")
self._power = _power self._power = _power
_tree = Tree("^", _tree = Tree("^", self._variable, self._power)
self._variable,
self._power,
)
Molecule.__init__(self, _tree) Molecule.__init__(self, _tree)
@ -113,6 +111,7 @@ class MOstrPower(Molecule):
""" """
return f"monome{self.power}" return f"monome{self.power}"
class MOMonomial(Molecule): class MOMonomial(Molecule):
""" Monomial math object""" """ Monomial math object"""
@ -164,7 +163,9 @@ class MOMonomial(Molecule):
if coefficient == 0: if coefficient == 0:
raise MOError("The coefficient of a monomial should not be 0") raise MOError("The coefficient of a monomial should not be 0")
elif coefficient == 1: 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 self._coefficient = _coefficient
_variable = MO.factory(variable) _variable = MO.factory(variable)
@ -174,7 +175,9 @@ class MOMonomial(Molecule):
elif isinstance(_variable, MOstr): elif isinstance(_variable, MOstr):
_power = MO.factory(power) _power = MO.factory(power)
else: 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._variable = _variable
self._power = _power self._power = _power
@ -187,10 +190,8 @@ class MOMonomial(Molecule):
except AttributeError: except AttributeError:
_tree = Tree("*", self._coefficient, self.strpower) _tree = Tree("*", self._coefficient, self.strpower)
Molecule.__init__(self, _tree) Molecule.__init__(self, _tree)
def __str__(self): def __str__(self):
if self._coefficient != -1: if self._coefficient != -1:
return super(MOMonomial, self).__str__() return super(MOMonomial, self).__str__()
@ -244,6 +245,7 @@ class MOMonomial(Molecule):
@property @property
def degree(self): def degree(self):
return self._power.value return self._power.value
@property @property
def signature(self): def signature(self):
""" Name of the mo in the API """ Name of the mo in the API
@ -256,6 +258,7 @@ class MOMonomial(Molecule):
""" """
return f"monome{self.power}" return f"monome{self.power}"
# ----------------------------- # -----------------------------
# Reglages pour 'vim' # Reglages pour 'vim'
# vim:set autoindent expandtab tabstop=4 shiftwidth=4: # vim:set autoindent expandtab tabstop=4 shiftwidth=4:

View File

@ -14,6 +14,7 @@ from .monomial import MOMonomial, MOstrPower
__all__ = ["MOpolynomial"] __all__ = ["MOpolynomial"]
class MOpolynomial(Molecule): class MOpolynomial(Molecule):
""" MO polynomial""" """ MO polynomial"""
@ -45,11 +46,13 @@ class MOpolynomial(Molecule):
self._variable = _variable self._variable = _variable
if isinstance(coefs, dict): if isinstance(coefs, dict):
_coefs = {MO.factory(d): MO.factory(c) for (d, c) in coefs.items() _coefs = {
if c != 0 } MO.factory(d): MO.factory(c) for (d, c) in coefs.items() if c != 0
}
elif isinstance(coefs, list): elif isinstance(coefs, list):
_coefs = {MO.factory(d): MO.factory(c) for (d, c) in enumerate(coefs) _coefs = {
if c != 0 } MO.factory(d): MO.factory(c) for (d, c) in enumerate(coefs) if c != 0
}
else: else:
raise TypeError("Coefs needs to be a dictionnary or a list") raise TypeError("Coefs needs to be a dictionnary or a list")
self._coefs = _coefs self._coefs = _coefs

View File

@ -2,7 +2,7 @@
# encoding: utf-8 # encoding: utf-8
__all__ = ['gcd'] __all__ = ["gcd"]
def gcd(a, b): def gcd(a, b):
@ -28,7 +28,7 @@ def gcd(a, b):
pos_a, _a = (a >= 0), abs(a) pos_a, _a = (a >= 0), abs(a)
pos_b, _b = (b >= 0), abs(b) 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: except TypeError:
_a = a _a = a
_b = b _b = b
@ -48,6 +48,7 @@ def gcd(a, b):
else: else:
return gcd_sgn * gcd(min(_a, _b), c) return gcd_sgn * gcd(min(_a, _b), c)
def lcm(a, b): def lcm(a, b):
"""Compute lcm(a,b) """Compute lcm(a,b)
@ -69,7 +70,8 @@ def lcm(a, b):
""" """
return (a * b) // gcd(a, b) return (a * b) // gcd(a, b)
if __name__ == '__main__':
if __name__ == "__main__":
print(gcd(3, 15)) print(gcd(3, 15))
print(gcd(3, 15)) print(gcd(3, 15))
print(gcd(-15, -3)) print(gcd(-15, -3))

View File

@ -25,15 +25,10 @@ from ..MO.polynomial import MOpolynomial
from itertools import product from itertools import product
from tabulate import tabulate 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): def compute(node, left_v, right_v):
""" """
@ -60,6 +55,7 @@ def compute(node, left_v, right_v):
return operation(left_v, right_v) return operation(left_v, right_v)
def compute_capacities(node): def compute_capacities(node):
""" Test an operation through all MOs """ Test an operation through all MOs
@ -72,21 +68,19 @@ def compute_capacities(node):
""" """
op = OPERATIONS[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: for left_mo in MOS:
lines.append( lines.append([left_mo.__name__] + [(left_mo, i) in op.funcs for i in MOS])
[left_mo.__name__] + \
[(left_mo, i) in op.funcs for i in MOS]
)
return lines return lines
def describe_compute(): def describe_compute():
""" Explain which operation are handle by compue """ """ Explain which operation are handle by compue """
ans = "Implemented compute operations among MOs" ans = "Implemented compute operations among MOs"
for op in OPERATIONS: for op in OPERATIONS:
ans += "\n" ans += "\n"
ans += tabulate(compute_capacities(op), tablefmt='grid') ans += tabulate(compute_capacities(op), tablefmt="grid")
return ans return ans

View File

@ -29,6 +29,7 @@ add_doc = """ Adding MOs
add = Dispatcher("add", doc=add_doc) add = Dispatcher("add", doc=add_doc)
def add_filter(left, right): def add_filter(left, right):
""" Automatic add on MO """ Automatic add on MO
@ -59,6 +60,7 @@ def add_filter(left, right):
except AttributeError: except AttributeError:
pass pass
@add.register(MOnumber, MOnumber) @add.register(MOnumber, MOnumber)
@special_case(add_filter) @special_case(add_filter)
def monumber_monumber(left, right): def monumber_monumber(left, right):
@ -72,6 +74,7 @@ def monumber_monumber(left, right):
""" """
return MO.factory(left.value + right.value) return MO.factory(left.value + right.value)
@add.register(MOnumber, MOFraction) @add.register(MOnumber, MOFraction)
@special_case(add_filter) @special_case(add_filter)
def monumber_mofraction(left, right): def monumber_mofraction(left, right):
@ -87,6 +90,7 @@ def monumber_mofraction(left, right):
left_fraction = MOFraction(left, MOnumber(1)) left_fraction = MOFraction(left, MOnumber(1))
return Tree("+", left_fraction, right) return Tree("+", left_fraction, right)
@add.register(MOFraction, MOnumber) @add.register(MOFraction, MOnumber)
@special_case(add_filter) @special_case(add_filter)
def mofraction_monumber(left, right): def mofraction_monumber(left, right):
@ -103,6 +107,7 @@ def mofraction_monumber(left, right):
right_fraction = MOFraction(right, MOnumber(1)) right_fraction = MOFraction(right, MOnumber(1))
return Tree("+", left, right_fraction) return Tree("+", left, right_fraction)
@add.register(MOFraction, MOFraction) @add.register(MOFraction, MOFraction)
@special_case(add_filter) @special_case(add_filter)
def mofraction_mofraction(left, right): def mofraction_mofraction(left, right):
@ -200,6 +205,7 @@ def mofraction_mofraction(left, right):
return Tree("+", left_frac, right_frac) return Tree("+", left_frac, right_frac)
@add.register(MOstr, MOstr) @add.register(MOstr, MOstr)
@special_case(add_filter) @special_case(add_filter)
def mostr_mostr(left, right): 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") raise NotImplementedError("Can't add 2 MOstr with not same letter")
return MOMonomial(2, left) return MOMonomial(2, left)
@add.register(MOstrPower, MOstrPower) @add.register(MOstrPower, MOstrPower)
@special_case(add_filter) @special_case(add_filter)
def mostrpower_mostrpower(left, right): 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") raise NotImplementedError("Can't add 2 MOstrPower with not same power")
return MOMonomial(2, left.variable, left.power) return MOMonomial(2, left.variable, left.power)
@add.register((MOnumber, MOFraction), MOpolynomial) @add.register((MOnumber, MOFraction), MOpolynomial)
@special_case(add_filter) @special_case(add_filter)
def moscalar_mopolynomial(left, right): 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] right_top = [mo for deg, mo in right.monomials.items() if deg > 0][::-1]
adds = right_top + [Tree("+", left, right_const)] adds = right_top + [Tree("+", left, right_const)]
return Tree.from_list('+', adds) return Tree.from_list("+", adds)
@add.register(MOpolynomial, (MOnumber, MOFraction)) @add.register(MOpolynomial, (MOnumber, MOFraction))
@special_case(add_filter) @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] left_top = [mo for deg, mo in left.monomials.items() if deg > 0][::-1]
adds = left_top + [Tree("+", left_const, right)] adds = left_top + [Tree("+", left_const, right)]
return Tree.from_list('+', adds) return Tree.from_list("+", adds)
@add.register(MOstr, MOpolynomial) @add.register(MOstr, MOpolynomial)
@special_case(add_filter) @special_case(add_filter)
@ -313,6 +323,7 @@ def mostr_mopolynomial(left, right):
return Tree.from_list("+", adds) return Tree.from_list("+", adds)
@add.register(MOpolynomial, MOstr) @add.register(MOpolynomial, MOstr)
@special_case(add_filter) @special_case(add_filter)
def mopolynomial_mostr(left, right): def mopolynomial_mostr(left, right):
@ -344,6 +355,7 @@ def mopolynomial_mostr(left, right):
return Tree.from_list("+", adds) return Tree.from_list("+", adds)
@add.register(MOstrPower, MOpolynomial) @add.register(MOstrPower, MOpolynomial)
@special_case(add_filter) @special_case(add_filter)
def mostrpower_mopolynomial(left, right): def mostrpower_mopolynomial(left, right):
@ -387,6 +399,7 @@ def mostrpower_mopolynomial(left, right):
return Tree.from_list("+", adds) return Tree.from_list("+", adds)
@add.register(MOpolynomial, MOstrPower) @add.register(MOpolynomial, MOstrPower)
@special_case(add_filter) @special_case(add_filter)
def mopolynomial_mostrpower(left, right): def mopolynomial_mostrpower(left, right):
@ -431,6 +444,7 @@ def mopolynomial_mostrpower(left, right):
return Tree.from_list("+", adds) return Tree.from_list("+", adds)
@add.register(MOMonomial, MOpolynomial) @add.register(MOMonomial, MOpolynomial)
@special_case(add_filter) @special_case(add_filter)
def momonomial_mopolynomial(left, right): def momonomial_mopolynomial(left, right):
@ -474,6 +488,7 @@ def momonomial_mopolynomial(left, right):
return Tree.from_list("+", adds) return Tree.from_list("+", adds)
@add.register(MOpolynomial, MOMonomial) @add.register(MOpolynomial, MOMonomial)
@special_case(add_filter) @special_case(add_filter)
def mopolynomial_momonomial(left, right): def mopolynomial_momonomial(left, right):
@ -517,6 +532,7 @@ def mopolynomial_momonomial(left, right):
return Tree.from_list("+", adds) return Tree.from_list("+", adds)
@add.register(MOpolynomial, MOpolynomial) @add.register(MOpolynomial, MOpolynomial)
@special_case(add_filter) @special_case(add_filter)
def mopolynomial_mopolynomial(left, right): def mopolynomial_mopolynomial(left, right):
@ -563,7 +579,7 @@ def mopolynomial_mopolynomial(left, right):
| > 2 | > 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: if not common_degree:
raise NotImplementedError("No degree in common, no calculus to do") 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]) return Tree.from_list("+", list(merge_monomials.values())[::-1])
@add.register(MOstr, MOMonomial) @add.register(MOstr, MOMonomial)
@special_case(add_filter) @special_case(add_filter)
def mostr_momonomial(left, right): def mostr_momonomial(left, right):
@ -593,6 +610,7 @@ def mostr_momonomial(left, right):
add_scal = Tree("+", 1, right.coefficient) add_scal = Tree("+", 1, right.coefficient)
return Tree("*", add_scal, left) return Tree("*", add_scal, left)
@add.register(MOMonomial, MOstr) @add.register(MOMonomial, MOstr)
@special_case(add_filter) @special_case(add_filter)
def momonomial_mostr(left, right): def momonomial_mostr(left, right):
@ -613,6 +631,7 @@ def momonomial_mostr(left, right):
add_scal = Tree("+", left.coefficient, 1) add_scal = Tree("+", left.coefficient, 1)
return Tree("*", add_scal, right) return Tree("*", add_scal, right)
@add.register(MOstrPower, MOMonomial) @add.register(MOstrPower, MOMonomial)
@special_case(add_filter) @special_case(add_filter)
def mostrpower_momonomial(left, right): def mostrpower_momonomial(left, right):
@ -633,6 +652,7 @@ def mostrpower_momonomial(left, right):
add_scal = Tree("+", 1, right.coefficient) add_scal = Tree("+", 1, right.coefficient)
return Tree("*", add_scal, left) return Tree("*", add_scal, left)
@add.register(MOMonomial, MOstrPower) @add.register(MOMonomial, MOstrPower)
@special_case(add_filter) @special_case(add_filter)
def momonomial_mostrpower(left, right): def momonomial_mostrpower(left, right):
@ -653,6 +673,7 @@ def momonomial_mostrpower(left, right):
add_scal = Tree("+", left.coefficient, 1) add_scal = Tree("+", left.coefficient, 1)
return Tree("*", add_scal, right) return Tree("*", add_scal, right)
@add.register(MOMonomial, MOMonomial) @add.register(MOMonomial, MOMonomial)
@special_case(add_filter) @special_case(add_filter)
def momonomial_momonomial(left, right): def momonomial_momonomial(left, right):

View File

@ -28,6 +28,7 @@ divide_doc = """ Dividing MOs
divide = Dispatcher("divide", doc=divide_doc) divide = Dispatcher("divide", doc=divide_doc)
def divide_filter(left, right): def divide_filter(left, right):
""" Automatic divide on MO """ Automatic divide on MO
@ -62,6 +63,7 @@ def divide_filter(left, right):
except TypeError: except TypeError:
pass pass
@divide.register(MOnumber, MOnumber) @divide.register(MOnumber, MOnumber)
@special_case(divide_filter) @special_case(divide_filter)
def monumber_monumber(left, right): 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 NotImplementedError: Can't divide 2 int. Need to create a Fraction instead
""" """
if type(left.value) in [float, Decimal] or \ if type(left.value) in [float, Decimal] or type(right.value) in [float, Decimal]:
type(right.value) in [float, Decimal]:
return MO.factory(left.value / right.value) return MO.factory(left.value / right.value)
else: 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) @divide.register(MOnumber, MOFraction)
@special_case(divide_filter) @special_case(divide_filter)
@ -103,6 +107,7 @@ def monumber_mofraction(left, right):
""" """
return Tree("*", left, right.inverse()) return Tree("*", left, right.inverse())
@divide.register(MOFraction, MOnumber) @divide.register(MOFraction, MOnumber)
@special_case(divide_filter) @special_case(divide_filter)
def mofraction_monumber(left, right): def mofraction_monumber(left, right):
@ -119,6 +124,7 @@ def mofraction_monumber(left, right):
right_fraction = MOFraction(MOnumber(1), right) right_fraction = MOFraction(MOnumber(1), right)
return Tree("*", left, right_fraction) return Tree("*", left, right_fraction)
@divide.register(MOFraction, MOFraction) @divide.register(MOFraction, MOFraction)
@special_case(divide_filter) @special_case(divide_filter)
def mofraction_mofraction(left, right): def mofraction_mofraction(left, right):
@ -134,6 +140,7 @@ def mofraction_mofraction(left, right):
""" """
return Tree("*", left, right.inverse()) return Tree("*", left, right.inverse())
# ----------------------------- # -----------------------------
# Reglages pour 'vim' # Reglages pour 'vim'
# vim:set autoindent expandtab tabstop=4 shiftwidth=4: # vim:set autoindent expandtab tabstop=4 shiftwidth=4:

View File

@ -10,18 +10,23 @@
Exceptions for computing Exceptions for computing
""" """
class ComputeError(Exception): class ComputeError(Exception):
pass pass
class AddError(ComputeError): class AddError(ComputeError):
pass pass
class MinusError(ComputeError): class MinusError(ComputeError):
pass pass
class MultiplyError(ComputeError): class MultiplyError(ComputeError):
pass pass
class DivideError(ComputeError): class DivideError(ComputeError):
pass pass

View File

@ -13,6 +13,7 @@ Decorator to filter MO before operate
from functools import wraps from functools import wraps
from .exceptions import ComputeError from .exceptions import ComputeError
def args_are(left_type, right_type): def args_are(left_type, right_type):
""" Decorator which filter arguments 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 :returns: a decorator which will allow only some type
""" """
def type_filter(func): def type_filter(func):
@wraps(func) @wraps(func)
def filtered_func(left, right): def filtered_func(left, right):
if not isinstance(left, left_type): if not isinstance(left, left_type):
raise ComputeError("Wrong type for left argument" raise ComputeError(
f"Require {left_type}, got {left.__class__.__name__}" "Wrong type for left argument"
) f"Require {left_type}, got {left.__class__.__name__}"
)
if not isinstance(right, right_type): if not isinstance(right, right_type):
raise ComputeError("Wrong type for right argument" raise ComputeError(
f"Require {right_type}, got {right.__class__.__name__}" "Wrong type for right argument"
) f"Require {right_type}, got {right.__class__.__name__}"
)
return func(left, right) return func(left, right)
return filtered_func return filtered_func
return type_filter return type_filter
def special_case(filter): def special_case(filter):
""" Decorate operation to filter special cases before call the function """ Decorate operation to filter special cases before call the function
@ -43,6 +50,7 @@ def special_case(filter):
:returns: decorator :returns: decorator
""" """
def decorator(func): def decorator(func):
@wraps(func) @wraps(func)
def _func(left, right): def _func(left, right):
@ -50,9 +58,12 @@ def special_case(filter):
if ans is None: if ans is None:
return func(left, right) return func(left, right)
return ans return ans
return _func return _func
return decorator return decorator
# ----------------------------- # -----------------------------
# Reglages pour 'vim' # Reglages pour 'vim'
# vim:set autoindent expandtab tabstop=4 shiftwidth=4: # vim:set autoindent expandtab tabstop=4 shiftwidth=4:

View File

@ -28,6 +28,7 @@ minus_doc = """ Opposite of a MO
minus = Dispatcher("minus", doc=minus_doc) minus = Dispatcher("minus", doc=minus_doc)
@minus.register(type(None), MOnumber) @minus.register(type(None), MOnumber)
def monumber(_, right): def monumber(_, right):
""" """
@ -37,7 +38,8 @@ def monumber(_, right):
<MOnumber - 4> <MOnumber - 4>
""" """
return MO.factory(- right.value) return MO.factory(-right.value)
@minus.register(type(None), MOFraction) @minus.register(type(None), MOFraction)
def mofraction(_, right): def mofraction(_, right):
@ -84,6 +86,7 @@ def mofraction(_, right):
return MOFraction(right._numerator, right._denominator, True) return MOFraction(right._numerator, right._denominator, True)
@minus.register(type(None), MOstr) @minus.register(type(None), MOstr)
def mostr(_, right): def mostr(_, right):
""" Opposite of 'x' is '-x' """ Opposite of 'x' is '-x'
@ -95,6 +98,7 @@ def mostr(_, right):
""" """
return MOMonomial(-1, right) return MOMonomial(-1, right)
@minus.register(type(None), MOstrPower) @minus.register(type(None), MOstrPower)
def mostrpower(_, right): def mostrpower(_, right):
""" Opposite of 'x^n' is '-x^n' """ Opposite of 'x^n' is '-x^n'
@ -106,6 +110,7 @@ def mostrpower(_, right):
""" """
return MOMonomial(-1, right.variable, right.power) return MOMonomial(-1, right.variable, right.power)
@minus.register(type(None), MOMonomial) @minus.register(type(None), MOMonomial)
def momonomial(_, right): def momonomial(_, right):
""" Opposite of 'ax^n' is '-ax^n' """ Opposite of 'ax^n' is '-ax^n'
@ -121,6 +126,7 @@ def momonomial(_, right):
coef = Tree("-", None, right.coefficient) coef = Tree("-", None, right.coefficient)
return Tree("*", coef, right.strpower) return Tree("*", coef, right.strpower)
@minus.register(type(None), MOpolynomial) @minus.register(type(None), MOpolynomial)
def mopolynomial(_, right): def mopolynomial(_, right):
""" Opposite of a polynomial """ Opposite of a polynomial
@ -133,6 +139,7 @@ def mopolynomial(_, right):
neg_coefs = {p: -c.value for (p, c) in right.coefficients.items()} neg_coefs = {p: -c.value for (p, c) in right.coefficients.items()}
return MOpolynomial(right.variable, neg_coefs) return MOpolynomial(right.variable, neg_coefs)
# ----------------------------- # -----------------------------
# Reglages pour 'vim' # Reglages pour 'vim'
# vim:set autoindent expandtab tabstop=4 shiftwidth=4: # vim:set autoindent expandtab tabstop=4 shiftwidth=4:

View File

@ -28,6 +28,7 @@ multiply_doc = """ Multiply MOs
multiply = Dispatcher("multiply", doc=multiply_doc) multiply = Dispatcher("multiply", doc=multiply_doc)
def multiply_filter(left, right): def multiply_filter(left, right):
""" Automatic multiply on MO """ Automatic multiply on MO
@ -68,6 +69,7 @@ def multiply_filter(left, right):
except TypeError: except TypeError:
pass pass
@multiply.register(MOnumber, MOnumber) @multiply.register(MOnumber, MOnumber)
@special_case(multiply_filter) @special_case(multiply_filter)
def monumber_monumber(left, right): def monumber_monumber(left, right):
@ -81,6 +83,7 @@ def monumber_monumber(left, right):
""" """
return MO.factory(left.value * right.value) return MO.factory(left.value * right.value)
@multiply.register(MOnumber, MOFraction) @multiply.register(MOnumber, MOFraction)
@special_case(multiply_filter) @special_case(multiply_filter)
def monumber_mofraction(left, right): def monumber_mofraction(left, right):
@ -108,6 +111,7 @@ def monumber_mofraction(left, right):
num = Tree("*", left, right.numerator) num = Tree("*", left, right.numerator)
return Tree("/", num, right._denominator) return Tree("/", num, right._denominator)
@multiply.register(MOFraction, MOnumber) @multiply.register(MOFraction, MOnumber)
@special_case(multiply_filter) @special_case(multiply_filter)
def mofraction_monumber(left, right): def mofraction_monumber(left, right):
@ -125,6 +129,7 @@ def mofraction_monumber(left, right):
num = Tree("*", left.numerator, right) num = Tree("*", left.numerator, right)
return Tree("/", num, left._denominator) return Tree("/", num, left._denominator)
@multiply.register(MOFraction, MOFraction) @multiply.register(MOFraction, MOFraction)
@special_case(multiply_filter) @special_case(multiply_filter)
def mofraction_mofraction(left, right): def mofraction_mofraction(left, right):
@ -145,6 +150,7 @@ def mofraction_mofraction(left, right):
denom = Tree("*", left.denominator, right.denominator) denom = Tree("*", left.denominator, right.denominator)
return Tree("/", num, denom) return Tree("/", num, denom)
@multiply.register((MOnumber, MOFraction), MOMonomial) @multiply.register((MOnumber, MOFraction), MOMonomial)
@special_case(multiply_filter) @special_case(multiply_filter)
def moscalar_monomonial(left, right): def moscalar_monomonial(left, right):
@ -161,8 +167,9 @@ def moscalar_monomonial(left, right):
> x^4 > x^4
""" """
coefficient = Tree('*', left, right.coefficient) coefficient = Tree("*", left, right.coefficient)
return Tree('*', coefficient, right.strpower) return Tree("*", coefficient, right.strpower)
@multiply.register(MOMonomial, (MOnumber, MOFraction)) @multiply.register(MOMonomial, (MOnumber, MOFraction))
@special_case(multiply_filter) @special_case(multiply_filter)
@ -180,8 +187,9 @@ def monomonial_moscalar(left, right):
> x^4 > x^4
""" """
coefficient = Tree('*', right, left.coefficient) coefficient = Tree("*", right, left.coefficient)
return Tree('*', coefficient, left.strpower) return Tree("*", coefficient, left.strpower)
@multiply.register(MOstr, MOstrPower) @multiply.register(MOstr, MOstrPower)
@special_case(multiply_filter) @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) NotImplementedError: Can't multiply MOstr and MOstrPower if they don'thave same variable (got x and y)
""" """
if left.variable != right.variable: if left.variable != right.variable:
raise NotImplementedError("Can't multiply MOstr and MOstrPower if they don't" raise NotImplementedError(
f"have same variable (got {left.variable} and {right.variable})") "Can't multiply MOstr and MOstrPower if they don't"
return MOstrPower(left.variable, right.power.value+1) f"have same variable (got {left.variable} and {right.variable})"
)
return MOstrPower(left.variable, right.power.value + 1)
@multiply.register(MOstrPower, MOstr) @multiply.register(MOstrPower, MOstr)
@special_case(multiply_filter) @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) NotImplementedError: Can't multiply MOstr and MOstrPower if they don'thave same variable (got x and y)
""" """
if left.variable != right.variable: if left.variable != right.variable:
raise NotImplementedError("Can't multiply MOstr and MOstrPower if they don't" raise NotImplementedError(
f"have same variable (got {left.variable} and {right.variable})") "Can't multiply MOstr and MOstrPower if they don't"
return MOstrPower(left.variable, left.power.value+1) f"have same variable (got {left.variable} and {right.variable})"
)
return MOstrPower(left.variable, left.power.value + 1)
@multiply.register(MOstr, MOstr) @multiply.register(MOstr, MOstr)
@special_case(multiply_filter) @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) NotImplementedError: Can't multiply MOstr and MOstr if they don'thave same variable (got y and x)
""" """
if left.variable != right.variable: if left.variable != right.variable:
raise NotImplementedError("Can't multiply MOstr and MOstr if they don't" raise NotImplementedError(
f"have same variable (got {left.variable} and {right.variable})") "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) return MOstrPower(left.variable, 2)
@multiply.register(MOstrPower, MOstrPower) @multiply.register(MOstrPower, MOstrPower)
@special_case(multiply_filter) @special_case(multiply_filter)
def mostr_mostrpower(left, right): 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) NotImplementedError: Can't multiply MOstrPower and MOstrPower if they don'thave same variable (got x and y)
""" """
if left.variable != right.variable: if left.variable != right.variable:
raise NotImplementedError("Can't multiply MOstrPower and MOstrPower if they don't" raise NotImplementedError(
f"have same variable (got {left.variable} and {right.variable})") "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) power = Tree("+", left.power, right.power)
return Tree("^", left.variable, power) return Tree("^", left.variable, power)
@multiply.register(MOstrPower, MOMonomial) @multiply.register(MOstrPower, MOMonomial)
@special_case(multiply_filter) @special_case(multiply_filter)
def mostrpower_momonomial(left, right): 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) NotImplementedError: Can't multiply MOstrPower and Monomial if they don'thave same variable (got x and y)
""" """
if left.variable != right.variable: if left.variable != right.variable:
raise NotImplementedError("Can't multiply MOstrPower and Monomial if they don't" raise NotImplementedError(
f"have same variable (got {left.variable} and {right.variable})") "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) power = Tree("+", left.power, right.power)
monome = Tree("^", left.variable, power) monome = Tree("^", left.variable, power)
return Tree("*", right.coefficient, monome) return Tree("*", right.coefficient, monome)
@multiply.register(MOMonomial, MOstrPower) @multiply.register(MOMonomial, MOstrPower)
@special_case(multiply_filter) @special_case(multiply_filter)
def momonomial_mostr(left, right): def momonomial_mostr(left, right):
@ -326,12 +349,15 @@ def momonomial_mostr(left, right):
""" """
if left.variable != right.variable: if left.variable != right.variable:
raise NotImplementedError("Can't multiply MOstrPower and Monomial if they don't" raise NotImplementedError(
f"have same variable (got {left.variable} and {right.variable})") "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) power = Tree("+", left.power, right.power)
monome = Tree("^", left.variable, power) monome = Tree("^", left.variable, power)
return Tree("*", left.coefficient, monome) return Tree("*", left.coefficient, monome)
@multiply.register(MOstr, MOMonomial) @multiply.register(MOstr, MOMonomial)
@special_case(multiply_filter) @special_case(multiply_filter)
def mostr_momonomial(left, right): 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) NotImplementedError: Can't multiply MOstr and Monomial if they don'thave same variable (got x and y)
""" """
if left.variable != right.variable: if left.variable != right.variable:
raise NotImplementedError("Can't multiply MOstr and Monomial if they don't" raise NotImplementedError(
f"have same variable (got {left.variable} and {right.variable})") "Can't multiply MOstr and Monomial if they don't"
return MOMonomial(right.coefficient, right.variable, right.power.value+1) f"have same variable (got {left.variable} and {right.variable})"
)
return MOMonomial(right.coefficient, right.variable, right.power.value + 1)
@multiply.register(MOMonomial, MOstr) @multiply.register(MOMonomial, MOstr)
@special_case(multiply_filter) @special_case(multiply_filter)
@ -371,9 +400,12 @@ def momonomial_mostr(left, right):
""" """
if left.variable != right.variable: if left.variable != right.variable:
raise NotImplementedError("Can't multiply MOstr and Monomial if they don't" raise NotImplementedError(
f"have same variable (got {left.variable} and {right.variable})") "Can't multiply MOstr and Monomial if they don't"
return MOMonomial(left.coefficient, left.variable, left.power.value+1) f"have same variable (got {left.variable} and {right.variable})"
)
return MOMonomial(left.coefficient, left.variable, left.power.value + 1)
@multiply.register(MOMonomial, MOMonomial) @multiply.register(MOMonomial, MOMonomial)
@special_case(multiply_filter) @special_case(multiply_filter)
@ -401,15 +433,17 @@ def momonomial_momonomial(left, right):
""" """
if left.variable != right.variable: if left.variable != right.variable:
raise NotImplementedError("Can't multiply MOMonomial and Monomial if they don't" raise NotImplementedError(
f"have same variable (got {left.variable} and {right.variable})") "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) powers = Tree("+", left.power, right.power)
monome = Tree("^", left.variable, powers) monome = Tree("^", left.variable, powers)
coefs = Tree("*", left.coefficient, right.coefficient) coefs = Tree("*", left.coefficient, right.coefficient)
return Tree("*", coefs, monome) return Tree("*", coefs, monome)
@multiply.register((MOnumber, MOFraction, MOstr, MOstrPower, MOMonomial), \
MOpolynomial) @multiply.register((MOnumber, MOFraction, MOstr, MOstrPower, MOMonomial), MOpolynomial)
@special_case(multiply_filter) @special_case(multiply_filter)
def lotsmo_mopolynomial(left, right): def lotsmo_mopolynomial(left, right):
""" Multiply a scalar and a MOMonomial """ Multiply a scalar and a MOMonomial
@ -492,13 +526,11 @@ def lotsmo_mopolynomial(left, right):
""" """
coefs = [Tree("*", left, monom) \ coefs = [Tree("*", left, monom) for monom in list(right.monomials.values())[::-1]]
for monom in list(right.monomials.values())[::-1]\
]
return Tree.from_list("+", coefs) 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) @special_case(multiply_filter)
def mopolynomial_lotsmo(left, right): def mopolynomial_lotsmo(left, right):
""" Multiply a MOpolynomial with nearly everything """ Multiply a MOpolynomial with nearly everything
@ -581,11 +613,10 @@ def mopolynomial_lotsmo(left, right):
| | > 3x^2 | | > 3x^2
""" """
coefs = [Tree("*", monom, right) \ coefs = [Tree("*", monom, right) for monom in list(left.monomials.values())[::-1]]
for monom in list(left.monomials.values())[::-1] \
]
return Tree.from_list("+", coefs) return Tree.from_list("+", coefs)
@multiply.register(MOpolynomial, MOpolynomial) @multiply.register(MOpolynomial, MOpolynomial)
@special_case(multiply_filter) @special_case(multiply_filter)
def mopolynomial_mopolynomial(left, right): def mopolynomial_mopolynomial(left, right):
@ -619,10 +650,11 @@ def mopolynomial_mopolynomial(left, right):
| | | > 4 | | | > 4
""" """
coefs = [Tree("*", l_monom, r_monom) \ coefs = [
for l_monom in list(left.monomials.values())[::-1] \ Tree("*", l_monom, r_monom)
for r_monom in list(right.monomials.values())[::-1] \ for l_monom in list(left.monomials.values())[::-1]
] for r_monom in list(right.monomials.values())[::-1]
]
return Tree.from_list("+", coefs) return Tree.from_list("+", coefs)

View File

@ -28,6 +28,7 @@ power_doc = """ Power of MOs
power = Dispatcher("power", doc=power_doc) power = Dispatcher("power", doc=power_doc)
def power_filter(left, right): def power_filter(left, right):
""" Automatic power on MO """ Automatic power on MO
@ -60,6 +61,7 @@ def power_filter(left, right):
except TypeError: except TypeError:
pass pass
@power.register(MOnumber, MOnumber) @power.register(MOnumber, MOnumber)
@special_case(power_filter) @special_case(power_filter)
def monumber_monumber(left, right): def monumber_monumber(left, right):
@ -73,6 +75,7 @@ def monumber_monumber(left, right):
""" """
return MO.factory(left.value ** right.value) return MO.factory(left.value ** right.value)
@power.register(MOFraction, MOnumber) @power.register(MOFraction, MOnumber)
@special_case(power_filter) @special_case(power_filter)
def mofraction_monumber(left, right): def mofraction_monumber(left, right):
@ -93,6 +96,7 @@ def mofraction_monumber(left, right):
denom = Tree("^", left.denominator, right) denom = Tree("^", left.denominator, right)
return Tree("/", num, denom) return Tree("/", num, denom)
@power.register(MOstrPower, MOnumber) @power.register(MOstrPower, MOnumber)
@special_case(power_filter) @special_case(power_filter)
def mostrpower_monumber(left, right): def mostrpower_monumber(left, right):
@ -110,6 +114,7 @@ def mostrpower_monumber(left, right):
power = Tree("*", left.power, right) power = Tree("*", left.power, right)
return Tree("^", left.variable, power) return Tree("^", left.variable, power)
@power.register(MOMonomial, MOnumber) @power.register(MOMonomial, MOnumber)
@special_case(power_filter) @special_case(power_filter)
def mostrpower_monumber(left, right): def mostrpower_monumber(left, right):
@ -133,6 +138,7 @@ def mostrpower_monumber(left, right):
strpower = Tree("^", left.variable, power) strpower = Tree("^", left.variable, power)
return Tree("*", coef, strpower) return Tree("*", coef, strpower)
@power.register(MOpolynomial, MOnumber) @power.register(MOpolynomial, MOnumber)
@special_case(power_filter) @special_case(power_filter)
def mopolynomial_monumber(left, right): def mopolynomial_monumber(left, right):
@ -145,8 +151,7 @@ def mopolynomial_monumber(left, right):
> 3x^2 - 2x + 1 > 3x^2 - 2x + 1
> 3x^2 - 2x + 1 > 3x^2 - 2x + 1
""" """
return Tree.from_list("*", [left]*right.value) return Tree.from_list("*", [left] * right.value)
# ----------------------------- # -----------------------------

View File

@ -14,17 +14,23 @@ from functools import wraps
__all__ = ["coroutine", "STOOOP", "RESTAAART"] __all__ = ["coroutine", "STOOOP", "RESTAAART"]
def coroutine(func): def coroutine(func):
@wraps(func) @wraps(func)
def start(*args, **kwargs): def start(*args, **kwargs):
cr = func(*args, **kwargs) cr = func(*args, **kwargs)
next(cr) next(cr)
return cr return cr
return start return start
class STOOOP(Exception): pass
class RESTAAART(Exception): pass
class STOOOP(Exception):
pass
class RESTAAART(Exception):
pass
# ----------------------------- # -----------------------------

View File

@ -8,32 +8,20 @@
__all__ = ["OperatorError", "OPERATORS", "is_operator"] __all__ = ["OperatorError", "OPERATORS", "is_operator"]
class OperatorError(Exception): class OperatorError(Exception):
pass pass
OPERATORS = { OPERATORS = {
"+": {'repr': "+", "+": {"repr": "+", "arity": 2, "precedence": 0},
'arity': 2, "-": {"repr": "-", "arity": 1, "precedence": 1},
'precedence': 0, "*": {"repr": "*", "arity": 2, "precedence": 2},
}, "/": {"repr": "/", "arity": 2, "precedence": 3},
"-": {'repr': "-", "^": {"repr": "^", "arity": 2, "precedence": 4},
'arity': 1,
'precedence': 1,
},
"*": {'repr': "*",
'arity': 2,
'precedence': 2,
},
"/": {'repr': "/",
'arity': 2,
'precedence': 3,
},
"^": {'repr': "^",
'arity': 2,
'precedence': 4,
},
} }
def is_operator(string): def is_operator(string):
""" Return whether a string is an operator or not """ Return whether a string is an operator or not

View File

@ -14,11 +14,8 @@ import random
__all__ = ["reject_random", "filter_random", "FilterRandom"] __all__ = ["reject_random", "filter_random", "FilterRandom"]
def reject_random(min_value = -10,
max_value = 10, def reject_random(min_value=-10, max_value=10, rejected=[0, 1], accept_callbacks=[]):
rejected = [0, 1],
accept_callbacks=[],
):
""" Generate a random integer with the rejection method """ Generate a random integer with the rejection method
:param name: name of the Integer :param name: name of the Integer
@ -61,11 +58,8 @@ def reject_random(min_value = -10,
return candidate return candidate
def filter_random(min_value = -10,
max_value = 10, def filter_random(min_value=-10, max_value=10, rejected=[0, 1], accept_callbacks=[]):
rejected = [0, 1],
accept_callbacks=[],
):
""" Generate a random integer by filtering then choosing a candidate """ Generate a random integer by filtering then choosing a candidate
:param name: name of the Integer :param name: name of the Integer
@ -99,37 +93,44 @@ def filter_random(min_value = -10,
>>> filter_random() >>> filter_random()
6 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 = {c for c in candidates if c not in rejected}
candidates = [candidate for candidate in candidates \ candidates = [
if all(c(candidate) for c in accept_callbacks)] candidate
for candidate in candidates
if all(c(candidate) for c in accept_callbacks)
]
if len(candidates) == 0: 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) return random.choice(candidates)
class FilterRandom(object): class FilterRandom(object):
""" Integer random generator which filter then choose candidate """ 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 # TODO: Faire un cache pour éviter de reconstruire les listes à chaque fois |ven. déc. 21 19:07:42 CET 2018
def __init__(self, def __init__(
rejected = [0, 1], self, rejected=[0, 1], accept_callbacks=[], min_value=-10, max_value=10
accept_callbacks=[], ):
min_value = -10,
max_value = 10,
):
self.conditions = (lambda x: x not in rejected,) + tuple(accept_callbacks) self.conditions = (lambda x: x not in rejected,) + tuple(accept_callbacks)
self._min = min_value self._min = min_value
self._max = max_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 \ self._candidates = {
if all(c(candidate) for c in self.conditions) } candidate
for candidate in candidates
if all(c(candidate) for c in self.conditions)
}
def add_candidates(self, low, high): def add_candidates(self, low, high):
""" Add candidates between low and high to _candidates """ """ Add candidates between low and high to _candidates """
@ -144,13 +145,16 @@ class FilterRandom(object):
else: else:
useless_high = True useless_high = True
if not(useless_low and useless_high): if not (useless_low and useless_high):
candidates = set(range(low, high+1)) candidates = set(range(low, high + 1))
self._candidates = self._candidates.union({ self._candidates = self._candidates.union(
candidate for candidate in candidates \ {
if all(c(candidate) for c in self.conditions) \ candidate
}) for candidate in candidates
if all(c(candidate) for c in self.conditions)
}
)
def candidates(self, min_value=-10, max_value=10): def candidates(self, min_value=-10, max_value=10):
""" Return candidates between min_value and max_value """ """ Return candidates between min_value and max_value """

View File

@ -8,7 +8,8 @@
from mapytex.calculus.core.operator import OPERATORS from mapytex.calculus.core.operator import OPERATORS
__all__ = ['tree2tex'] __all__ = ["tree2tex"]
def plus2tex(left, right): def plus2tex(left, right):
r""" + rendering r""" + rendering
@ -51,6 +52,7 @@ def plus2tex(left, right):
return f"{left_} {right_}" return f"{left_} {right_}"
def minus2tex(left, right): def minus2tex(left, right):
r""" - rendering r""" - rendering
@ -64,7 +66,7 @@ def minus2tex(left, right):
""" """
try: try:
right_need_parenthesis = False right_need_parenthesis = False
if OPERATORS[right.node]["precedence"] < OPERATORS['-']["precedence"]: if OPERATORS[right.node]["precedence"] < OPERATORS["-"]["precedence"]:
right_need_parenthesis = True right_need_parenthesis = True
except AttributeError: except AttributeError:
right_ = right.__tex__ right_ = right.__tex__
@ -76,6 +78,7 @@ def minus2tex(left, right):
return f"- {right_}" return f"- {right_}"
def mul2tex(left, right): def mul2tex(left, right):
r""" * rendering r""" * rendering
@ -101,14 +104,16 @@ def mul2tex(left, right):
right_ = render_with_parenthesis(right, "*") right_ = render_with_parenthesis(right, "*")
display_time = True display_time = True
if (right_[0].isalpha() and (left_.isnumeric() or left_.isdecimal())) or \ if (right_[0].isalpha() and (left_.isnumeric() or left_.isdecimal())) or right_[
right_[0] == '(': 0
display_time = False ] == "(":
display_time = False
if display_time: if display_time:
return f"{left_} \\times {right_}" return f"{left_} \\times {right_}"
return f"{left_}{right_}" return f"{left_}{right_}"
def div2tex(left, right): def div2tex(left, right):
r""" / rendering r""" / rendering
@ -137,6 +142,7 @@ def div2tex(left, right):
return "\\frac{" + left_ + "}{" + right_ + "}" return "\\frac{" + left_ + "}{" + right_ + "}"
def pow2tex(left, right): def pow2tex(left, right):
r""" ^ rendering r""" ^ rendering
@ -159,7 +165,7 @@ def pow2tex(left, right):
""" """
try: try:
left_need_parenthesis = False left_need_parenthesis = False
if OPERATORS[left.node]["precedence"] < OPERATORS['^']["precedence"]: if OPERATORS[left.node]["precedence"] < OPERATORS["^"]["precedence"]:
left_need_parenthesis = True left_need_parenthesis = True
except AttributeError: except AttributeError:
left_ = left.__tex__ left_ = left.__tex__
@ -185,7 +191,10 @@ def render_with_parenthesis(subtree, operator):
subtree.node subtree.node
except AttributeError: except AttributeError:
try: try:
if OPERATORS[subtree.MAINOP]["precedence"] < OPERATORS[operator]["precedence"]: if (
OPERATORS[subtree.MAINOP]["precedence"]
< OPERATORS[operator]["precedence"]
):
subtree_need_parenthesis = True subtree_need_parenthesis = True
except (AttributeError, KeyError): except (AttributeError, KeyError):
pass pass
@ -200,13 +209,8 @@ def render_with_parenthesis(subtree, operator):
return subtree_ return subtree_
OPERATOR2TEX = { OPERATOR2TEX = {"+": plus2tex, "-": minus2tex, "*": mul2tex, "/": div2tex, "^": pow2tex}
"+": plus2tex,
"-": minus2tex,
"*": mul2tex,
"/": div2tex,
"^": pow2tex,
}
def tree2tex(tree): def tree2tex(tree):
r""" Convert a tree into its tex version r""" Convert a tree into its tex version

View File

@ -8,7 +8,8 @@
from ..operator import OPERATORS from ..operator import OPERATORS
__all__ = ['tree2txt'] __all__ = ["tree2txt"]
def plus2txt(left, right): def plus2txt(left, right):
""" + rendering """ + rendering
@ -41,6 +42,7 @@ def plus2txt(left, right):
return f"{left_} {right_}" return f"{left_} {right_}"
def minus2txt(left, right): def minus2txt(left, right):
""" - rendering """ - rendering
@ -54,7 +56,7 @@ def minus2txt(left, right):
""" """
try: try:
right_need_parenthesis = False right_need_parenthesis = False
if OPERATORS[right.node]["precedence"] < OPERATORS['-']["precedence"]: if OPERATORS[right.node]["precedence"] < OPERATORS["-"]["precedence"]:
right_need_parenthesis = True right_need_parenthesis = True
except AttributeError: except AttributeError:
right_ = right.__txt__ right_ = right.__txt__
@ -66,6 +68,7 @@ def minus2txt(left, right):
return f"- {right_}" return f"- {right_}"
def mul2txt(left, right): def mul2txt(left, right):
""" * rendering """ * rendering
@ -96,9 +99,9 @@ def mul2txt(left, right):
if right_[0].isalpha(): if right_[0].isalpha():
# TODO: C'est bien beurk en dessous... |ven. déc. 21 12:03:07 CET 2018 # 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 display_time = False
elif right_[0] == '(': elif right_[0] == "(":
display_time = False display_time = False
if display_time: if display_time:
@ -106,6 +109,7 @@ def mul2txt(left, right):
else: else:
return f"{left_}{right_}" return f"{left_}{right_}"
def div2txt(left, right): def div2txt(left, right):
""" / rendering """ / rendering
@ -125,7 +129,7 @@ def div2txt(left, right):
""" """
try: try:
left_need_parenthesis = False left_need_parenthesis = False
if OPERATORS[left.node]["precedence"] < OPERATORS['/']["precedence"]: if OPERATORS[left.node]["precedence"] < OPERATORS["/"]["precedence"]:
left_need_parenthesis = True left_need_parenthesis = True
except AttributeError: except AttributeError:
left_ = left.__txt__ left_ = left.__txt__
@ -136,7 +140,7 @@ def div2txt(left, right):
left_ = tree2txt(left) left_ = tree2txt(left)
try: try:
right_need_parenthesis = False right_need_parenthesis = False
if OPERATORS[right.node]["precedence"] < OPERATORS['/']["precedence"]: if OPERATORS[right.node]["precedence"] < OPERATORS["/"]["precedence"]:
right_need_parenthesis = True right_need_parenthesis = True
except AttributeError: except AttributeError:
right_ = right.__txt__ right_ = right.__txt__
@ -148,6 +152,7 @@ def div2txt(left, right):
return f"{left_} / {right_}" return f"{left_} / {right_}"
def pow2txt(left, right): def pow2txt(left, right):
""" ^ rendering """ ^ rendering
@ -169,7 +174,7 @@ def pow2txt(left, right):
try: try:
right_need_parenthesis = False right_need_parenthesis = False
if OPERATORS[right.node]["precedence"] < OPERATORS['^']["precedence"]: if OPERATORS[right.node]["precedence"] < OPERATORS["^"]["precedence"]:
right_need_parenthesis = True right_need_parenthesis = True
except AttributeError: except AttributeError:
right_ = right.__txt__ right_ = right.__txt__
@ -181,13 +186,17 @@ def pow2txt(left, right):
return f"{left_}^{right_}" return f"{left_}^{right_}"
def render_with_parenthesis(subtree, operator): def render_with_parenthesis(subtree, operator):
subtree_need_parenthesis = False subtree_need_parenthesis = False
try: try:
subtree.node subtree.node
except AttributeError: except AttributeError:
try: try:
if OPERATORS[subtree.MAINOP]["precedence"] < OPERATORS[operator]["precedence"]: if (
OPERATORS[subtree.MAINOP]["precedence"]
< OPERATORS[operator]["precedence"]
):
subtree_need_parenthesis = True subtree_need_parenthesis = True
except (AttributeError, KeyError): except (AttributeError, KeyError):
pass pass
@ -201,13 +210,9 @@ def render_with_parenthesis(subtree, operator):
return f"({subtree_})" return f"({subtree_})"
return subtree_ return subtree_
OPERATOR2TXT = {
"+": plus2txt, OPERATOR2TXT = {"+": plus2txt, "-": minus2txt, "*": mul2txt, "/": div2txt, "^": pow2txt}
"-": minus2txt,
"*": mul2txt,
"/": div2txt,
"^": pow2txt,
}
def tree2txt(tree): def tree2txt(tree):
""" Convert a tree into its txt version """ Convert a tree into its txt version
@ -224,6 +229,7 @@ def tree2txt(tree):
'2 + 3 * 4' '2 + 3 * 4'
""" """
from ..tree import Tree from ..tree import Tree
if not isinstance(tree, Tree): if not isinstance(tree, Tree):
raise ValueError(f"Can only render a Tree (got {type(tree).__name__}: {tree})") raise ValueError(f"Can only render a Tree (got {type(tree).__name__}: {tree})")
return OPERATOR2TXT[tree.node](tree.left_value, tree.right_value) return OPERATOR2TXT[tree.node](tree.left_value, tree.right_value)

View File

@ -16,7 +16,8 @@ from .coroutine import *
from .operator import is_operator from .operator import is_operator
from .MO import moify from .MO import moify
__all__ = ["str2", ] __all__ = ["str2"]
class ParsingError(Exception): class ParsingError(Exception):
pass pass
@ -44,6 +45,7 @@ def maybe_it_is(cara):
>>> it_is_iuo("uo") >>> it_is_iuo("uo")
False False
""" """
def func(c): def func(c):
if c == cara: if c == cara:
return True return True
@ -51,20 +53,25 @@ def maybe_it_is(cara):
return "maybe" return "maybe"
else: else:
return False return False
return func return func
def something_in(cara_list): def something_in(cara_list):
""" Return a function which sais whether a caracter is in cara_list or not """ Return a function which sais whether a caracter is in cara_list or not
""" """
def func(c): def func(c):
if c in cara_list: if c in cara_list:
return True return True
else: else:
return False return False
return func return func
@coroutine @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 """ Sink which is looking for term and yield replace founded patern
with the lenght of the accumulation. with the lenght of the accumulation.
@ -165,7 +172,7 @@ def lookfor(condition, replace = lambda x:''.join(x)):
else: else:
if c is not None: if c is not None:
acc.append(c) acc.append(c)
found = condition(''.join([str(i) for i in acc])) found = condition("".join([str(i) for i in acc]))
if found == "maybe": if found == "maybe":
ans = "maybe" ans = "maybe"
elif found: elif found:
@ -175,6 +182,7 @@ def lookfor(condition, replace = lambda x:''.join(x)):
ans = False ans = False
acc = [] acc = []
@coroutine @coroutine
def remember_lookfor(lookfor): def remember_lookfor(lookfor):
""" Coroutine which remember sent value before the lookfor finds something """ Coroutine which remember sent value before the lookfor finds something
@ -235,8 +243,9 @@ def remember_lookfor(lookfor):
acc.append(c) acc.append(c)
ans = False ans = False
@coroutine @coroutine
def concurent_broadcast(target, lookfors = []): def concurent_broadcast(target, lookfors=[]):
""" Coroutine which broadcasts multiple lookfor coroutines and reinitializes """ Coroutine which broadcasts multiple lookfor coroutines and reinitializes
them when one found something them when one found something
@ -316,6 +325,7 @@ def concurent_broadcast(target, lookfors = []):
target_.send(i) target_.send(i)
yield target_.throw(err) yield target_.throw(err)
@coroutine @coroutine
def missing_times(target): def missing_times(target):
""" Coroutine which send a "*" when it's missing """ Coroutine which send a "*" when it's missing
@ -379,15 +389,14 @@ def missing_times(target):
previous = None previous = None
if isinstance(tok, str): if isinstance(tok, str):
if tok == '(': if tok == "(":
target_.send("*") target_.send("*")
elif not is_operator(tok) and tok != ')': elif not is_operator(tok) and tok != ")":
target_.send("*") target_.send("*")
if isinstance(tok, int) or \ if isinstance(tok, int) or (
(isinstance(tok, str) and \ isinstance(tok, str) and not is_operator(tok) and not tok == "("
not is_operator(tok) and \ ):
not tok == '('):
previous = tok previous = tok
target_.send(tok) target_.send(tok)
@ -395,6 +404,7 @@ def missing_times(target):
except STOOOP as err: except STOOOP as err:
yield target_.throw(err) yield target_.throw(err)
@coroutine @coroutine
def lookforNumbers(target): def lookforNumbers(target):
""" Coroutine which parse numbers """ Coroutine which parse numbers
@ -467,12 +477,12 @@ def lookforNumbers(target):
try: try:
int(tok) int(tok)
except ValueError: except ValueError:
if tok == '.': if tok == ".":
if current.replace("-", "", 1).isdigit(): if current.replace("-", "", 1).isdigit():
current += tok current += tok
else: else:
raise ParsingError(f"Can't build decimal with '{current}'") raise ParsingError(f"Can't build decimal with '{current}'")
elif tok == '-': elif tok == "-":
if current == "": if current == "":
current = tok current = tok
elif current == ("("): elif current == ("("):
@ -489,13 +499,15 @@ def lookforNumbers(target):
target_.send(typifiy_numbers(current)) target_.send(typifiy_numbers(current))
except InvalidOperation: except InvalidOperation:
target_.send(current) target_.send(current)
target_.send('+') target_.send("+")
current = tok current = tok
else: else:
if current == "": if current == "":
current = tok current = tok
elif is_operator(current) and is_operator(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: else:
try: try:
target_.send(typifiy_numbers(current)) target_.send(typifiy_numbers(current))
@ -522,6 +534,7 @@ def lookforNumbers(target):
target_.send(current) target_.send(current)
yield target_.throw(err) yield target_.throw(err)
def typifiy_numbers(number): def typifiy_numbers(number):
""" Transform a str number into a integer or a decimal """ """ Transform a str number into a integer or a decimal """
try: try:
@ -529,6 +542,7 @@ def typifiy_numbers(number):
except ValueError: except ValueError:
return Decimal(number) return Decimal(number)
@coroutine @coroutine
def pparser(target): def pparser(target):
""" Parenthesis parser sink """ Parenthesis parser sink
@ -565,6 +579,7 @@ def pparser(target):
except STOOOP as err: except STOOOP as err:
yield target_.throw(err) yield target_.throw(err)
@coroutine @coroutine
def list_sink(): def list_sink():
""" Testing sink for coroutines """ Testing sink for coroutines
@ -588,6 +603,7 @@ def list_sink():
except STOOOP: except STOOOP:
yield ans yield ans
def str2(sink, convert_to_mo=True): def str2(sink, convert_to_mo=True):
""" Return a pipeline which parse an expression with the sink as an endpont """ 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) lfop = lookfor(is_operator)
operator_corout = partial(concurent_broadcast, lookfors=[lfop]) operator_corout = partial(concurent_broadcast, lookfors=[lfop])
def pipeline(expression): def pipeline(expression):
if convert_to_mo: 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: else:
str2_corout = lookforNumbers(operator_corout(missing_times(pparser(sink)))) str2_corout = lookforNumbers(operator_corout(missing_times(pparser(sink))))
for i in expression.replace(" ",""): for i in expression.replace(" ", ""):
str2_corout.send(i) str2_corout.send(i)
a = str2_corout.throw(STOOOP) a = str2_corout.throw(STOOOP)

View File

@ -9,10 +9,7 @@ Tree class
""" """
from .tree_tools import (to_nested_parenthesis, from .tree_tools import to_nested_parenthesis, postfix_concatenate, show_tree
postfix_concatenate,
show_tree,
)
from .coroutine import coroutine, STOOOP from .coroutine import coroutine, STOOOP
from .str2 import str2 from .str2 import str2
from .operator import OPERATORS, is_operator from .operator import OPERATORS, is_operator
@ -20,7 +17,7 @@ from .operator import OPERATORS, is_operator
__all__ = ["Tree", "MutableTree"] __all__ = ["Tree", "MutableTree"]
class Tree(): class Tree:
""" """
Binary tree Binary tree
@ -118,9 +115,8 @@ class Tree():
except TypeError: except TypeError:
raise ValueError("Nested parenthesis are not composed of lists") raise ValueError("Nested parenthesis are not composed of lists")
if nested_len != 2 and \ if nested_len != 2 and num_len != 2:
num_len != 2: raise ValueError("Nested parenthesis don't have right shape")
raise ValueError("Nested parenthesis don't have right shape")
node = nested_parenthesis[0] node = nested_parenthesis[0]
@ -185,8 +181,8 @@ class Tree():
l_value = leafs[0] l_value = leafs[0]
r_value = cls.from_list(node, leafs[1:]) r_value = cls.from_list(node, leafs[1:])
else: else:
l_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:]) r_value = cls.from_list(node, leafs[len_leafs // 2 :])
return cls(node, l_value, r_value) return cls(node, l_value, r_value)
@classmethod @classmethod
@ -241,9 +237,10 @@ class Tree():
left_value = tree.left_value left_value = tree.left_value
right_value = tree.right_value right_value = tree.right_value
if node is None or \ if node is None or right_value is None:
right_value is None: raise TypeError(
raise TypeError(f"Tree can't have empty node or leaf. Got node = {node} and right_value = {right_value}") f"Tree can't have empty node or leaf. Got node = {node} and right_value = {right_value}"
)
try: try:
left_value.IMLEAF left_value.IMLEAF
@ -336,16 +333,14 @@ class Tree():
left_is_leaf = 0 left_is_leaf = 0
try: try:
left_applied = self.left_value.\ left_applied = self.left_value.apply_on_last_level(function)
apply_on_last_level(function)
except AttributeError: except AttributeError:
left_applied = self.left_value left_applied = self.left_value
left_is_leaf = 1 left_is_leaf = 1
right_is_leaf = 0 right_is_leaf = 0
try: try:
right_applied = self.right_value.\ right_applied = self.right_value.apply_on_last_level(function)
apply_on_last_level(function)
except AttributeError: except AttributeError:
right_applied = self.right_value right_applied = self.right_value
right_is_leaf = 1 right_is_leaf = 1
@ -401,7 +396,7 @@ class Tree():
except NotImplementedError: except NotImplementedError:
return Tree(self.node, left_value, right_value) 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. """ Generator which yield all the leaf value of the tree.
Callback act on every leaf. Callback act on every leaf.
@ -424,7 +419,7 @@ class Tree():
except AttributeError: except AttributeError:
yield callback(self.right_value) 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. """ Generator which yield all nodes of the tree.
Callback act on every nodes. Callback act on every nodes.
@ -653,7 +648,7 @@ class Tree():
else: else:
return self.left_value return self.left_value
def balance(self, exclude_nodes = []): def balance(self, exclude_nodes=[]):
""" Recursively balance the tree without permutting different nodes """ Recursively balance the tree without permutting different nodes
:return: balanced tree :return: balanced tree
@ -836,22 +831,22 @@ class Tree():
except AttributeError: except AttributeError:
r_depth = 1 r_depth = 1
if l_depth > r_depth+1 and\ if (
self.node == self.left_value.node and \ l_depth > r_depth + 1
self.node not in exclude_nodes: and self.node == self.left_value.node
and self.node not in exclude_nodes
):
new_left = self.left_value.long_branch new_left = self.left_value.long_branch
new_right = Tree(self.node, new_right = Tree(self.node, self.left_value.short_branch, self.right_value)
self.left_value.short_branch,
self.right_value)
return Tree(self.node, new_left, new_right).balance(exclude_nodes) return Tree(self.node, new_left, new_right).balance(exclude_nodes)
if r_depth > l_depth+1 and\ if (
self.node == self.right_value.node and \ r_depth > l_depth + 1
self.node not in exclude_nodes: and self.node == self.right_value.node
and self.node not in exclude_nodes
):
new_right = self.right_value.long_branch new_right = self.right_value.long_branch
new_left = Tree(self.node, new_left = Tree(self.node, self.left_value, self.right_value.short_branch)
self.left_value,
self.right_value.short_branch)
return Tree(self.node, new_left, new_right).balance(exclude_nodes) return Tree(self.node, new_left, new_right).balance(exclude_nodes)
try: try:
@ -874,10 +869,8 @@ class MutableTree(Tree):
It is used to build a new tree before fixing it into a Tree It is used to build a new tree before fixing it into a Tree
""" """
def __init__(self,
node = None, def __init__(self, node=None, left_value=None, right_value=None):
left_value = None,
right_value = None):
""" """
Initiate a tree with potentialy None values Initiate a tree with potentialy None values
@ -1024,7 +1017,10 @@ class MutableTree(Tree):
try: try:
ans.set_node(c) ans.set_node(c)
except ValueError: 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 # the operation has to be done first
if nested_tree is not None: if nested_tree is not None:
b_tree = cls(c, nested_tree, None) b_tree = cls(c, nested_tree, None)
@ -1124,7 +1120,9 @@ class MutableTree(Tree):
try: try:
self.right_value.append(value) self.right_value.append(value)
except AttributeError: 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): def append(self, value):
""" Append the value at the bottom of the tree. """ Append the value at the bottom of the tree.
@ -1196,7 +1194,7 @@ class MutableTree(Tree):
> None > None
""" """
#self_cp = MutableTree.from_any_tree(self) # self_cp = MutableTree.from_any_tree(self)
self_cp = MutableTree() self_cp = MutableTree()
self_cp.set_node(self.node) self_cp.set_node(self.node)
self_cp.set_left_value(self.left_value) 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 """ Tree which concider every subtree with a node different from itself
as a Leaf as a Leaf
""" """
def map_on_leaf(self, function): def map_on_leaf(self, function):
""" Map on leafs a function """ Map on leafs a function
@ -1492,10 +1491,9 @@ class AssocialTree(Tree):
t = Tree.from_list(self.node, balanced_leafs) t = Tree.from_list(self.node, balanced_leafs)
return t return t
def organise_by(self, def organise_by(
signature=lambda x: type(x), self, signature=lambda x: type(x), recursive=True, exclude_nodes=[]
recursive=True, ):
exclude_nodes=[]):
""" Reoganise AssocialTree base on self order and groups by signature """ Reoganise AssocialTree base on self order and groups by signature
:param signature: grouping function (default type) :param signature: grouping function (default type)
@ -1648,11 +1646,11 @@ class AssocialTree(Tree):
except AttributeError: except AttributeError:
return leaf return leaf
return AssocialTree.from_any_tree(tree).\ return AssocialTree.from_any_tree(tree).map_on_leaf(contaminate_organise)
map_on_leaf(contaminate_organise)
return tree return tree
if __name__ == "__main__": if __name__ == "__main__":
a = MutableTree.from_str("(1+2)*3") a = MutableTree.from_str("(1+2)*3")
print(a) print(a)

View File

@ -17,6 +17,7 @@ __all__ = []
# Functions on (op, left, right) # Functions on (op, left, right)
def to_nested_parenthesis(op, left, right): def to_nested_parenthesis(op, left, right):
""" Get nested form for arguments """ Get nested form for arguments
@ -27,6 +28,7 @@ def to_nested_parenthesis(op, left, right):
""" """
return (op, (left, right)) return (op, (left, right))
def infix_str_concatenate(op, left, right): def infix_str_concatenate(op, left, right):
""" Concatenate arguments placing op on the middle. """ Concatenate arguments placing op on the middle.
@ -37,6 +39,7 @@ def infix_str_concatenate(op, left, right):
""" """
return f"{left} {op} {right}" return f"{left} {op} {right}"
def postfix_concatenate(op, left, right): def postfix_concatenate(op, left, right):
""" Concatenate arguments placing op on the middle. """ Concatenate arguments placing op on the middle.
@ -61,6 +64,7 @@ def postfix_concatenate(op, left, right):
return left_tokens + right_tokens + [op] return left_tokens + right_tokens + [op]
def show_tree(op, left, right, sep="|", node_caracter=">"): def show_tree(op, left, right, sep="|", node_caracter=">"):
""" Shape argument to make nice Tree display """ 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()) right_slided = leaf_suffix.join(str(right).splitlines())
return node_suffix.join([op, left_slided, right_slided]) return node_suffix.join([op, left_slided, right_slided])
# ----------------------------- # -----------------------------
# Reglages pour 'vim' # Reglages pour 'vim'
# vim:set autoindent expandtab tabstop=4 shiftwidth=4: # vim:set autoindent expandtab tabstop=4 shiftwidth=4:

View File

@ -12,6 +12,7 @@ Typing with MO
from .exceptions import TypingError from .exceptions import TypingError
from .add import add from .add import add
# from .minus import minus # from .minus import minus
from .multiply import multiply from .multiply import multiply
from .divide import divide from .divide import divide
@ -25,18 +26,18 @@ from ..MO.polynomial import MOpolynomial
from itertools import product from itertools import product
from tabulate import tabulate from tabulate import tabulate
MOS = [ MOnumber, MOstr, MOFraction, MOstrPower, MOMonomial, MOpolynomial] MOS = [MOnumber, MOstr, MOFraction, MOstrPower, MOMonomial, MOpolynomial]
OPERATIONS = { OPERATIONS = {
"+": add, "+": add,
# "-": minus, # "-": minus,
"*": multiply, "*": multiply,
"/": divide, "/": divide,
"^": power, "^": 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 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") raise NotImplementedError(f"Unknown operation ({node}) in typing")
return operation(left_v, right_v) return operation(left_v, right_v)
def typing_capacities(node): def typing_capacities(node):
""" Test an operation through all MOs """ Test an operation through all MOs
@ -59,21 +61,19 @@ def typing_capacities(node):
""" """
op = OPERATIONS[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: for left_mo in MOS:
lines.append( lines.append([left_mo.__name__] + [(left_mo, i) in op.funcs for i in MOS])
[left_mo.__name__] + \
[(left_mo, i) in op.funcs for i in MOS]
)
return lines return lines
def describe_typing(): def describe_typing():
""" Explain which operations are handle by typing """ """ Explain which operations are handle by typing """
ans = "Implemented typing operations among MOs\n" ans = "Implemented typing operations among MOs\n"
for op in OPERATIONS: for op in OPERATIONS:
ans += "\n" ans += "\n"
ans += tabulate(typing_capacities(op), tablefmt='grid') ans += tabulate(typing_capacities(op), tablefmt="grid")
return ans return ans

View File

@ -27,6 +27,7 @@ add_doc = """ Add MOs
add = Dispatcher("add", doc=add_doc) add = Dispatcher("add", doc=add_doc)
@add.register((MOnumber, MOFraction), MOstr) @add.register((MOnumber, MOFraction), MOstr)
def moscalar_mostr(left, right): def moscalar_mostr(left, right):
""" add a scalar with a letter to create a MOpolynomial """ add a scalar with a letter to create a MOpolynomial
@ -41,6 +42,7 @@ def moscalar_mostr(left, right):
""" """
return MOpolynomial(right, [left, 1]) return MOpolynomial(right, [left, 1])
@add.register(MOstr, (MOnumber, MOFraction)) @add.register(MOstr, (MOnumber, MOFraction))
def mostr_moscalar(left, right): def mostr_moscalar(left, right):
""" add a scalar with a letter to create a MOpolynomial """ add a scalar with a letter to create a MOpolynomial
@ -55,6 +57,7 @@ def mostr_moscalar(left, right):
""" """
return MOpolynomial(left, [right, 1]) return MOpolynomial(left, [right, 1])
@add.register((MOnumber, MOFraction), MOstrPower) @add.register((MOnumber, MOFraction), MOstrPower)
def moscalar_mostrpower(left, right): def moscalar_mostrpower(left, right):
""" add a scalar with a letter to create a MOpolynomial """ 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}) return MOpolynomial(right.variable, {0: left, right.power: 1})
@add.register(MOstrPower, (MOnumber, MOFraction)) @add.register(MOstrPower, (MOnumber, MOFraction))
def mostrpower_moscalar(left, right): def mostrpower_moscalar(left, right):
""" add a scalar with a letter to create a MOpolynomial """ 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}) return MOpolynomial(left.variable, {0: right, left.power: 1})
@add.register((MOnumber, MOFraction), MOMonomial) @add.register((MOnumber, MOFraction), MOMonomial)
def moscalar_momonomial(left, right): def moscalar_momonomial(left, right):
""" add a scalar with a MOMonomial to create a MOpolynomial """ add a scalar with a MOMonomial to create a MOpolynomial
@ -95,9 +100,8 @@ def moscalar_momonomial(left, right):
>>> add(a, b) >>> add(a, b)
<MOpolynomial 1 / 5 + 3x^4> <MOpolynomial 1 / 5 + 3x^4>
""" """
return MOpolynomial(right.variable, return MOpolynomial(right.variable, {right.power: right.coefficient, 0: left})
{right.power: right.coefficient, 0: left}
)
@add.register(MOMonomial, (MOnumber, MOFraction)) @add.register(MOMonomial, (MOnumber, MOFraction))
def momonial_moscalar(left, right): def momonial_moscalar(left, right):
@ -112,9 +116,8 @@ def momonial_moscalar(left, right):
<MOpolynomial 3x^4 + 1 / 5> <MOpolynomial 3x^4 + 1 / 5>
""" """
return MOpolynomial(left.variable, return MOpolynomial(left.variable, {0: right, left.power: left.coefficient})
{0: right, left.power: left.coefficient}
)
@add.register((MOnumber, MOFraction), MOpolynomial) @add.register((MOnumber, MOFraction), MOpolynomial)
def moscalar_mopolynomial(left, right): def moscalar_mopolynomial(left, right):
@ -129,13 +132,16 @@ def moscalar_mopolynomial(left, right):
<MOpolynomial 1 / 5 + 3x^2 + 2x> <MOpolynomial 1 / 5 + 3x^2 + 2x>
""" """
if 0 in right.coefficients.keys(): 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} new_coefs = {**right.coefficients}
#! Need to be add at the end to be printed at the beginning #! Need to be add at the end to be printed at the beginning
new_coefs[0] = left new_coefs[0] = left
return MOpolynomial(right.variable, new_coefs) return MOpolynomial(right.variable, new_coefs)
@add.register(MOpolynomial, (MOnumber, MOFraction)) @add.register(MOpolynomial, (MOnumber, MOFraction))
def mopolynomial_moscalar(left, right): def mopolynomial_moscalar(left, right):
""" add a scalar with a MOpolynomial to create a MOpolynomial """ 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} new_coefs = {**new_coefs, **left.coefficients}
return MOpolynomial(left.variable, new_coefs) return MOpolynomial(left.variable, new_coefs)
@add.register(MOstr, MOstr) @add.register(MOstr, MOstr)
def mostr_mostr(left, right): def mostr_mostr(left, right):
""" add 2 mostr """ add 2 mostr
@ -167,7 +174,8 @@ def mostr_mostr(left, right):
""" """
if left != right: if left != right:
raise NotImplementedError("Can't add 2 Mostr without same letter") raise NotImplementedError("Can't add 2 Mostr without same letter")
return MOMonomial(2, left) return MOMonomial(2, left)
@add.register(MOstr, MOstrPower) @add.register(MOstr, MOstrPower)
def mostr_mostrpower(left, right): def mostr_mostrpower(left, right):
@ -182,8 +190,9 @@ def mostr_mostrpower(left, right):
<MOpolynomial x^2 + x> <MOpolynomial x^2 + x>
""" """
if left != right.variable: if left != right.variable:
raise raise
return MOpolynomial(left , {1: 1, right.power: 1}) return MOpolynomial(left, {1: 1, right.power: 1})
@add.register(MOstrPower, MOstr) @add.register(MOstrPower, MOstr)
def mostrpower_mostr(left, right): def mostrpower_mostr(left, right):
@ -198,8 +207,9 @@ def mostrpower_mostr(left, right):
<MOpolynomial x^2 + x> <MOpolynomial x^2 + x>
""" """
if right != left.variable: if right != left.variable:
raise raise
return MOpolynomial(right , {1: 1, left.power: 1}) return MOpolynomial(right, {1: 1, left.power: 1})
@add.register(MOstrPower, MOstrPower) @add.register(MOstrPower, MOstrPower)
def mostrpower_mostrpower(left, right): def mostrpower_mostrpower(left, right):
@ -213,9 +223,12 @@ def mostrpower_mostrpower(left, right):
if left.variable != right.variable: if left.variable != right.variable:
raise NotImplementedError("Can't add 2 Mostrpower without same letter") raise NotImplementedError("Can't add 2 Mostrpower without same letter")
if left.power != right.power: 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) @add.register(MOstr, MOpolynomial)
def mostr_mopolynomial(left, right): def mostr_mopolynomial(left, right):
@ -234,6 +247,7 @@ def mostr_mopolynomial(left, right):
new_coefs[1] = 1 new_coefs[1] = 1
return MOpolynomial(right.variable, new_coefs) return MOpolynomial(right.variable, new_coefs)
@add.register(MOpolynomial, MOstr) @add.register(MOpolynomial, MOstr)
def mopolynomial_mostr(left, right): def mopolynomial_mostr(left, right):
""" add a str with a MOpolynomial to create a MOpolynomial """ 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} new_coefs = {**new_coefs, **left.coefficients}
return MOpolynomial(left.variable, new_coefs) return MOpolynomial(left.variable, new_coefs)
@add.register(MOstrPower, MOpolynomial) @add.register(MOstrPower, MOpolynomial)
def mostrpower_mopolynomial(left, right): def mostrpower_mopolynomial(left, right):
""" add a strPower with a MOpolynomial to create a MOpolynomial """ add a strPower with a MOpolynomial to create a MOpolynomial
@ -267,6 +282,7 @@ def mostrpower_mopolynomial(left, right):
new_coefs[left.power] = 1 new_coefs[left.power] = 1
return MOpolynomial(right.variable, new_coefs) return MOpolynomial(right.variable, new_coefs)
@add.register(MOpolynomial, MOstrPower) @add.register(MOpolynomial, MOstrPower)
def mopolynomial_mostrpower(left, right): def mopolynomial_mostrpower(left, right):
""" add a strPower with a MOpolynomial to create a MOpolynomial """ 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} new_coefs = {**new_coefs, **left.coefficients}
return MOpolynomial(left.variable, new_coefs) return MOpolynomial(left.variable, new_coefs)
@add.register(MOMonomial, MOpolynomial) @add.register(MOMonomial, MOpolynomial)
def momonomial_mopolynomial(left, right): def momonomial_mopolynomial(left, right):
""" add a Monomial with a MOpolynomial to create a MOpolynomial """ 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 new_coefs[left.power] = left.coefficient
return MOpolynomial(right.variable, new_coefs) return MOpolynomial(right.variable, new_coefs)
@add.register(MOpolynomial, MOMonomial) @add.register(MOpolynomial, MOMonomial)
def mopolynomial_momonomial(left, right): def mopolynomial_momonomial(left, right):
""" add a Monomial with a MOpolynomial to create a MOpolynomial """ 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} new_coefs = {**new_coefs, **left.coefficients}
return MOpolynomial(left.variable, new_coefs) return MOpolynomial(left.variable, new_coefs)
@add.register(MOpolynomial, MOpolynomial) @add.register(MOpolynomial, MOpolynomial)
def mopolynomial_mopolynomial(left, right): def mopolynomial_mopolynomial(left, right):
""" add a polynomial with a MOpolynomial to create a MOpolynomial """ add a polynomial with a MOpolynomial to create a MOpolynomial
@ -327,13 +346,14 @@ def mopolynomial_mopolynomial(left, right):
>>> add(b, a) >>> add(b, a)
<MOpolynomial 4x^3 + 2x + 3x^2 + 1> <MOpolynomial 4x^3 + 2x + 3x^2 + 1>
""" """
common_degree = set(left.monomials.keys()).intersection(right.monomials.keys()) common_degree = set(left.monomials.keys()).intersection(right.monomials.keys())
if common_degree: if common_degree:
raise NotImplementedError("Degree in common, need to compute") raise NotImplementedError("Degree in common, need to compute")
new_coefs = {**right.coefficients, **left.coefficients} new_coefs = {**right.coefficients, **left.coefficients}
return MOpolynomial(right.variable, new_coefs) return MOpolynomial(right.variable, new_coefs)
@add.register(MOstr, MOMonomial) @add.register(MOstr, MOMonomial)
def mostr_monomial(left, right): def mostr_monomial(left, right):
""" add a mostr with a MOMonomial to create a MOpolynomial """ add a mostr with a MOMonomial to create a MOpolynomial
@ -346,9 +366,8 @@ def mostr_monomial(left, right):
if right.power == 1: if right.power == 1:
raise NotImplementedError("Monomial is deg 1, need to compute") raise NotImplementedError("Monomial is deg 1, need to compute")
return MOpolynomial(right.variable, return MOpolynomial(right.variable, {right.power: right.coefficient, 1: 1})
{right.power: right.coefficient, 1: 1}
)
@add.register(MOMonomial, MOstr) @add.register(MOMonomial, MOstr)
def monomial_mostr(left, right): def monomial_mostr(left, right):
@ -362,9 +381,8 @@ def monomial_mostr(left, right):
if left.power == 1: if left.power == 1:
raise NotImplementedError("Monomial is deg 1, need to compute") raise NotImplementedError("Monomial is deg 1, need to compute")
return MOpolynomial(left.variable, return MOpolynomial(left.variable, {1: 1, left.power: left.coefficient})
{1: 1, left.power: left.coefficient}
)
@add.register(MOstrPower, MOMonomial) @add.register(MOstrPower, MOMonomial)
def mostrpower_monomial(left, right): def mostrpower_monomial(left, right):
@ -376,11 +394,12 @@ def mostrpower_monomial(left, right):
<MOpolynomial x^2 + 3x^4> <MOpolynomial x^2 + 3x^4>
""" """
if left.power == right.power: 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) @add.register(MOMonomial, MOstrPower)
def monomial_mostrpower(left, right): def monomial_mostrpower(left, right):
@ -392,11 +411,12 @@ def monomial_mostrpower(left, right):
<MOpolynomial 3x^4 + x^3> <MOpolynomial 3x^4 + x^3>
""" """
if left.power == right.power: 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) @add.register(MOMonomial, MOMonomial)
def monomial_momonomial(left, right): def monomial_momonomial(left, right):
@ -410,9 +430,9 @@ def monomial_momonomial(left, right):
if left.power == right.power: if left.power == right.power:
raise NotImplementedError("MOMonomials are same degree, need to compute") raise NotImplementedError("MOMonomials are same degree, need to compute")
return MOpolynomial(left.variable, return MOpolynomial(
{right.power: right.coefficient, left.power: left.coefficient} left.variable, {right.power: right.coefficient, left.power: left.coefficient}
) )
# ----------------------------- # -----------------------------

View File

@ -24,6 +24,7 @@ divide_doc = """ Typing trees a divide root
divide = Dispatcher("divide", doc=divide_doc) divide = Dispatcher("divide", doc=divide_doc)
@divide.register(MOnumber, MOnumber) @divide.register(MOnumber, MOnumber)
def monumber_monumber(left, right): def monumber_monumber(left, right):
""" A divide tree with 2 MOnumbers is a MOFraction """ A divide tree with 2 MOnumbers is a MOFraction

View File

@ -10,9 +10,11 @@
Exceptions for typing trees Exceptions for typing trees
""" """
class TypingError(Exception): class TypingError(Exception):
pass pass
# ----------------------------- # -----------------------------
# Reglages pour 'vim' # Reglages pour 'vim'
# vim:set autoindent expandtab tabstop=4 shiftwidth=4: # vim:set autoindent expandtab tabstop=4 shiftwidth=4:

View File

@ -26,6 +26,7 @@ multiply_doc = """ Multiply MOs
multiply = Dispatcher("multiply", doc=multiply_doc) multiply = Dispatcher("multiply", doc=multiply_doc)
@multiply.register((MOnumber, MOFraction), MOstr) @multiply.register((MOnumber, MOFraction), MOstr)
def moscalar_mostr(left, right): def moscalar_mostr(left, right):
""" Multiply a scalar with a letter to create a MOMonomial """ Multiply a scalar with a letter to create a MOMonomial
@ -40,6 +41,7 @@ def moscalar_mostr(left, right):
""" """
return MOMonomial(left, right) return MOMonomial(left, right)
@multiply.register(MOstr, (MOnumber, MOFraction)) @multiply.register(MOstr, (MOnumber, MOFraction))
def mostr_moscalar(left, right): def mostr_moscalar(left, right):
""" Multiply a scalar with a letter to create a MOMonomial """ Multiply a scalar with a letter to create a MOMonomial
@ -54,6 +56,7 @@ def mostr_moscalar(left, right):
""" """
return MOMonomial(right, left) return MOMonomial(right, left)
@multiply.register((MOnumber, MOFraction), MOstrPower) @multiply.register((MOnumber, MOFraction), MOstrPower)
def moscalar_mostrpower(left, right): def moscalar_mostrpower(left, right):
""" Multiply a scalar with a MOstrPower """ Multiply a scalar with a MOstrPower
@ -66,6 +69,7 @@ def moscalar_mostrpower(left, right):
""" """
return MOMonomial(left, right) return MOMonomial(left, right)
@multiply.register(MOstrPower, (MOnumber, MOFraction)) @multiply.register(MOstrPower, (MOnumber, MOFraction))
def mostrpower_moscalar(left, right): def mostrpower_moscalar(left, right):
""" Multiply a MOstrPower with a scalar """ Multiply a MOstrPower with a scalar
@ -78,6 +82,7 @@ def mostrpower_moscalar(left, right):
""" """
return MOMonomial(right, left) return MOMonomial(right, left)
# ----------------------------- # -----------------------------
# Reglages pour 'vim' # Reglages pour 'vim'
# vim:set autoindent expandtab tabstop=4 shiftwidth=4: # vim:set autoindent expandtab tabstop=4 shiftwidth=4:

View File

@ -25,6 +25,7 @@ power_doc = """ Typing Power of MOs
power = Dispatcher("power", doc=power_doc) power = Dispatcher("power", doc=power_doc)
@power.register(MOstr, MOnumber) @power.register(MOstr, MOnumber)
def mostr_monumber(left, right): def mostr_monumber(left, right):
""" Create MOstrPower over powered MOstr """ Create MOstrPower over powered MOstr
@ -38,7 +39,6 @@ def mostr_monumber(left, right):
return MOstrPower(left, right) return MOstrPower(left, right)
# ----------------------------- # -----------------------------
# Reglages pour 'vim' # Reglages pour 'vim'
# vim:set autoindent expandtab tabstop=4 shiftwidth=4: # vim:set autoindent expandtab tabstop=4 shiftwidth=4: