#! /usr/bin/env python # -*- coding: utf-8 -*- # vim:fenc=utf-8 # # Copyright © 2017 lafrite # # Distributed under terms of the MIT license. """ Adding MO """ from functools import wraps 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 AddError from .arithmetic import lcm from .filters import special_case add_doc = """ Adding MOs :param left: left MO :param right: right MO :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) >>> add(b, a) """ 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 >>> a = MOnumber(4) >>> b = MOnumber(6) >>> add(a, b) """ 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 >>> a = MOnumber(4) >>> b = MOFraction(6, 5) >>> print(add(a, b)) + > / | > 4 | > 1 > / | > 6 | > 5 """ left_fraction = MOFraction(left, MOnumber(1)) 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 >>> a = MOFraction(6, 5) >>> b = MOnumber(4) >>> print(add(a, b)) + > / | > 6 | > 5 > / | > 4 | > 1 """ right_fraction = MOFraction(right, MOnumber(1)) return Tree("+", left, right_fraction) @add.register(MOFraction, MOFraction) @special_case(add_filter) def mofraction_mofraction(left, right): """ 3 differents cases: Fractions have same denomintor -> add numerator Tree >>> a = MOFraction(1, 5) >>> b = MOFraction(4, 5) >>> print(add(a, b)) / > + | > 1 | > 4 > 5 >>> a = MOFraction(1, 5, True) >>> b = MOFraction(4, 5) >>> print(mofraction_mofraction(a, b)) / > + | > - | | > None | | > 1 | > 4 > 5 >>> a = MOFraction(1, 5) >>> b = MOFraction(4, 5, True) >>> print(mofraction_mofraction(a, b)) / > + | > 1 | > - | | > None | | > 4 > 5 A denominator is a multiple of the other >>> a = MOFraction(1, 2) >>> b = MOFraction(1, 4) >>> print(mofraction_mofraction(a, b)) + > / | > * | | > 1 | | > 2 | > * | | > 2 | | > 2 > / | > 1 | > 4 Denominators are coprime >>> a = MOFraction(1, 2) >>> b = MOFraction(1, 5) >>> print(mofraction_mofraction(a, b)) + > / | > * | | > 1 | | > 5 | > * | | > 2 | | > 5 > / | > * | | > 1 | | > 2 | > * | | > 5 | | > 2 """ if left.denominator == right.denominator: num = Tree("+", left.numerator, right.numerator) return Tree("/", num, left.denominator) denom_lcm = lcm(left.denominator.value, right.denominator.value) if left.denominator.value == denom_lcm: left_frac = left else: multiply_by = MO.factory(denom_lcm // left.denominator.value) left_num = Tree("*", left.numerator, multiply_by) left_denom = Tree("*", left.denominator, multiply_by) left_frac = Tree("/", left_num, left_denom) if right.denominator.value == denom_lcm: right_frac = right else: multiply_by = MO.factory(denom_lcm // right.denominator.value) right_num = Tree("*", right.numerator, multiply_by) right_denom = Tree("*", right.denominator, multiply_by) right_frac = Tree("/", right_num, right_denom) return Tree("+", left_frac, right_frac) @add.register(MOstr, MOstr) @special_case(add_filter) def mostr_mostr(left, right): """ Add 2 MOstr :example: >>> a = MOstr("x") >>> b = MOstr("x") >>> add(a, b) """ if 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): """ Add 2 MOstrPower :example: >>> a = MOstrPower("x", 2) >>> b = MOstrPower("x", 2) >>> add(a, b) """ if left.variable != right.variable: raise NotImplementedError("Can't add 2 MOstrPower with not same letter") if left.power != right.power: raise NotImplementedError("Can't add 2 MOstrPower with not same power") return MOMonomial(2, left.variable, left.power) # ----------------------------- # Reglages pour 'vim' # vim:set autoindent expandtab tabstop=4 shiftwidth=4: # cursor: 16 del