#! /usr/bin/env python # -*- coding: utf-8 -*- # vim:fenc=utf-8 # # Copyright © 2017 lafrite # # Distributed under terms of the MIT license. from mapytex.calculus.core.tree import Tree class MOError(Exception): pass class MO(object): """MO for math object This base class is representing int and Decimal. It stocks its value in self.value and it """ def __init__(self, value): """ Initiate the MO It should be idempotent. >>> a = MO(3) >>> a >>> a = MO(a) >>> a """ try: self.value = value.value except AttributeError: self.value = value self.is_scalar = True @classmethod def factory(cls, value): """ Factory to ensure that a value is a MO before using it """ if isinstance(value, MO): return value elif isinstance(value, str): return MOstr(value) return MO(value) def __repr__(self): return f"<{self.__class__.__name__} {self.__txt__}>" def __str__(self): return self.__txt__ @property def __txt__(self): return str(self.value) def __add__(self, other): """ Overload + for MOs >>> from decimal import Decimal >>> a = MO(4) >>> b = MO(Decimal("1.2")) >>> a + b >>> b + a """ return MO.factory(self.value + other.value) def __mul__(self, other): """ Overload * for MOs >>> from decimal import Decimal >>> a = MO(4) >>> b = MO(Decimal("1.2")) >>> a * b >>> b * a """ return MO.factory(self.value * other.value) def __truediv__(self, other): """ Overload / for MOs >>> from decimal import Decimal >>> a = MO(4) >>> b = MO(Decimal("1.4")) >>> c = b / a >>> c >>> type(c.value) >>> c = a / b >>> c >>> type(c.value) """ return MO.factory(self.value / other.value) def __neg__(self): """ Overload + for MOs >>> from decimal import Decimal >>> a = MO(4) >>> - a >>> b = MO(Decimal("1.2")) >>> - b """ return MO.factory(-self.value) class MOstr(MO): """ Unknown math object like x or n""" def __init__(self, value, negative=False): """ Initiate a string MO >>> a = MOstr("x") >>> a >>> a = MOstr("x", negative=True) >>> a >>> b = MOstr(a) >>> b >>> MOstr("ui") Traceback (most recent call last): ... mo.MOError: An MOstr should be initiate with a single caracter string >>> MOstr(2) Traceback (most recent call last): ... mo.MOError: An MOstr should be initiate with a string - the unknown """ try: val = value.value except AttributeError: val = value if not isinstance(val, str): raise MOError("An MOstr should be initiate with a string - the unknown") if len(val) != 1: raise MOError("An MOstr should be initiate with a single caracter string") MO.__init__(self, value) self.negative = negative self.is_scalar = False @property def __txt__(self): return "-"*self.negative + str(self.value) def __add__(self, other): raise NotImplemented def __radd__(self, other): raise NotImplemented def __mul__(self, other): if other.is_scalar: raise NotImplemented raise NotImplemented def __rmul__(self, other): if other.is_scalar: raise NotImplemented raise NotImplemented def __truediv__(self, other): if other.is_scalar: raise NotImplemented raise NotImplemented def __rtruediv__(self, other): if other.is_scalar: raise NotImplemented raise NotImplemented def __neg__(self): return MO(self.value, not self.negative) class MOFraction(MO): """ Fraction math object""" def __init__(self, numerator, denominator, negative=False): """ Initiate the MOFraction It can't be indempotent. :param numerator: Numerator of the Fraction :param denominator: Denominator of the Fraction :param negative: Is the fraction negative (not concidering sign of numerator or denominator. >>> f = MOFraction(2, 3) >>> f >>> f = MOFraction(2, 3, negative = True) >>> f """ value = Tree("/", MO.factory(numerator), MO.factory(denominator), ) MO.__init__(self, value) self._numerator = numerator self._denominator = denominator self.negative = negative @property def __txt__(self): # TODO: fonctionnement temporaire. Il faudrait utilser un moteur de rendu plus fin. |jeu. mars 8 15:26:49 EAT 2018 try: numerator = self._numerator.__txt__ except AttributeError: numerator = str(self._numerator) try: denominator = self._denominator.__txt__ except AttributeError: denominator = str(self._denominator) return "- "*self.negative + f"{numerator} / {denominator}" def __add__(self, other): """ Overload * for MOFraction :param other: any other MO :yields: calculus steps and the final yielded value is a MO. >>> f = MOFraction(1, 2) >>> g = MOFraction(3, 2) """ raise NotImplemented def __mul__(self, other): raise NotImplemented def __truediv__(self, other): raise NotImplemented # ----------------------------- # Reglages pour 'vim' # vim:set autoindent expandtab tabstop=4 shiftwidth=4: # cursor: 16 del