Finish unify_render! :D and even mod the doc

This commit is contained in:
Lafrite 2014-08-29 17:15:29 +02:00
parent 71b4c987ec
commit 412149f22d
3 changed files with 50 additions and 39 deletions

View File

@ -25,23 +25,39 @@ Un expression peut être initialisée de deux façons différentes: à partir d'
>>> exp = Expression("1 + 2 * 3")
>>> exp = Expression([1, "+", 2, "*", 3])
On peut ensuite afficher l'expression avec un *print* (pour un rendu en mode texte).
On peut ensuite afficher l'expression avec un *print*.
>>> print(exp)
1 + 2 \times 3
Et si l'on souhaite un rendu plus adapté à la console:
>>> from pymath.renders import txt
>>> exp.render(render = txt)
1 + 2 * 3
Ou encore
>>> from pymath.renders import txt
>>> Expression.STR_RENDER = txt
>>> print(exp)
1 + 2 * 3
Et si l'on souhaite un rendu en latex:
/!\ Il ne faut pas faire
>>> from pymath.renders import tex
>>> exp.render(render = tex)
1 + 2 \times 3
>>> exp.STR_RENDER = txt
car le changement ne se propagera pas à toute la classe. Ce qui posera problème quand on utilisera la méthode *simplify*(les sous expressions auront l'ancien STR_RENDER).
### Simplification des expressions
Une fois les expressions créées, elles peuvent se réduire en expliquant les étapes et en respectant les règles de priorités. Les exemples suivants seront données avec un rendu texte.
>>> from pymath.expression import Expression
>>> from pymath.renders import txt
>>> Expression.STR_RENDER = txt
>>> exp = Expression("1 + 2 * 3")
>>> for i in exp.simplify(render = txt):
>>> for i in exp.simplify():
... print(i)
...
1 + 2 * 3
@ -52,7 +68,7 @@ Une fois les expressions créées, elles peuvent se réduire en expliquant les
Les opérations autorisées sont les opérations "classique": + - * / ^. L'utilisation des parenthèses est aussi gérée.
>>> exp = Expression("1 + 2 / 5")
>>> for i in exp.simplify(render = txt):
>>> for i in exp.simplify():
... print(i)
...
1 + 2 / 5
@ -70,11 +86,10 @@ Les opérations autorisées sont les opérations "classique": + - * / ^. L'utili
-30
### Différents rendus
Comme dit dans l'introduction, il y a deux types de rendus: un rendus texte (utilisé depuis le début) et un rendus latex. Voici un exemple de l'utilisation du rendu latex
Comme dit dans l'introduction, il y a deux types de rendus: un rendus texte (utilisé depuis le début) et un rendus latex. Voici un exemple de l'utilisation du rendu latex (par défaut)
>>> from pymath.renders import tex
>>> exp = Expression("1 + 2 / 5")
>>> for i in exp.simplify(render = tex):
>>> for i in exp.simplify():
... print(i)
...
1 + \frac{ 2 }{ 5 }
@ -94,12 +109,16 @@ Pour créer une expression il faut au moins une chose: la forme de l'expression.
>>> form = "2* {a} + 3"
>>> rd_exp = RdExpression(form)
>>> rd_exp()
>>> e = rd_exp()
>>> type(e)
pymath.expression.Expression
>>> print(e)
'2 \\times 9 + 3'
>>> rd_exp(30, 40)
'2 \\times 31 + 3'
On remarque que ici le rendu est directement en latex (je ne sais d'ailleurs pas si c'est une très bonne idée que le rendu par défaut ne soit pas le même qu'avec expression...).
On remarque que ici que rd_exp renvoie une expression. Cela permettra qu'ensuite on puisse simplifier ou manipuler les expressions
On verra plus tard comment se passer de cette classe pour par exemple créer des expressions avec des fonctions non implémentées dans Expression.
### Créer une expression avec conditions
Parfois il peut être nécessaire d'imposer des conditions sur les éléments à générer pour créer des exercices spécifiques.
@ -107,7 +126,7 @@ Parfois il peut être nécessaire d'imposer des conditions sur les éléments à
>>> form = "{a} / {b} + {c} / {d}"
>>> cond = ["abs({b}) != 1", "{d} > 1", "{b} != {d}", "gcd({a},{b}) == 1", "gcd({c},{d}) == 1"]
>>> rd_frac_add = RdExpression(form, cond)
>>> rd_frac_add()
>>> print(rd_frac_add())
'\\frac{ 4 }{ 5 } + \\frac{ 9 }{ 7 }'
La méthode pour créer les valeurs avec des conditions est la méthode par rejet. Elle n'est pas très efficace et rien n'est encore prévu dans le cas où aucune valeur n'est possible.
@ -118,35 +137,30 @@ Pour éviter de faire tourner la méthode par rejet trop longtemps, il est possi
>>> form = "{a} / {b} + {c} / {k*b}"
>>> cond = ["abs({b}) != 1", "{k} > 1", "{b} != {d}", "gcd({a},{b}) == 1", "gcd({c},{k*b}) == 1"]
>>> rd_frac_add = RdExpression(form, cond)
>>> rd_frac_add()
>>> print(rd_frac_add())
'\\frac{ -9 }{ 7 } + \\frac{ 1 }{ 28 }
### Rendu des expressions
Le rendu des expressions se fait avec la classe Expression présentée plus haut. C'est pratique car cela permet de profiter des rendus automatiques en latex. Mais cela ne permet par de réutiliser facilement l'expression (pour une correction par exemple) et cela gène quand on veut utiliser des choses que Expression ne sait pas gérer.
On peut vouloir ne pas passer passer par la classe Expression pour obtenir notre expression (si l'on veut utiliser la racine carré par exemple). Pour cela il va falloir changer la forme du rendu
>>> RdExpression.FORM = "raw"
>>> form = "{a} / {b} + {c} / {k*b}"
>>> cond = ["abs({b}) != 1", "{d} > 1", "{b} != {d}", "gcd({a},{b}) == 1", "gcd({c},{k*b}) == 1"]
>>> rd_frac_add = RdExpression(form, cond)
>>> exp = rd_frac_add.raw_exp()
>>> exp = rd_frac_add()
>>> type(exp)
str
>>> print(exp)
-2 / 5 + -8 / 35
>>> for i in exp.simplify(render = txt):
... print(i)
...
-2 / 5 + -8 / 35
-2 / 5 + ( -8 / 35 )
( -2 * 7 ) / ( 5 * 7 ) + ( -8 * 1 ) / ( 35 * 1 )
( -14 + ( -8 ) ) / 35
-22 / 35
>>> form = "{a**2}x^2 + {2*a*b} x + {b**2}"
>>> rd_id_rmq = RdExpression(form, with_Exp = False)
>>> rd_id_rmq()
>>> print(rd_id_rmq())
'100x^2 + -180 x + 81'
>>> rd_id_rmq()
'49x^2 + 42 x + 9'
On remarque le défaut d'utiliser *with_Exp* le rendu est moins bien fait (dans l'exemple, il n'y a pas de parenthèses autour du -180).
On remarque le défaut d'utiliser cette forme, le rendu est moins bien fait (dans l'exemple, il n'y a pas de parenthèses autour du -8).

View File

@ -47,24 +47,20 @@ class Expression(object):
## ---------------------
## Mechanism functions
def simplify(self, render = lambda x:str(x)):
""" Generator which return steps for computing the expression
:param render: function which render the list of token (postfix form now) to string
"""
def simplify(self):
""" Generator which return steps for computing the expression """
if not self.can_go_further():
yield render(self.postfix_tokens)
yield self.STR_RENDER(self.postfix_tokens)
else:
self.compute_exp()
old_s = ''
for s in self.steps:
new_s = render(s)
new_s = self.STR_RENDER(s)
# Astuce pour éviter d'avoir deux fois la même étape (par exemple pour la transfo d'une division en fraction)
if new_s != old_s:
old_s = new_s
yield new_s
for s in self.child.simplify(render = render):
for s in self.child.simplify():
if old_s != s:
yield s
@ -329,9 +325,7 @@ class Expression(object):
def test(exp):
a = Expression(exp)
#for i in a.simplify():
#for i in a.simplify(render = txt):
for i in a.simplify(render = tex):
for i in a.simplify():
print(i)
print("\n")

View File

@ -8,7 +8,7 @@ import unittest
from pymath.expression import Expression
from pymath.fraction import Fraction
from pymath.generic import first_elem
from pymath.renders import txt
from pymath.renders import txt, tex
class TestExpression(unittest.TestCase):
@ -76,6 +76,7 @@ class TestExpression(unittest.TestCase):
def test_simplify_frac(self):
exp = Expression("1/2 - 4")
Expression.STR_RENDER = lambda _,x : str(x)
steps = ["[1, 2, '/', 4, '-']", \
"[< Fraction 1 / 2>, 4, '-']", \
"[1, 1, '*', 2, 1, '*', '/', 4, 2, '*', 1, 2, '*', '/', '-']", \
@ -83,6 +84,8 @@ class TestExpression(unittest.TestCase):
'[< Fraction -7 / 2>]']
self.assertEqual(steps, list(exp.simplify()))
Expression.STR_RENDER = tex
if __name__ == '__main__':
unittest.main()