Integrate MO inside str2 and in Tree (doctest are ok)

This commit is contained in:
Bertrand Benjamin 2018-03-09 19:31:46 +03:00
parent 1ab74eb133
commit a8a62864a6
5 changed files with 196 additions and 84 deletions

View 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

View 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

View File

@ -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
@ -118,6 +144,43 @@ class MO(object):
""" """
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):
""" Unknown math object like x or n""" """ Unknown math object like x or n"""
@ -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:

View File

@ -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)

View File

@ -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: