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