264 lines
6.3 KiB
Python
264 lines
6.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.
|
|
|
|
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
|
|
<MO 3>
|
|
>>> a = MO(a)
|
|
>>> a
|
|
<MO 3>
|
|
|
|
"""
|
|
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
|
|
<MO 5.2>
|
|
>>> b + a
|
|
<MO 5.2>
|
|
"""
|
|
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
|
|
<MO 4.8>
|
|
>>> b * a
|
|
<MO 4.8>
|
|
"""
|
|
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
|
|
<MO 0.35>
|
|
>>> type(c.value)
|
|
<class 'decimal.Decimal'>
|
|
>>> c = a / b
|
|
>>> c
|
|
<MO 2.857142857142857142857142857>
|
|
>>> type(c.value)
|
|
<class 'decimal.Decimal'>
|
|
"""
|
|
return MO.factory(self.value / other.value)
|
|
|
|
def __neg__(self):
|
|
""" Overload + for MOs
|
|
|
|
>>> from decimal import Decimal
|
|
>>> a = MO(4)
|
|
>>> - a
|
|
<MO -4>
|
|
>>> b = MO(Decimal("1.2"))
|
|
>>> - b
|
|
<MO -1.2>
|
|
"""
|
|
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
|
|
<MOstr x>
|
|
>>> a = MOstr("x", negative=True)
|
|
>>> a
|
|
<MOstr -x>
|
|
>>> b = MOstr(a)
|
|
>>> b
|
|
<MOstr x>
|
|
|
|
>>> 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
|
|
<MOFraction 2 / 3>
|
|
>>> f = MOFraction(2, 3, negative = True)
|
|
>>> f
|
|
<MOFraction - 2 / 3>
|
|
"""
|
|
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
|