Integrate MO inside str2 and in Tree (doctest are ok)
This commit is contained in:
parent
1ab74eb133
commit
a8a62864a6
18
mapytex/calculus/core/MO/__init__.py
Normal file
18
mapytex/calculus/core/MO/__init__.py
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#! /usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# vim:fenc=utf-8
|
||||||
|
#
|
||||||
|
# Copyright © 2017 lafrite <lafrite@Poivre>
|
||||||
|
#
|
||||||
|
# Distributed under terms of the MIT license.
|
||||||
|
|
||||||
|
"""
|
||||||
|
MO: math objects
|
||||||
|
"""
|
||||||
|
|
||||||
|
from .mo import *
|
||||||
|
|
||||||
|
# -----------------------------
|
||||||
|
# Reglages pour 'vim'
|
||||||
|
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
|
||||||
|
# cursor: 16 del
|
82
mapytex/calculus/core/MO/fraction.py
Normal file
82
mapytex/calculus/core/MO/fraction.py
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
#! /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
|
||||||
|
from .mo import MO, MOError
|
||||||
|
|
||||||
|
__all__ = ["MOFraction"]
|
||||||
|
|
||||||
|
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
|
@ -6,11 +6,37 @@
|
|||||||
#
|
#
|
||||||
# Distributed under terms of the MIT license.
|
# Distributed under terms of the MIT license.
|
||||||
|
|
||||||
from mapytex.calculus.core.tree import Tree
|
from mapytex.calculus.core.coroutine import coroutine, STOOOP
|
||||||
|
from decimal import Decimal
|
||||||
|
|
||||||
|
__all__ = ["moify", "MO", "MOstr"]
|
||||||
|
|
||||||
class MOError(Exception):
|
class MOError(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@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)
|
||||||
|
|
||||||
|
|
||||||
class MO(object):
|
class MO(object):
|
||||||
|
|
||||||
"""MO for math object
|
"""MO for math object
|
||||||
@ -117,6 +143,43 @@ class MO(object):
|
|||||||
<MO -1.2>
|
<MO -1.2>
|
||||||
"""
|
"""
|
||||||
return MO.factory(-self.value)
|
return MO.factory(-self.value)
|
||||||
|
|
||||||
|
class MOnumber(MO):
|
||||||
|
|
||||||
|
""" Base number math object (int or Decimal) """
|
||||||
|
|
||||||
|
def __init__(self, value, negative=False):
|
||||||
|
""" Initiate a number MO
|
||||||
|
|
||||||
|
>>> MOnumber(23)
|
||||||
|
<MOnumber 23>
|
||||||
|
>>> MOnumber(-23)
|
||||||
|
<MOnumber -23>
|
||||||
|
>>> MOnumber(23.3)
|
||||||
|
<MOnumber 23.300000000000000710542735760100185871124267578125>
|
||||||
|
>>> MOnumber(Decimal("23.3"))
|
||||||
|
<MOnumber 23.3>
|
||||||
|
>>> a = MOnumber(23)
|
||||||
|
>>> MOnumber(a)
|
||||||
|
<MOnumber 23>
|
||||||
|
>>> MOnumber("a")
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
mapytex.calculus.core.MO.mo.MOError: The value of an MOnumber need to be a int, a float or a Decimal
|
||||||
|
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
val = value.value
|
||||||
|
except AttributeError:
|
||||||
|
val = value
|
||||||
|
|
||||||
|
if isinstance(val, int) or isinstance(val, Decimal):
|
||||||
|
MO.__init__(self, value)
|
||||||
|
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")
|
||||||
|
|
||||||
|
|
||||||
class MOstr(MO):
|
class MOstr(MO):
|
||||||
|
|
||||||
@ -135,14 +198,18 @@ class MOstr(MO):
|
|||||||
>>> b
|
>>> b
|
||||||
<MOstr x>
|
<MOstr x>
|
||||||
|
|
||||||
|
>>> a = MOstr("+")
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
mapytex.calculus.core.MO.mo.MOError: An MOstr should be initiate with a alpha string, got +
|
||||||
>>> MOstr("ui")
|
>>> MOstr("ui")
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
mo.MOError: An MOstr should be initiate with a single caracter string
|
mapytex.calculus.core.MO.mo.MOError: An MOstr should be initiate with a single caracter string, got ui
|
||||||
>>> MOstr(2)
|
>>> MOstr(2)
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
mo.MOError: An MOstr should be initiate with a string - the unknown
|
mapytex.calculus.core.MO.mo.MOError: An MOstr should be initiate with a string - the unknown, got 2
|
||||||
|
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
@ -151,9 +218,11 @@ class MOstr(MO):
|
|||||||
val = value
|
val = value
|
||||||
|
|
||||||
if not isinstance(val, str):
|
if not isinstance(val, str):
|
||||||
raise MOError("An MOstr should be initiate with a string - the unknown")
|
raise MOError(f"An MOstr should be initiate with a string - the unknown, got {val}")
|
||||||
if len(val) != 1:
|
if len(val) != 1:
|
||||||
raise MOError("An MOstr should be initiate with a single caracter string")
|
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}")
|
||||||
|
|
||||||
MO.__init__(self, value)
|
MO.__init__(self, value)
|
||||||
self.negative = negative
|
self.negative = negative
|
||||||
@ -192,71 +261,6 @@ class MOstr(MO):
|
|||||||
def __neg__(self):
|
def __neg__(self):
|
||||||
return MO(self.value, not self.negative)
|
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'
|
# Reglages pour 'vim'
|
||||||
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
|
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
|
||||||
|
@ -14,6 +14,7 @@ from functools import partial
|
|||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
from .coroutine import *
|
from .coroutine import *
|
||||||
from .operator import is_operator
|
from .operator import is_operator
|
||||||
|
from .MO import moify
|
||||||
|
|
||||||
__all__ = ["str2", ]
|
__all__ = ["str2", ]
|
||||||
|
|
||||||
@ -563,7 +564,7 @@ def list_sink():
|
|||||||
except STOOOP:
|
except STOOOP:
|
||||||
yield ans
|
yield ans
|
||||||
|
|
||||||
def str2(sink):
|
def str2(sink, convert_to_MO=True):
|
||||||
""" Return a pipeline which parse an expression with the sink as an endpont
|
""" Return a pipeline which parse an expression with the sink as an endpont
|
||||||
|
|
||||||
:example:
|
:example:
|
||||||
@ -572,6 +573,11 @@ def str2(sink):
|
|||||||
>>> exp = "12+3*4"
|
>>> exp = "12+3*4"
|
||||||
>>> t = str2nestedlist(exp)
|
>>> t = str2nestedlist(exp)
|
||||||
>>> print(t)
|
>>> print(t)
|
||||||
|
[<MOnumber 12>, '+', <MOnumber 3>, '*', <MOnumber 4>]
|
||||||
|
>>> str2nestedlist = str2(list_sink, False)
|
||||||
|
>>> exp = "12+3*4"
|
||||||
|
>>> t = str2nestedlist(exp)
|
||||||
|
>>> print(t)
|
||||||
[12, '+', 3, '*', 4]
|
[12, '+', 3, '*', 4]
|
||||||
>>> exp = "12*3+4"
|
>>> exp = "12*3+4"
|
||||||
>>> t = str2nestedlist(exp)
|
>>> t = str2nestedlist(exp)
|
||||||
@ -680,10 +686,12 @@ def str2(sink):
|
|||||||
"""
|
"""
|
||||||
lfop = lookfor(is_operator)
|
lfop = lookfor(is_operator)
|
||||||
operator_corout = partial(concurent_broadcast, lookfors = [lfop])
|
operator_corout = partial(concurent_broadcast, lookfors = [lfop])
|
||||||
|
|
||||||
def pipeline(expression):
|
def pipeline(expression):
|
||||||
str2_corout = lookforNumbers(operator_corout(missing_times(pparser(sink))))
|
if convert_to_MO:
|
||||||
#str2_corout = lookforNumbers(operator_corout(pparser(sink)))
|
str2_corout = lookforNumbers(operator_corout(missing_times(moify(pparser(sink)))))
|
||||||
|
else:
|
||||||
|
str2_corout = lookforNumbers(operator_corout(missing_times(pparser(sink))))
|
||||||
|
|
||||||
for i in expression:
|
for i in expression:
|
||||||
str2_corout.send(i)
|
str2_corout.send(i)
|
||||||
a = str2_corout.throw(STOOOP)
|
a = str2_corout.throw(STOOOP)
|
||||||
|
@ -57,7 +57,7 @@ class Tree(object):
|
|||||||
self.right_value = right_value
|
self.right_value = right_value
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_str(cls, expression):
|
def from_str(cls, expression, convert_to_MO=True):
|
||||||
""" Initiate a tree from an string expression
|
""" Initiate a tree from an string expression
|
||||||
|
|
||||||
:example:
|
:example:
|
||||||
@ -85,7 +85,7 @@ class Tree(object):
|
|||||||
| > n
|
| > n
|
||||||
|
|
||||||
"""
|
"""
|
||||||
t = MutableTree.from_str(expression)
|
t = MutableTree.from_str(expression, convert_to_MO)
|
||||||
return cls.from_any_tree(t)
|
return cls.from_any_tree(t)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@ -270,7 +270,7 @@ class Tree(object):
|
|||||||
|
|
||||||
:example:
|
:example:
|
||||||
|
|
||||||
>>> t = Tree.from_str("3*4+2")
|
>>> t = Tree.from_str("3*4+2", convert_to_MO=False)
|
||||||
>>> print(t)
|
>>> print(t)
|
||||||
+
|
+
|
||||||
> *
|
> *
|
||||||
@ -399,9 +399,9 @@ class Tree(object):
|
|||||||
|
|
||||||
>>> t = Tree.from_str("3+4+5*2")
|
>>> t = Tree.from_str("3+4+5*2")
|
||||||
>>> [l for l in t.get_leafs()]
|
>>> [l for l in t.get_leafs()]
|
||||||
[3, 4, 5, 2]
|
[<MOnumber 3>, <MOnumber 4>, <MOnumber 5>, <MOnumber 2>]
|
||||||
>>> {type(l) for l in t.get_leafs()}
|
>>> {type(l) for l in t.get_leafs()}
|
||||||
{<class 'int'>}
|
{<class 'mapytex.calculus.core.MO.mo.MOnumber'>}
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
yield from self.left_value.get_leafs(callback)
|
yield from self.left_value.get_leafs(callback)
|
||||||
@ -584,7 +584,7 @@ class MutableTree(Tree):
|
|||||||
self.right_value = right_value
|
self.right_value = right_value
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_str(cls, expression):
|
def from_str(cls, expression, convert_to_MO=True):
|
||||||
""" Initiate the MutableTree
|
""" Initiate the MutableTree
|
||||||
|
|
||||||
:example:
|
:example:
|
||||||
@ -610,7 +610,7 @@ class MutableTree(Tree):
|
|||||||
| > -2
|
| > -2
|
||||||
| > 3
|
| > 3
|
||||||
"""
|
"""
|
||||||
str2mutTree = str2(cls.sink)
|
str2mutTree = str2(cls.sink, convert_to_MO)
|
||||||
return str2mutTree(expression)
|
return str2mutTree(expression)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@ -871,7 +871,7 @@ class AssocialTree(Tree):
|
|||||||
|
|
||||||
:example:
|
:example:
|
||||||
|
|
||||||
>>> t = Tree.from_str("3*4+2")
|
>>> t = Tree.from_str("3*4+2", convert_to_MO=False)
|
||||||
>>> print(t)
|
>>> print(t)
|
||||||
+
|
+
|
||||||
> *
|
> *
|
||||||
@ -921,7 +921,7 @@ class AssocialTree(Tree):
|
|||||||
... return (op, (l, r))
|
... return (op, (l, r))
|
||||||
>>> t = AssocialTree.from_str("3+4+5*2")
|
>>> t = AssocialTree.from_str("3+4+5*2")
|
||||||
>>> t.apply(to_nested)
|
>>> t.apply(to_nested)
|
||||||
('+', (('+', (3, 4)), 'tree(*)'))
|
('+', (('+', (<MOnumber 3>, <MOnumber 4>)), 'tree(*)'))
|
||||||
|
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
@ -954,7 +954,7 @@ class AssocialTree(Tree):
|
|||||||
>>> [l for l in t.get_leafs(str)]
|
>>> [l for l in t.get_leafs(str)]
|
||||||
['3', '4', '*\\n > 5\\n > 2']
|
['3', '4', '*\\n > 5\\n > 2']
|
||||||
>>> [ l for l in t.get_leafs(type) ]
|
>>> [ l for l in t.get_leafs(type) ]
|
||||||
[<class 'int'>, <class 'int'>, <class 'mapytex.calculus.core.tree.AssocialTree'>]
|
[<class 'mapytex.calculus.core.MO.mo.MOnumber'>, <class 'mapytex.calculus.core.MO.mo.MOnumber'>, <class 'mapytex.calculus.core.tree.AssocialTree'>]
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
if self.left_value.node == self.node:
|
if self.left_value.node == self.node:
|
||||||
|
Loading…
Reference in New Issue
Block a user