Compare commits

...

5 Commits

Author SHA1 Message Date
cbcead48f7 Feat: Init polynomial with coefficients
All checks were successful
continuous-integration/drone/push Build is passing
2021-02-04 10:18:12 +01:00
ff4d8471ef Feat: dirty way to manage () and * in render 2020-12-15 16:01:54 +01:00
460255b151 Fix: Rendering and changing it works 2020-12-15 15:37:27 +01:00
95fd12c430 Feat: test num and denom for fraction 2020-12-15 15:02:39 +01:00
a1608a20d1 Feat: add test on what doesn't work! 2020-12-15 14:36:39 +01:00
10 changed files with 121 additions and 127 deletions

View File

@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
# encoding: utf-8 # encoding: utf-8
from .calculus import Expression, Integer, Decimal, random_list from .calculus import Expression, Integer, Decimal, random_list, render, Polynomial
# Expression.set_render('tex') # Expression.set_render('tex')

View File

@ -108,66 +108,35 @@ x^7
(6 + 6) * x + 4x^2 + 9 (6 + 6) * x + 4x^2 + 9
4x^2 + 12x + 9 4x^2 + 12x + 9
>>> e = Expression.from_str("(2x+3)(-x+1)") >>> e = Expression.from_str("(2x-3)(-x+2)")
>>> e_simplified = e.simplify() >>> e_simplified = e.simplify()
>>> e_simplified >>> e_simplified
<Quadratic - 2x^2 - x + 3> <Quadratic - 2x^2 + 7x - 6>
>>> for s in e_simplified.explain(): >>> for s in e_simplified.explain():
... print(s) ... print(s)
(2x - 3)(- x + 2)
(2x - 3)(- x + 2)
2x(- x) + 2x * 2 - 3(- x) - 3 * 2
2(- 1) * x^(1 + 1) + 2 * 2 * x - 3(- 1) * x - 6
4x + 3x - 2x^2 - 6
(4 + 3) * x - 2x^2 - 6
- 2x^2 + 7x - 6
""" """
from .expression import Expression from .expression import Expression
from .tokens import Token from .tokens import Token
from .tokens.number import Integer, Decimal from .tokens.polynomial import Polynomial
from .tokens.number import Integer, Decimal, Fraction
from .renders import render
def set_render(render):
"""
:example:
>>> e = Expression.from_str("2+3*4")
>>> print(e)
2 + 3 * 4
>>> e = Expression.from_str("2+3/4")
>>> print(e)
2 + 3 / 4
>>> es = e.simplify()
>>> print(es)
11 / 4
>>> set_render('tex')
>>> Expression.RENDER
'tex'
>>> Token.RENDER
'tex'
>>> e = Expression.from_str("2+3*4")
>>> print(e)
2 + 3 \\times 4
>>> e = Expression.from_str("2+3/4")
>>> print(e)
2 + \\dfrac{3}{4}
>>> es = e.simplify()
>>> print(es)
\\dfrac{11}{4}
>>> set_render('txt')
"""
Expression.set_render(render)
Token.set_render(render)
if __name__ == "__main__": if __name__ == "__main__":
e = Expression.from_str("1+2/3/4/5") e = Expression.from_str("(2x-3)(-x+2)")
et = e._typing() e_simplified = e.simplify()
print("typing") e_simplified
print(e._tree) for s in e_simplified.explain():
e = et._order() print(s._tree.map_on_leaf(lambda x: type(x)))
print("order") print(s)
print(e._tree)
e = e._optimize()
print("then optimize")
print(e._tree)
e = et._optimize()
print("optimize without order")
print(e._tree)
# ----------------------------- # -----------------------------
# Reglages pour 'vim' # Reglages pour 'vim'

View File

@ -21,7 +21,7 @@ from ..core.random import (
) )
from ..core.MO import moify from ..core.MO import moify
from .tokens import factory from .tokens import factory
from .renders import renders from .renders import render
class Expression(object): class Expression(object):
@ -42,7 +42,6 @@ class Expression(object):
14 14
""" """
RENDER = "txt"
def __init__(self, tree, ancestor=None): def __init__(self, tree, ancestor=None):
""" """
@ -50,15 +49,6 @@ class Expression(object):
self._tree = tree self._tree = tree
self._ancestor = ancestor self._ancestor = ancestor
@classmethod
def set_render(cls, render):
""" Define default render function
:param render: render name (txt or tex)
"""
cls.RENDER = render
@classmethod @classmethod
def from_str(cls, string, typing=True): def from_str(cls, string, typing=True):
""" Initiate the expression from a string """ Initiate the expression from a string
@ -148,10 +138,10 @@ class Expression(object):
return cls(t) return cls(t)
def __str__(self): def __str__(self):
return renders[self.RENDER](self._tree) return render(self._tree)
def __repr__(self): def __repr__(self):
return f"<Exp: {renders['txt'](self._tree)}>" return f"<Exp: {render(self._tree, 'txt')}>"
def _order(self, exclude_nodes=["*", "/", "**"]): def _order(self, exclude_nodes=["*", "/", "**"]):
""" Order the expression base on types """ Order the expression base on types

View File

@ -12,34 +12,55 @@ Expression
""" """
from ..core import tree2txt, tree2tex from ..core import tree2txt, tree2tex
class Render(object):
""" Object which render Expression or token """
def _txt(mo_tree): def __init__(self, default="txt"):
""" txt render for MOs or Trees""" self._default = default
self._render = default
self.renders = {}
def register_render(self, name, func, attribute):
""" register a render """
try: try:
return tree2txt(mo_tree) self.renders[name]
except KeyError:
self.renders[name] = {"name": name, "func": func, "attribute": attribute}
else:
raise ValueError("This render name already exists")
@property
def render(self):
return self.renders[self._render]
def __call__(self, mo_tree, tmp_render=''):
if tmp_render:
r = self.renders[tmp_render]
else:
r = self.render
try:
return r["func"](mo_tree)
except ValueError: except ValueError:
pass pass
try: try:
return mo_tree.__txt__ return getattr(mo_tree, r["attribute"])
except AttributeError: except AttributeError:
return str(mo_tree) return str(mo_tree)
def set_render(self, render):
def _tex(mo_tree): """ Define the render """
""" Tex render for MOs or Trees""" if render in self.renders.keys():
try: self._render = render
return tree2tex(mo_tree) else:
except ValueError: raise ValueError("This render does not exists")
pass
try:
return mo_tree.__tex__
except AttributeError:
return str(mo_tree)
renders = {"txt": _txt, "tex": _tex}
render = Render()
render.register_render("txt", tree2txt, "__txt__")
render.register_render("tex", tree2tex, "__tex__")
# ----------------------------- # -----------------------------
# Reglages pour 'vim' # Reglages pour 'vim'

View File

@ -18,7 +18,7 @@ from ...core.MO import MO, MOnumber
from ...core.MO.fraction import MOFraction from ...core.MO.fraction import MOFraction
from random import random from random import random
__all__ = ["Integer", "Decimal"] __all__ = ["Integer", "Decimal", "Fraction"]
class Integer(Token): class Integer(Token):
@ -237,11 +237,25 @@ class Fraction(Token):
@property @property
def numerator(self): def numerator(self):
return self._mo.numerator """ Get numerator of the fraction
:example:
>>> a = Fraction("3/4")
>>> a.numerator
<Integer 3>
"""
return Integer(self._mo.numerator)
@property @property
def denominator(self): def denominator(self):
return self._mo.denominator """ Get denominator of the fraction
:example:
>>> a = Fraction("3/4")
>>> a.denominator
<Integer 4>
"""
return Integer(self._mo.denominator)
@property @property
def decimal(self): def decimal(self):

View File

@ -15,6 +15,7 @@ from .token import Token
from . import to_be_token from . import to_be_token
from ...core.MO import MO from ...core.MO import MO
from ...core.MO.atoms import moify from ...core.MO.atoms import moify
from ...core.MO.polynomial import MOpolynomial
__all__ = ["Polynomial", "Quadratic", "Linear"] __all__ = ["Polynomial", "Quadratic", "Linear"]
@ -44,9 +45,21 @@ class Polynomial(Token):
return cls(mo, name, ancestor) return cls(mo, name, ancestor)
@classmethod @classmethod
def from_coefficients(cls, coefficients): def from_coefficients(cls, coefficients, variable_name="x", name=""):
""" Initiate polynomial from list of coefficients """ """ Initiate polynomial from list of coefficients
pass
:examples:
>>> P = Polynomial.from_coefficients([1, 2, 3])
>>> P
<Polynomial 3x^2 + 2x + 1>
>>> P = Polynomial.from_coefficients([1, 2, -3])
>>> P
<Polynomial - 3x^2 + 2x + 1>
>>> P = Polynomial.from_coefficients([1, 2, 3], "y")
>>> P
<Polynomial 3y^2 + 2y + 1>
"""
return cls(MOpolynomial(variable_name, coefficients), name)
@classmethod @classmethod
def random(cls): def random(cls):

View File

@ -10,7 +10,7 @@
Tokens: practical envelop of math object Tokens: practical envelop of math object
""" """
from ..renders import renders from ..renders import render
from ...core.MO.atoms import moify from ...core.MO.atoms import moify
@ -18,8 +18,6 @@ class Token(object):
""" Token: practical envelop of an math object """ """ Token: practical envelop of an math object """
RENDER = "txt"
def __init__(self, mo, name="", ancestor=None): def __init__(self, mo, name="", ancestor=None):
self._mo = mo self._mo = mo
self.name = name self.name = name
@ -34,14 +32,6 @@ class Token(object):
): ):
raise NotImplemented raise NotImplemented
@classmethod
def set_render(cls, render):
""" Define default render function
:param render: render name (txt or tex)
"""
cls.RENDER = render
def explain(self): def explain(self):
""" Yield every calculus step which have lead to self """ Yield every calculus step which have lead to self
@ -64,10 +54,10 @@ class Token(object):
yield self yield self
def __repr__(self): def __repr__(self):
return f"<{self.__class__.__name__} {renders['txt'](self._mo)}>" return f"<{self.__class__.__name__} {render(self._mo, 'txt')}>"
def __str__(self): def __str__(self):
return renders[self.RENDER](self._mo) return render(self._mo)
@property @property
def raw(self): def raw(self):

View File

@ -13,7 +13,7 @@ Make calculus as a student
Expression is the classe wich handle all calculus. It can randomly generate or import calculus, simplify them and explain them as a student would do. Expression is the classe wich handle all calculus. It can randomly generate or import calculus, simplify them and explain them as a student would do.
>>> from mapytex.calculus import Expression >>> from mapytex.calculus import Expression
>>> Expression.set_render("txt") >>> render.set_render("txt")
>>> e = Expression.from_str("2x + 6 - 3x") >>> e = Expression.from_str("2x + 6 - 3x")
>>> print(e) >>> print(e)
2x + 6 - 3x 2x + 6 - 3x
@ -30,7 +30,7 @@ Expression is the classe wich handle all calculus. It can randomly generate or i
""" """
from .API import Expression, Integer, Decimal from .API import Expression, Integer, Decimal, render, Polynomial
from .core import random_list from .core import random_list
from decimal import getcontext from decimal import getcontext
#getcontext().prec = 2 #getcontext().prec = 2

View File

@ -91,9 +91,11 @@ def mul2tex(left, right):
'- 3x' '- 3x'
>>> mul2tex(a, a) >>> mul2tex(a, a)
'x \\times x' 'x \\times x'
>>> mul2tex(a, MO.factory(-3))
'x(- 3)'
""" """
left_ = render_with_parenthesis(left, "*") left_ = render_with_parenthesis(left, "*")
right_ = render_with_parenthesis(right, "*") right_ = render_with_parenthesis(right, "*", is_at_right=True)
display_time = True display_time = True
# if (right_[0].isalpha() and (left_.isnumeric() or left_.isdecimal())) or right_[ # if (right_[0].isalpha() and (left_.isnumeric() or left_.isdecimal())) or right_[
@ -183,23 +185,17 @@ def pow2tex(left, right):
return f"{left_}^{{{right_}}}" return f"{left_}^{{{right_}}}"
def render_with_parenthesis(subtree, operator): def render_with_parenthesis(subtree, operator, is_at_right=False):
subtree_need_parenthesis = False subtree_need_parenthesis = False
try: try:
subtree.node subtree.node
except AttributeError: except AttributeError:
try:
if (
OPERATORS[subtree.MAINOP]["precedence"]
< OPERATORS[operator]["precedence"]
):
subtree_need_parenthesis = True
except (AttributeError, KeyError):
pass
try: try:
subtree_ = subtree.__tex__ subtree_ = subtree.__tex__
except AttributeError: except AttributeError:
subtree_ = str(subtree) subtree_ = str(subtree)
if subtree_.startswith("-") and OPERATORS["-"]["precedence"] < OPERATORS[operator]["precedence"] and is_at_right:
subtree_need_parenthesis = True
else: else:
if OPERATORS[subtree.node]["precedence"] < OPERATORS[operator]["precedence"]: if OPERATORS[subtree.node]["precedence"] < OPERATORS[operator]["precedence"]:
subtree_need_parenthesis = True subtree_need_parenthesis = True

View File

@ -91,11 +91,13 @@ def mul2txt(left, right):
'- 3x' '- 3x'
>>> mul2txt(a, a) >>> mul2txt(a, a)
'x * x' 'x * x'
>>> mul2txt(a, MO.factory(-3))
'x(- 3)'
""" """
display_time = True display_time = True
left_ = render_with_parenthesis(left, "*") left_ = render_with_parenthesis(left, "*")
right_ = render_with_parenthesis(right, "*") right_ = render_with_parenthesis(right, "*", is_at_right=True)
if right_[0].isalpha(): if right_[0].isalpha():
# TODO: C'est bien beurk en dessous... |ven. déc. 21 12:03:07 CET 2018 # TODO: C'est bien beurk en dessous... |ven. déc. 21 12:03:07 CET 2018
@ -187,23 +189,22 @@ def pow2txt(left, right):
return f"{left_}^{right_}" return f"{left_}^{right_}"
def render_with_parenthesis(subtree, operator): def tree_with_parenthesis(subtree, operator):
""" Assuming the subtree is a tree, then have .node """
pass
def render_with_parenthesis(subtree, operator, is_at_right=False):
subtree_need_parenthesis = False subtree_need_parenthesis = False
try: try:
subtree.node subtree.node
except AttributeError: except AttributeError:
try:
if (
OPERATORS[subtree.MAINOP]["precedence"]
< OPERATORS[operator]["precedence"]
):
subtree_need_parenthesis = True
except (AttributeError, KeyError):
pass
try: try:
subtree_ = subtree.__txt__ subtree_ = subtree.__txt__
except AttributeError: except AttributeError:
subtree_ = str(subtree) subtree_ = str(subtree)
if subtree_.startswith("-") and OPERATORS["-"]["precedence"] < OPERATORS[operator]["precedence"] and is_at_right:
subtree_need_parenthesis = True
else: else:
if OPERATORS[subtree.node]["precedence"] < OPERATORS[operator]["precedence"]: if OPERATORS[subtree.node]["precedence"] < OPERATORS[operator]["precedence"]:
subtree_need_parenthesis = True subtree_need_parenthesis = True