#! /usr/bin/env python # -*- coding: utf-8 -*- # vim:fenc=utf-8 # # Copyright © 2017 lafrite # # 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 ..MO.polynomial import MOpolynomial 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) >>> multiply(b, a) >>> a = MOnumber(0) >>> b = MOFraction(1, 2) >>> multiply(a, b) """ 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) """ 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), 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) >>> a = MOstr('x') >>> b = MOstrPower('y', 4) >>> multiply(a, b) Traceback (most recent call last): ... 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) @multiply.register(MOstrPower, MOstr) @special_case(multiply_filter) def mostr_mostrpower(left, right): """ Multiply a MOstr and a MOstrPower >>> a = MOstrPower('x', 4) >>> b = MOstr('x') >>> multiply(a, b) >>> a = MOstrPower('y', 4) >>> b = MOstr('x') >>> multiply(a, b) Traceback (most recent call last): ... 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) @multiply.register(MOstr, MOstr) @special_case(multiply_filter) def mostr_mostr(left, right): """ Multiply a MOstr and a MOstr :example: >>> a = MOstr('x') >>> b = MOstr('x') >>> multiply(a, b) >>> a = MOstr('y') >>> b = MOstr('x') >>> multiply(a, b) Traceback (most recent call last): ... 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})") return MOstrPower(left.variable, 2) @multiply.register(MOstrPower, MOstrPower) @special_case(multiply_filter) def mostr_mostrpower(left, right): """ Multiply a MOstrPower and a MOstrPower >>> a = MOstrPower('x', 2) >>> b = MOstrPower('x', 4) >>> print(multiply(a, b)) ^ > x > + | > 2 | > 4 >>> a = MOstrPower('x', 2) >>> b = MOstrPower('y', 4) >>> multiply(a, b) Traceback (most recent call last): ... 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})") power = Tree("+", left.power, right.power) return Tree("^", left.variable, power) @multiply.register(MOstrPower, MOMonomial) @special_case(multiply_filter) def mostr_momonomial(left, right): """ Multiply a MOstrPower and a MOMonomial >>> a = MOstrPower('x', 2) >>> b = MOMonomial(2, 'x', 4) >>> print(multiply(a, b)) * > 2 > ^ | > x | > + | | > 2 | | > 4 >>> a = MOstrPower('x', 2) >>> b = MOMonomial(2, 'y', 4) >>> multiply(a, b) Traceback (most recent call last): ... 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})") 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): """ Multiply a MOMonomial and a MOstrPower >>> a = MOMonomial(2, 'x', 4) >>> b = MOstrPower('x', 2) >>> print(multiply(a, b)) * > 2 > ^ | > x | > + | | > 4 | | > 2 >>> a = MOMonomial(2, 'y', 4) >>> b = MOstrPower('x', 2) >>> multiply(a, b) Traceback (most recent call last): ... NotImplementedError: Can't multiply MOstrPower and Monomial if they don'thave same variable (got y and x) """ 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})") 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): """ Multiply a MOstr and a MOMonomial >>> a = MOstr('x') >>> b = MOMonomial(2, 'x', 4) >>> print(multiply(a, b)) * > 2 > ^ | > x | > 5 >>> a = MOstr('x') >>> b = MOMonomial(2, 'y', 4) >>> multiply(a, b) Traceback (most recent call last): ... 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) @multiply.register(MOMonomial, MOstr) @special_case(multiply_filter) def momonomial_mostr(left, right): """ Multiply a MOMonomial and a MOstr >>> a = MOMonomial(2, 'x', 4) >>> b = MOstr('x') >>> print(multiply(a, b)) * > 2 > ^ | > x | > 5 >>> a = MOMonomial(2, 'y', 4) >>> b = MOstr('x') >>> multiply(a, b) Traceback (most recent call last): ... NotImplementedError: Can't multiply MOstr and Monomial if they don'thave same variable (got y and x) """ 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) @multiply.register(MOMonomial, MOMonomial) @special_case(multiply_filter) def momonomial_momonomial(left, right): """ Multiply a MOMonomial and a MOMonomial >>> a = MOMonomial(2, 'x', 4) >>> b = MOMonomial(3, 'x', 2) >>> print(multiply(a, b)) * > * | > 2 | > 3 > ^ | > x | > + | | > 4 | | > 2 >>> a = MOMonomial(2, 'y', 4) >>> b = MOMonomial(3, 'x', 2) >>> multiply(a, b) Traceback (most recent call last): ... NotImplementedError: Can't multiply MOMonomial and Monomial if they don'thave same variable (got y and x) """ 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})") 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) @special_case(multiply_filter) def moscalar_mopolynomial(left, right): """ Multiply a scalar and a MOMonomial >>> a = MOnumber(2) >>> b = MOpolynomial('x', [1, 2, 3]) >>> print(multiply(a, b)) + > * | > 2 | > 1 > + | > * | | > 2 | | > * | | | > 2 | | | > x | > * | | > 2 | | > * | | | > 3 | | | > ^ | | | | > x | | | | > 2 >>> a = MOFraction(1, 5) >>> b = MOpolynomial('x', [1, 2, 3]) >>> print(multiply(a, b)) + > * | > / | | > 1 | | > 5 | > 1 > + | > * | | > / | | | > 1 | | | > 5 | | > * | | | > 2 | | | > x | > * | | > / | | | > 1 | | | > 5 | | > * | | | > 3 | | | > ^ | | | | > x | | | | > 2 >>> a = MOstr("x") >>> b = MOpolynomial('x', [1, 2, 3]) >>> print(multiply(a, b)) + > * | > x | > 1 > + | > * | | > x | | > * | | | > 2 | | | > x | > * | | > x | | > * | | | > 3 | | | > ^ | | | | > x | | | | > 2 >>> a = MOstrPower("x", 2) >>> b = MOpolynomial('x', [1, 2, 3]) >>> print(multiply(a, b)) + > * | > ^ | | > x | | > 2 | > 1 > + | > * | | > ^ | | | > x | | | > 2 | | > * | | | > 2 | | | > x | > * | | > ^ | | | > x | | | > 2 | | > * | | | > 3 | | | > ^ | | | | > x | | | | > 2 >>> a = MOMonomial(3, "x", 2) >>> b = MOpolynomial('x', [1, 2, 3]) >>> print(multiply(a, b)) + > * | > * | | > 3 | | > ^ | | | > x | | | > 2 | > 1 > + | > * | | > * | | | > 3 | | | > ^ | | | | > x | | | | > 2 | | > * | | | > 2 | | | > x | > * | | > * | | | > 3 | | | > ^ | | | | > x | | | | > 2 | | > * | | | > 3 | | | > ^ | | | | > x | | | | > 2 """ coefs = [Tree("*", left, monom) for monom in right.monomials.values()] return Tree.from_list("+", coefs) # ----------------------------- # Reglages pour 'vim' # vim:set autoindent expandtab tabstop=4 shiftwidth=4: # cursor: 16 del