Decorator for computing special cases

This commit is contained in:
Bertrand Benjamin 2018-03-17 11:55:32 +03:00
parent f4422c6d1a
commit 3f3e52cdf8
4 changed files with 134 additions and 34 deletions

View File

@ -10,13 +10,14 @@
Adding MO
"""
from functools import wraps
from multipledispatch import Dispatcher
from ..tree import Tree
from ..MO.mo import MO, MOnumber
from ..MO.fraction import MOFraction
from .exceptions import AddError
from .arithmetic import lcm
from .type_filter import args_are
from .filters import special_case
add_doc = """ Adding MOs
@ -25,9 +26,36 @@ add_doc = """ Adding MOs
:return: Tree or MO
"""
add = Dispatcher("add", doc=add_doc)
def add_filter(left, right):
""" Automatic add on MO
:param left: MO
:param right: MO
:returns: MO if it is a special case, nothing other wise
>>> a = MOnumber(0)
>>> b = MOFraction(1, 2)
>>> add(a, b)
<MOFraction 1 / 2>
>>> add(b, a)
<MOFraction 1 / 2>
"""
try:
if left == 0:
return right
except TypeError:
pass
try:
if right == 0:
return left
except TypeError:
pass
@add.register(MOnumber, MOnumber)
@special_case(add_filter)
def monumber_monumber(left, right):
""" Simply add MO value
@ -40,6 +68,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):
""" Return a tree with the MOnumber transformed into a MOFraction
@ -58,6 +87,7 @@ def monumber_mofraction(left, right):
return Tree("+", left_fraction, right)
@add.register(MOFraction, MOnumber)
@special_case(add_filter)
def mofraction_monumber(left, right):
""" Return a tree with the MOnumber transformed into a MOFraction
@ -76,6 +106,7 @@ def mofraction_monumber(left, right):
return Tree("+", left, right_fraction)
@add.register(MOFraction, MOFraction)
@special_case(add_filter)
def mofraction_mofraction(left, right):
""" 3 differents cases:

View File

@ -15,7 +15,7 @@ from ..tree import Tree
from ..MO.mo import MO, MOnumber
from ..MO.fraction import MOFraction
from .exceptions import DivideError
from .type_filter import args_are
from .filters import special_case
divide_doc = """ Dividing MOs
@ -27,7 +27,42 @@ divide_doc = """ Dividing MOs
divide = Dispatcher("divide", doc=divide_doc)
def divide_filter(left, right):
""" Automatic divide on MO
>>> a = MOnumber(4)
>>> b = MOnumber(1)
>>> divide(a, b)
<MOnumber 4>
>>> a = MOnumber(0)
>>> b = MOnumber(1)
>>> divide(a, b)
<MOnumber 0>
>>> a = MOnumber(4)
>>> b = MOnumber(0)
>>> divide(a, b)
Traceback (most recent call last):
...
mapytex.calculus.core.compute.exceptions.DivideError: Division by zero
"""
try:
if left == 0:
return left
except TypeError:
pass
try:
if right == 1:
return left
except TypeError:
pass
try:
if right == 0:
raise DivideError("Division by zero")
except TypeError:
pass
@divide.register(MOnumber, MOnumber)
@special_case(divide_filter)
def monumber_monumber(left, right):
""" Divide 2 monumbers and return a MOFraction
@ -39,6 +74,7 @@ def monumber_monumber(left, right):
return MOFraction(left, right)
@divide.register(MOnumber, MOFraction)
@special_case(divide_filter)
def monumber_mofraction(left, right):
""" Divide a monumber and a mofraction by inverting MOFraction
@ -63,6 +99,7 @@ def monumber_mofraction(left, right):
return Tree("*", left, right.inverse())
@divide.register(MOFraction, MOnumber)
@special_case(divide_filter)
def mofraction_monumber(left, right):
""" Divide a monumber and a mofraction by inverting MOnumber
@ -82,6 +119,7 @@ def mofraction_monumber(left, right):
return Tree("*", left, right_fraction)
@divide.register(MOFraction, MOFraction)
@special_case(divide_filter)
def mofraction_mofraction(left, right):
""" Divide two mofractions by inverting right MOFraction
@ -99,37 +137,6 @@ def mofraction_mofraction(left, right):
"""
return Tree("*", left, right.inverse())
#def divide(left, right):
# """ Perform the addition of left and right
#
# :param left: left MO
# :param right: right MO
# :returns: Tree or MO
#
# >>> a = MOnumber(4)
# >>> b = MOnumber(6)
# >>> divide(a, b)
# <MOFraction 4 / 6>
# >>> b = MOnumber(0)
# >>> divide(a, b)
# Traceback (most recent call last):
# ...
# mapytex.calculus.core.compute.exceptions.DivideError: Division by zero
#
# """
# try:
# right.value
# except AttributeError:
# pass
# else:
# if right.value == 0:
# raise DivideError("Division by zero")
#
# if right.value == 1:
# return left
#
# return MULFUNCTIONS[(type(left), type(right))](left, right)
# -----------------------------
# Reglages pour 'vim'
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:

View File

@ -36,7 +36,22 @@ def args_are(left_type, right_type):
return filtered_func
return type_filter
def special_case(filter):
""" Decorate operation to filter special cases before call the function
:param filter: (MO, MO) -> MO or Tree
:returns: decorator
"""
def decorator(func):
@wraps(func)
def _func(left, right):
ans = filter(left, right)
if ans is None:
return func(left, right)
return ans
return _func
return decorator
# -----------------------------
# Reglages pour 'vim'

View File

@ -16,7 +16,7 @@ from ..MO.mo import MO, MOnumber, MOstr
from ..MO.fraction import MOFraction
from ..MO.monomial import MOMonomial
from .exceptions import MultiplyError
from .type_filter import args_are
from .filters import special_case
multiply_doc = """ Multiply MOs
@ -28,7 +28,48 @@ multiply_doc = """ Multiply MOs
multiply = Dispatcher("multiply", doc=multiply_doc)
def multiply_filter(left, right):
""" Automatic multiply on MO
:param left: MO
:param right: MO
:returns: MO if it is a special case, nothing other wise
>>> a = MOnumber(1)
>>> b = MOFraction(1, 2)
>>> multiply(a, b)
<MOFraction 1 / 2>
>>> multiply(b, a)
<MOFraction 1 / 2>
>>> a = MOnumber(0)
>>> b = MOFraction(1, 2)
>>> multiply(a, b)
<MOnumber 0>
"""
try:
if left == 0:
return left
except TypeError:
pass
try:
if right == 0:
return right
except TypeError:
pass
try:
if left == 1:
return right
except TypeError:
pass
try:
if right == 1:
return left
except TypeError:
pass
@multiply.register(MOnumber, MOnumber)
@special_case(multiply_filter)
def monumber_monumber(left, right):
""" Simply multiply values
@ -41,6 +82,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):
""" Return division Tree with on the numertor MOnumber times numerator of MOFraction
@ -67,6 +109,7 @@ def monumber_mofraction(left, right):
return Tree("/", num, right._denominator)
@multiply.register(MOFraction, MOnumber)
@special_case(multiply_filter)
def mofraction_monumber(left, right):
""" Return division Tree with on the numertor MOnumber times numerator of MOFraction
@ -83,6 +126,7 @@ def mofraction_monumber(left, right):
return Tree("/", num, left._denominator)
@multiply.register(MOFraction, MOFraction)
@special_case(multiply_filter)
def mofraction_mofraction(left, right):
""" Multiply two mofractions (numertors together and denominators together)
@ -102,6 +146,7 @@ def mofraction_mofraction(left, right):
return Tree("/", num, denom)
@multiply.register((MOnumber, MOFraction), MOstr)
@special_case(multiply_filter)
def moscalar_mostr(left, right):
""" Multiply a scalar with a letter to create a MOMonomial
@ -116,6 +161,7 @@ def moscalar_mostr(left, right):
return MOMonomial(left, right)
@multiply.register(MOstr, (MOnumber, MOFraction))
@special_case(multiply_filter)
def mostr_moscalar(left, right):
""" Multiply a scalar with a letter to create a MOMonomial
@ -130,6 +176,7 @@ def mostr_moscalar(left, right):
return MOMonomial(right, left)
@multiply.register((MOnumber, MOFraction), MOMonomial)
@special_case(multiply_filter)
def moscalar_monomonial(left, right):
""" Multiply a scalar with a monomial