Mapytex/mapytex/calculus/core/compute/multiply.py

279 lines
6.3 KiB
Python

#! /usr/bin/env python
# -*- coding: utf-8 -*-
# vim:fenc=utf-8
#
# Copyright © 2017 lafrite <lafrite@Poivre>
#
# Distributed under terms of the MIT license.
"""
Multiply MO
"""
from multipledispatch import Dispatcher
from ..tree import Tree
from ..MO.mo import MO, MOnumber, MOstr
from ..MO.fraction import MOFraction
from ..MO.monomial import MOstrPower, MOMonomial
from .exceptions import MultiplyError
from .filters import special_case
multiply_doc = """ Multiply MOs
:param left: left MO
:param right: right MO
:returns: Tree or MO
"""
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
>>> a = MOnumber(4)
>>> b = MOnumber(6)
>>> multiply(a, b)
<MOnumber 24>
"""
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
>>> a = MOnumber(4)
>>> b = MOFraction(6, 5)
>>> print(multiply(a, b))
/
> *
| > 4
| > 6
> 5
>>> b = MOFraction(6, 5, True)
>>> print(multiply(a, b))
/
> *
| > 4
| > -
| | > None
| | > 6
> 5
"""
num = Tree("*", left, right.numerator)
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
>>> a = MOFraction(6, 5)
>>> b = MOnumber(4)
>>> print(multiply(a, b))
/
> *
| > 6
| > 4
> 5
"""
num = Tree("*", left.numerator, 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)
>>> a = MOFraction(1, 5)
>>> b = MOFraction(4, 5)
>>> print(multiply(a, b))
/
> *
| > 1
| > 4
> *
| > 5
| > 5
"""
num = Tree("*", left.numerator, right.numerator)
denom = Tree("*", left.denominator, right.denominator)
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
>>> a = MOnumber(2)
>>> b = MOstr('x')
>>> multiply(a, b)
<MOMonomial 2x>
>>> a = MOFraction(1, 5)
>>> multiply(a, b)
<MOMonomial 1 / 5x>
"""
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
>>> a = MOstr('x')
>>> b = MOnumber(2)
>>> multiply(a, b)
<MOMonomial 2x>
>>> b = MOFraction(1, 5)
>>> multiply(a, b)
<MOMonomial 1 / 5x>
"""
return MOMonomial(right, left)
@multiply.register((MOnumber, MOFraction), MOstrPower)
@special_case(multiply_filter)
def moscalar_mostrpower(left, right):
""" Multiply a scalar with a MOstrPower
>>> a = MOnumber(4)
>>> x = MOstrPower('x', 4)
>>> print(multiply(a, x))
*
> 4
> ^
| > x
| > 4
"""
return MOMonomial(left, right)
@multiply.register(MOstrPower, (MOnumber, MOFraction))
@special_case(multiply_filter)
def mostrpower_moscalar(left, right):
""" Multiply a MOstrPower with a scalar
>>> a = MOnumber(4)
>>> x = MOstrPower('x', 4)
>>> print(multiply(x, a))
*
> 4
> ^
| > x
| > 4
"""
return MOMonomial(right, left)
@multiply.register((MOnumber, MOFraction), MOMonomial)
@special_case(multiply_filter)
def moscalar_monomonial(left, right):
""" Multiply a scalar with a monomial
>>> a = MOnumber(4)
>>> x = MOstrPower('x', 4)
>>> b = MOMonomial(5, x)
>>> print(multiply(a, b))
*
> *
| > 4
| > 5
> ^
| > x
| > 4
"""
coefficient = Tree('*', left, right.coefficient)
return Tree('*', coefficient, right.strpower)
@multiply.register(MOMonomial, (MOnumber, MOFraction))
@special_case(multiply_filter)
def monomonial_moscalar(left, right):
""" Multiply a momonial with a scalar
>>> x = MOstrPower('x', 4)
>>> a = MOMonomial(5, x)
>>> b = MOnumber(4)
>>> print(multiply(a, b))
*
> *
| > 4
| > 5
> ^
| > x
| > 4
"""
coefficient = Tree('*', right, left.coefficient)
return Tree('*', coefficient, left.strpower)
@multiply.register(MOstr, MOstrPower)
@special_case(multiply_filter)
def mostr_mostrpower(left, right):
""" Multiply a MOstr and a MOstrPower
>>> a = MOstr('x')
>>> b = MOstrPower('x', 4)
>>> multiply(a, b)
<MOstrPower x^5>
>>> a = MOstr('x')
>>> b = MOstrPower('y', 4)
>>> multiply(a, b)
Traceback (most recent call last):
...
mapytex.calculus.core.compute.exceptions.MultiplyError: Can't multiply MOstr and MOstrPower if they don'thave same variable (got x and y)
"""
if left.variable != right.variable:
raise MultiplyError("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+1)
# -----------------------------
# Reglages pour 'vim'
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
# cursor: 16 del