Mapytex/mapytex/calculus/core/MO/mo.py

278 lines
6.8 KiB
Python
Raw Normal View History

2018-03-08 14:01:47 +00:00
#! /usr/bin/env python
# -*- coding: utf-8 -*-
# vim:fenc=utf-8
#
# Copyright © 2017 lafrite <lafrite@Poivre>
#
# Distributed under terms of the MIT license.
2018-03-13 11:43:48 +00:00
from decimal import Decimal
2018-03-14 08:04:13 +00:00
from .exceptions import MOError
from ..coroutine import coroutine, STOOOP
2018-03-10 13:08:28 +00:00
from ..renders import tree2txt, tree2tex
2018-03-15 13:38:25 +00:00
from functools import total_ordering
__all__ = ["moify", "MO", "MOstr"]
2018-03-08 14:01:47 +00:00
@coroutine
def moify(target):
""" Coroutine which try to convert everything into an MO """
try:
target_ = target()
except TypeError:
target_ = target
try:
while True:
tok = yield
try:
target_.send(MOnumber(tok))
except MOError:
try:
target_.send(MOstr(tok))
except MOError:
target_.send(tok)
except STOOOP as err:
yield target_.throw(err)
2018-03-08 14:01:47 +00:00
class MO(object):
"""MO for math object
This base class is representing int and Decimal.
:attr value: sympy compatible version of the MO
:attr _tree: tree version of the MO
2018-11-23 09:05:36 +00:00
:attr _signature: Name to identify the MO in the API
2018-03-13 11:43:48 +00:00
2018-03-08 14:01:47 +00:00
"""
def __init__(self, value):
""" Initiate the MO
It should be idempotent.
2018-03-13 11:43:48 +00:00
2018-03-08 14:01:47 +00:00
>>> a = MO(3)
>>> a
<MO 3>
>>> a = MO(a)
>>> a
<MO 3>
"""
try:
self._tree = value._tree
2018-03-08 14:01:47 +00:00
except AttributeError:
self._tree = value
2018-03-08 14:01:47 +00:00
self.is_scalar = True
2018-11-23 09:05:36 +00:00
self._signature = None
2018-03-08 14:01:47 +00:00
@classmethod
def factory(cls, value):
""" Factory to ensure that a value is a MO before using it
Idempotent??
>>> MO.factory("x")
<MOstr x>
>>> MO.factory(2)
<MOnumber 2>
>>> MO.factory(2.3)
<MOnumber 2.29999999999999982236431605997495353221893310546875>
>>> MO.factory(Decimal("2.3"))
<MOnumber 2.3>
>>> x = MO.factory("x")
>>> MO.factory(x)
<MOstr x>
"""
if isinstance(value, str):
2018-03-08 14:01:47 +00:00
return MOstr(value)
elif isinstance(value, int) \
or isinstance(value, Decimal) \
or isinstance(value, float):
return MOnumber(value)
elif isinstance(value, MO):
return value
2018-03-08 14:01:47 +00:00
raise MOError("Can't convert it into a MO."
f"Need str, int, Decimal, float or MO, got {value}")
2018-03-08 14:01:47 +00:00
def __repr__(self):
return f"<{self.__class__.__name__} {self.__txt__}>"
def __str__(self):
return str(self._tree)
2018-03-08 14:01:47 +00:00
@property
def __txt__(self):
try:
return tree2txt(self._tree)
except AttributeError:
return str(self._tree)
2018-03-08 14:01:47 +00:00
2018-03-10 13:08:28 +00:00
@property
def __tex__(self):
try:
return tree2tex(self._tree)
2018-03-10 13:08:28 +00:00
except AttributeError:
return str(self._tree)
2018-03-10 13:08:28 +00:00
def __hash__(self):
return self._tree.__hash__()
def __eq__(self, other):
""" == a MOnumber """
try:
return self._tree == other._tree
except AttributeError:
return self._tree == other
2018-11-23 09:05:36 +00:00
@property
def signature(self):
""" Name of the mo in the API
:example:
>>> MOnumber(3).signature
'scalar'
>>> MOstr("x").signature
'monome1'
"""
return self._signature
2018-03-15 13:38:25 +00:00
@total_ordering
class MOnumber(MO):
""" Base number math object (int or Decimal) """
2018-03-13 11:43:48 +00:00
def __init__(self, value):
""" Initiate a number MO
>>> MOnumber(23)
<MOnumber 23>
>>> MOnumber(-23)
2018-03-10 05:03:55 +00:00
<MOnumber - 23>
>>> MOnumber(23.3)
<MOnumber 23.300000000000000710542735760100185871124267578125>
>>> MOnumber(Decimal("23.3"))
<MOnumber 23.3>
2018-03-10 05:03:55 +00:00
>>> MOnumber(Decimal("-23.3"))
<MOnumber - 23.3>
>>> a = MOnumber(23)
>>> MOnumber(a)
<MOnumber 23>
>>> MOnumber("a")
Traceback (most recent call last):
...
2018-03-14 08:04:13 +00:00
mapytex.calculus.core.MO.exceptions.MOError: The value of an MOnumber need to be a int, a float or a Decimal
"""
try:
val = value._tree
except AttributeError:
val = value
2018-03-13 11:43:48 +00:00
if isinstance(val, (int, Decimal)):
MO.__init__(self, val)
elif isinstance(val, float):
MO.__init__(self, Decimal(val))
else:
raise MOError("The value of an MOnumber need to be a int, a float or a Decimal")
self.value = self._tree
2018-11-23 09:05:36 +00:00
self._signature = "scalar"
2018-03-10 05:03:55 +00:00
@property
def __txt__(self):
2018-03-11 17:04:47 +00:00
if self.value >= 0:
2018-03-10 05:03:55 +00:00
return str(self.value)
return f"- {abs(self.value)}"
2018-03-10 13:08:28 +00:00
@property
def __tex__(self):
if self.value > 0:
return str(self.value)
return f"- {abs(self.value)}"
2018-03-13 11:43:48 +00:00
def __lt__(self, other):
""" < a MOnumber """
try:
return self.value < other.value
except AttributeError:
return self.value < other
2018-03-08 14:01:47 +00:00
class MOstr(MO):
""" Unknown math object like x or n"""
def __init__(self, value):
2018-03-08 14:01:47 +00:00
""" Initiate a string MO
>>> a = MOstr("x")
>>> a
<MOstr x>
>>> b = MOstr(a)
>>> b
<MOstr x>
>>> a = MOstr("+")
Traceback (most recent call last):
...
2018-03-14 08:04:13 +00:00
mapytex.calculus.core.MO.exceptions.MOError: An MOstr should be initiate with a alpha string, got +
2018-03-08 14:01:47 +00:00
>>> MOstr("ui")
Traceback (most recent call last):
...
2018-03-14 08:04:13 +00:00
mapytex.calculus.core.MO.exceptions.MOError: An MOstr should be initiate with a single caracter string, got ui
2018-03-08 14:01:47 +00:00
>>> MOstr(2)
Traceback (most recent call last):
...
2018-03-14 08:04:13 +00:00
mapytex.calculus.core.MO.exceptions.MOError: An MOstr should be initiate with a string - the unknown, got 2
2018-03-08 14:01:47 +00:00
"""
try:
val = value._tree
2018-03-08 14:01:47 +00:00
except AttributeError:
val = value
if not isinstance(val, str):
raise MOError(f"An MOstr should be initiate with a string - the unknown, got {val}")
2018-03-08 14:01:47 +00:00
if len(val) != 1:
raise MOError(f"An MOstr should be initiate with a single caracter string, got {val}")
if not val.isalpha():
raise MOError(f"An MOstr should be initiate with a alpha string, got {val}")
2018-03-08 14:01:47 +00:00
MO.__init__(self, val)
2018-03-08 14:01:47 +00:00
self.is_scalar = False
self._variable = val
2018-11-23 09:05:36 +00:00
self._signature = "monome1"
@property
def variable(self):
return self._variable
2018-03-13 11:43:48 +00:00
@property
def coefficients(self):
""" Dictionnary of coefficients
:example:
>>> p = MOstr("x")
>>> p.coefficients
{1: <MOnumber 1>}
"""
return {1: MOnumber(1)}
@property
def degree(self):
return 1
2018-03-08 14:01:47 +00:00
# -----------------------------
# Reglages pour 'vim'
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
# cursor: 16 del