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 .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:

View File

@ -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'

View File

@ -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:

View File

@ -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

View File

@ -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):

View File

@ -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:

View File

@ -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}")

View File

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

View File

@ -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'

View File

@ -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:

View File

@ -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:

View File

@ -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

View File

@ -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))

View File

@ -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

View File

@ -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):

View File

@ -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:

View File

@ -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

View File

@ -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:

View File

@ -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:

View File

@ -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)

View File

@ -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)
# -----------------------------

View File

@ -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
# -----------------------------

View File

@ -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

View File

@ -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 """

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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:

View File

@ -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

View File

@ -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}
)
# -----------------------------

View File

@ -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

View File

@ -10,9 +10,11 @@
Exceptions for typing trees
"""
class TypingError(Exception):
pass
# -----------------------------
# Reglages pour 'vim'
# 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.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:

View File

@ -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: