Feat(API): integrate Token to Expression simplify

This commit is contained in:
Bertrand Benjamin 2018-12-07 10:27:50 +01:00
parent 5938cc7875
commit 5bf23a4793
5 changed files with 165 additions and 15 deletions

View File

@ -11,6 +11,7 @@ Expression
""" """
from ..core import AssocialTree, Tree, compute, typing, TypingError from ..core import AssocialTree, Tree, compute, typing, TypingError
from .tokens import factory
from .renders import renders from .renders import renders
class Expression(object): class Expression(object):
@ -79,6 +80,7 @@ class Expression(object):
'tex' 'tex'
>>> print(e) >>> print(e)
2 + 3 \\times 4 2 + 3 \\times 4
>>> Expression.set_render('txt')
""" """
cls.RENDER = render cls.RENDER = render
@ -218,7 +220,7 @@ class Expression(object):
""" Set ancestor """ """ Set ancestor """
self._ancestor = ancestor self._ancestor = ancestor
def simplify(self, optimize=True): def _simplify(self, optimize=True):
""" Compute as much as possible the expression """ Compute as much as possible the expression
:param optimize: bool to optimize tree when it's possible :param optimize: bool to optimize tree when it's possible
@ -227,8 +229,8 @@ class Expression(object):
:example: :example:
>>> e = Expression.from_str("2+3*4") >>> e = Expression.from_str("2+3*4")
>>> e >>> e
<Exp: 2 + 3 \\times 4> <Exp: 2 + 3 * 4>
>>> f = e.simplify() >>> f = e._simplify()
>>> f >>> f
<Exp: 14> <Exp: 14>
>>> f._ancestor >>> f._ancestor
@ -249,7 +251,26 @@ class Expression(object):
return typed_exp return typed_exp
else: else:
comp_exp.set_ancestor(self) comp_exp.set_ancestor(self)
return comp_exp.simplify(optimize=optimize) return comp_exp._simplify(optimize=optimize)
def simplify(self, optimize=True):
""" Compute as much as possible the expression
:param optimize: bool to optimize tree when it's possible
:return: an expression
:example:
>>> e = Expression.from_str("2+3*4")
>>> e
<Exp: 2 + 3 * 4>
>>> f = e.simplify()
>>> f
<Integer 14>
>>> f._ancestor
<Exp: 2 + 12>
"""
self._child = self._simplify(optimize=optimize)
return factory(self._child, ancestor=self._child._ancestor)
def explain(self): def explain(self):
""" Yield every calculus step which have lead to self """ Yield every calculus step which have lead to self

View File

@ -0,0 +1,53 @@
#! /usr/bin/env python
# -*- coding: utf-8 -*-
# vim:fenc=utf-8
#
# Copyright © 2017 lafrite <lafrite@Poivre>
#
# Distributed under terms of the MIT license.
"""
Tokens represents MathObject at API level
"""
from ...core.MO.mo import MO, MOnumber, MOstr
from ...core.MO.fraction import MOFraction
from ...core.MO.monomial import MOstrPower, MOMonomial
from ...core.MO.polynomial import MOpolynomial
from decimal import Decimal as _Decimal
from .number import Integer, Decimal, Fraction
from .polynomial import Polynomial, Linear, Quadratic
__all__ = ["factory"]
def factory(exp, name="", ancestor=None):
""" Transform a Expression with on MathObject (from core) to a appropriate token (from API)
"""
mo = exp._tree
if not isinstance(mo, MO):
raise TypeError(f"Can't build Token from not computed Expression (got {mo})")
if isinstance(mo, MOnumber):
if isinstance(mo.value, int):
return Integer(mo, name, ancestor)
elif isinstance(mo.value, _Decimal):
return Decimal(mo, name, ancestor)
else:
raise TypeError(f"Can't build from MOnumber ({mo}) neither int nor decimal")
elif isinstance(mo, MOFraction):
if isinstance(mo._denominator, MOnumber) and \
isinstance(mo._numerator, MOnumber):
return Fraction(mo, name, ancestor)
else:
raise TypeError(f"Can't build from MOFraction ({mo}) numerator and denominator are not MOnumber")
elif isinstance(mo, (MOstr, MOstrPower, MOMonomial, MOpolynomial)):
raise TypeError(f"Can't build Polynom yet")
else:
raise TypeError(f"{type(mo)} is unknown MathObject")
# -----------------------------
# Reglages pour 'vim'
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
# cursor: 16 del

View File

@ -11,7 +11,8 @@ Tokens representing interger and decimal
""" """
from .token import Token from .token import Token
from ...core.MO import MOnumber, MOFraction from ...core.MO.mo import MOnumber
from ...core.MO.fraction import MOFraction
from decimal import Decimal as _Decimal from decimal import Decimal as _Decimal
__all__ = ["Integer", "Decimal"] __all__ = ["Integer", "Decimal"]
@ -20,13 +21,13 @@ class Integer(Token):
""" Token representing a integer """ """ Token representing a integer """
def __init__(self, mo, name=""): def __init__(self, mo, name="", ancestor=None):
if not isinstance(mo, MOnumber): if not isinstance(mo, MOnumber):
raise TypeError raise TypeError
if not isinstance(mo.value, int): if not isinstance(mo.value, int):
raise TypeError raise TypeError
Token.__init__(self, mo, name) Token.__init__(self, mo, name, ancestor)
self._mathtype = 'entier' self._mathtype = 'entier'
@classmethod @classmethod
@ -37,13 +38,13 @@ class Decimal(Token):
""" Token representing a decimal """ """ Token representing a decimal """
def __init__(self, mo, name=""): def __init__(self, mo, name="", ancestor=None):
if not isinstance(mo, MOnumber): if not isinstance(mo, MOnumber):
raise TypeError raise TypeError
if not isinstance(mo.value, _Decimal): if not isinstance(mo.value, _Decimal):
raise TypeError raise TypeError
Token.__init__(self, mo, name) Token.__init__(self, mo, name, ancestor)
self._mathtype = 'décimal' self._mathtype = 'décimal'
@classmethod @classmethod
@ -54,7 +55,7 @@ class Fraction(Token):
""" Token representing a fraction """ """ Token representing a fraction """
def __init__(self, mo, name=""): def __init__(self, mo, name="", ancestor=None):
if not isinstance(mo, MOFraction): if not isinstance(mo, MOFraction):
raise TypeError raise TypeError
if not isinstance(mo._numerator, MOnumber): if not isinstance(mo._numerator, MOnumber):
@ -62,7 +63,7 @@ class Fraction(Token):
if not isinstance(mo._denominator, MOnumber): if not isinstance(mo._denominator, MOnumber):
raise TypeError raise TypeError
Token.__init__(self, mo, name) Token.__init__(self, mo, name, ancestor)
self._mathtype = 'fraction' self._mathtype = 'fraction'
@classmethod @classmethod

View File

@ -7,7 +7,7 @@
# Distributed under terms of the MIT license. # Distributed under terms of the MIT license.
""" """
Tokens representing interger and decimal Tokens representing polynomials functions
""" """
from .token import Token from .token import Token
@ -18,13 +18,13 @@ class Polynomial(Token):
""" Token representing a polynomial """ """ Token representing a polynomial """
def __init__(self, mo, name=""): def __init__(self, mo, name="", ancestor=None):
if not isinstance(mo, MOpolynomial): if not isinstance(mo, MOpolynomial):
raise TypeError raise TypeError
if not isinstance(mo.value, int): if not isinstance(mo.value, int):
raise TypeError raise TypeError
Token.__init__(self, mo, name) Token.__init__(self, mo, name, ancestor)
self._mathtype = 'polynome' self._mathtype = 'polynome'
@classmethod @classmethod
@ -43,6 +43,40 @@ class Polynomial(Token):
""" Call a Polynomial to evaluate itself on value """ """ Call a Polynomial to evaluate itself on value """
pass pass
class Linear(Token):
""" Token representing a linear """
def __init__(self, mo, name="", ancestor=None):
if not isinstance(mo, MOpolynomial):
raise TypeError
if not isinstance(mo.value, int):
raise TypeError
Token.__init__(self, mo, name, ancestor)
self._mathtype = 'affine'
@classmethod
def random(cls):
raise NotImplemented
class Quadratic(Token):
""" Token representing a quadratic """
def __init__(self, mo, name="", ancestor=None):
if not isinstance(mo, MOpolynomial):
raise TypeError
if not isinstance(mo.value, int):
raise TypeError
Token.__init__(self, mo, name, ancestor)
self._mathtype = 'polynome du 2nd degré'
@classmethod
def random(cls):
raise NotImplemented
# ----------------------------- # -----------------------------
# Reglages pour 'vim' # Reglages pour 'vim'

View File

@ -10,20 +10,61 @@
Tokens: practical envelop of math object Tokens: practical envelop of math object
""" """
from ..renders import renders
class Token(object): class Token(object):
""" Token: practical envelop of an math object """ """ Token: practical envelop of an math object """
def __init__(self, mo, name=""): RENDER = 'txt'
def __init__(self, mo, name="", ancestor = None):
self._mo = mo self._mo = mo
self.name = name self.name = name
self._mathtype = None self._mathtype = None
self._ancestor = ancestor
@classmethod @classmethod
def random(cls): def random(cls):
raise NotImplemented raise NotImplemented
def explain(self):
""" Yield every calculus step which have lead to self
:example:
>>> from mapytex.calculus.API import Expression
>>> e = Expression.from_str("2+3*4")
>>> f = e.simplify()
>>> f
<Integer 14>
>>> for s in f.explain():
... print(s)
2 + 3 * 4
2 + 12
14
"""
try:
yield from self._ancestor.explain()
yield self
except AttributeError:
yield self
def __repr__(self):
return f"<{self.__class__.__name__} {self.__txt__}>"
def __str__(self):
return renders[self.RENDER](self._mo)
@property
def __txt__(self):
return self._mo.__txt__
@property
def __tex__(self):
return self._mo.__tex__
# ----------------------------- # -----------------------------