243 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			243 lines
		
	
	
		
			5.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.
 | |
| 
 | |
| """
 | |
| 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)
 | |
|     <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
 | |
| 
 | |
|     >>> a = MOnumber(4)
 | |
|     >>> b = MOnumber(6)
 | |
|     >>> add(a, b)
 | |
|     <MOnumber 10>
 | |
| 
 | |
|     """
 | |
|     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)
 | |
|     <MOMonomial 2x>
 | |
|     """
 | |
|     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)
 | |
|     <MOMonomial 2x^2>
 | |
|     """
 | |
|     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
 |