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 Adding MO
""" """
from functools import wraps
from multipledispatch import Dispatcher from multipledispatch import Dispatcher
from ..tree import Tree from ..tree import Tree
from ..MO.mo import MO, MOnumber from ..MO.mo import MO, MOnumber
from ..MO.fraction import MOFraction from ..MO.fraction import MOFraction
from .exceptions import AddError from .exceptions import AddError
from .arithmetic import lcm from .arithmetic import lcm
from .type_filter import args_are from .filters import special_case
add_doc = """ Adding MOs add_doc = """ Adding MOs
@ -25,9 +26,36 @@ add_doc = """ Adding MOs
:return: Tree or MO :return: Tree or MO
""" """
add = Dispatcher("add", doc=add_doc) 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) @add.register(MOnumber, MOnumber)
@special_case(add_filter)
def monumber_monumber(left, right): def monumber_monumber(left, right):
""" Simply add MO value """ Simply add MO value
@ -40,6 +68,7 @@ def monumber_monumber(left, right):
return MO.factory(left.value + right.value) return MO.factory(left.value + right.value)
@add.register(MOnumber, MOFraction) @add.register(MOnumber, MOFraction)
@special_case(add_filter)
def monumber_mofraction(left, right): def monumber_mofraction(left, right):
""" Return a tree with the MOnumber transformed into a MOFraction """ Return a tree with the MOnumber transformed into a MOFraction
@ -58,6 +87,7 @@ def monumber_mofraction(left, right):
return Tree("+", left_fraction, right) return Tree("+", left_fraction, right)
@add.register(MOFraction, MOnumber) @add.register(MOFraction, MOnumber)
@special_case(add_filter)
def mofraction_monumber(left, right): def mofraction_monumber(left, right):
""" Return a tree with the MOnumber transformed into a MOFraction """ Return a tree with the MOnumber transformed into a MOFraction
@ -76,6 +106,7 @@ def mofraction_monumber(left, right):
return Tree("+", left, right_fraction) return Tree("+", left, right_fraction)
@add.register(MOFraction, MOFraction) @add.register(MOFraction, MOFraction)
@special_case(add_filter)
def mofraction_mofraction(left, right): def mofraction_mofraction(left, right):
""" 3 differents cases: """ 3 differents cases:

View File

@ -15,7 +15,7 @@ from ..tree import Tree
from ..MO.mo import MO, MOnumber from ..MO.mo import MO, MOnumber
from ..MO.fraction import MOFraction from ..MO.fraction import MOFraction
from .exceptions import DivideError from .exceptions import DivideError
from .type_filter import args_are from .filters import special_case
divide_doc = """ Dividing MOs divide_doc = """ Dividing MOs
@ -27,7 +27,42 @@ divide_doc = """ Dividing MOs
divide = Dispatcher("divide", doc=divide_doc) 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) @divide.register(MOnumber, MOnumber)
@special_case(divide_filter)
def monumber_monumber(left, right): def monumber_monumber(left, right):
""" Divide 2 monumbers and return a MOFraction """ Divide 2 monumbers and return a MOFraction
@ -39,6 +74,7 @@ def monumber_monumber(left, right):
return MOFraction(left, right) return MOFraction(left, right)
@divide.register(MOnumber, MOFraction) @divide.register(MOnumber, MOFraction)
@special_case(divide_filter)
def monumber_mofraction(left, right): def monumber_mofraction(left, right):
""" Divide a monumber and a mofraction by inverting MOFraction """ Divide a monumber and a mofraction by inverting MOFraction
@ -63,6 +99,7 @@ def monumber_mofraction(left, right):
return Tree("*", left, right.inverse()) return Tree("*", left, right.inverse())
@divide.register(MOFraction, MOnumber) @divide.register(MOFraction, MOnumber)
@special_case(divide_filter)
def mofraction_monumber(left, right): def mofraction_monumber(left, right):
""" Divide a monumber and a mofraction by inverting MOnumber """ Divide a monumber and a mofraction by inverting MOnumber
@ -82,6 +119,7 @@ def mofraction_monumber(left, right):
return Tree("*", left, right_fraction) return Tree("*", left, right_fraction)
@divide.register(MOFraction, MOFraction) @divide.register(MOFraction, MOFraction)
@special_case(divide_filter)
def mofraction_mofraction(left, right): def mofraction_mofraction(left, right):
""" Divide two mofractions by inverting right MOFraction """ Divide two mofractions by inverting right MOFraction
@ -99,37 +137,6 @@ def mofraction_mofraction(left, right):
""" """
return Tree("*", left, right.inverse()) 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' # Reglages pour 'vim'
# vim:set autoindent expandtab tabstop=4 shiftwidth=4: # 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 filtered_func
return type_filter 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' # Reglages pour 'vim'

View File

@ -16,7 +16,7 @@ from ..MO.mo import MO, MOnumber, MOstr
from ..MO.fraction import MOFraction from ..MO.fraction import MOFraction
from ..MO.monomial import MOMonomial from ..MO.monomial import MOMonomial
from .exceptions import MultiplyError from .exceptions import MultiplyError
from .type_filter import args_are from .filters import special_case
multiply_doc = """ Multiply MOs multiply_doc = """ Multiply MOs
@ -28,7 +28,48 @@ multiply_doc = """ Multiply MOs
multiply = Dispatcher("multiply", doc=multiply_doc) 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) @multiply.register(MOnumber, MOnumber)
@special_case(multiply_filter)
def monumber_monumber(left, right): def monumber_monumber(left, right):
""" Simply multiply values """ Simply multiply values
@ -41,6 +82,7 @@ def monumber_monumber(left, right):
return MO.factory(left.value * right.value) return MO.factory(left.value * right.value)
@multiply.register(MOnumber, MOFraction) @multiply.register(MOnumber, MOFraction)
@special_case(multiply_filter)
def monumber_mofraction(left, right): def monumber_mofraction(left, right):
""" Return division Tree with on the numertor MOnumber times numerator of MOFraction """ 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) return Tree("/", num, right._denominator)
@multiply.register(MOFraction, MOnumber) @multiply.register(MOFraction, MOnumber)
@special_case(multiply_filter)
def mofraction_monumber(left, right): def mofraction_monumber(left, right):
""" Return division Tree with on the numertor MOnumber times numerator of MOFraction """ 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) return Tree("/", num, left._denominator)
@multiply.register(MOFraction, MOFraction) @multiply.register(MOFraction, MOFraction)
@special_case(multiply_filter)
def mofraction_mofraction(left, right): def mofraction_mofraction(left, right):
""" Multiply two mofractions (numertors together and denominators together) """ Multiply two mofractions (numertors together and denominators together)
@ -102,6 +146,7 @@ def mofraction_mofraction(left, right):
return Tree("/", num, denom) return Tree("/", num, denom)
@multiply.register((MOnumber, MOFraction), MOstr) @multiply.register((MOnumber, MOFraction), MOstr)
@special_case(multiply_filter)
def moscalar_mostr(left, right): def moscalar_mostr(left, right):
""" Multiply a scalar with a letter to create a MOMonomial """ Multiply a scalar with a letter to create a MOMonomial
@ -116,6 +161,7 @@ def moscalar_mostr(left, right):
return MOMonomial(left, right) return MOMonomial(left, right)
@multiply.register(MOstr, (MOnumber, MOFraction)) @multiply.register(MOstr, (MOnumber, MOFraction))
@special_case(multiply_filter)
def mostr_moscalar(left, right): def mostr_moscalar(left, right):
""" Multiply a scalar with a letter to create a MOMonomial """ Multiply a scalar with a letter to create a MOMonomial
@ -130,6 +176,7 @@ def mostr_moscalar(left, right):
return MOMonomial(right, left) return MOMonomial(right, left)
@multiply.register((MOnumber, MOFraction), MOMonomial) @multiply.register((MOnumber, MOFraction), MOMonomial)
@special_case(multiply_filter)
def moscalar_monomonial(left, right): def moscalar_monomonial(left, right):
""" Multiply a scalar with a monomial """ Multiply a scalar with a monomial