From 1ab74eb13302f81d97e69e49590ec006f28de96d Mon Sep 17 00:00:00 2001 From: Bertrand Benjamin Date: Thu, 8 Mar 2018 17:01:47 +0300 Subject: [PATCH] Start writing MOs --- mapytex/calculus/core/MO/mo.py | 263 +++++++++++++++++++++++++++++++++ 1 file changed, 263 insertions(+) create mode 100644 mapytex/calculus/core/MO/mo.py diff --git a/mapytex/calculus/core/MO/mo.py b/mapytex/calculus/core/MO/mo.py new file mode 100644 index 0000000..90a001c --- /dev/null +++ b/mapytex/calculus/core/MO/mo.py @@ -0,0 +1,263 @@ +#! /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