rewrite expression.simplify and adapt Fraction to it

This commit is contained in:
Benjamin Bertrand 2016-02-13 20:54:13 +03:00
parent f968a25345
commit bfafaac319
2 changed files with 95 additions and 73 deletions

View File

@ -103,32 +103,34 @@ class Expression(Explicable):
) )
) )
if len(expression.postfix_tokens) == 1: # if len(expression.postfix_tokens) == 1:
token = expression.postfix_tokens[0] # token = expression.postfix_tokens[0]
if isinstance(token, Explicable_int) or isinstance(token, int): # if isinstance(token, Explicable_int) or isinstance(token, int):
return Explicable_int(token) # return Explicable_int(token)
# TODO: J'en arrive au soucis même soucis qu'avec les fractions qui une fois simplifiée devrait être des Explicable_int. Mais comment on ne redéfini pas les opérations, ce sont les opérations des int qui se font et donc on perd toute l'historique. |sam. févr. 13 18:57:45 EAT 2016 # # TODO: J'en arrive au soucis même soucis qu'avec les fractions qui une fois simplifiée devrait être des Explicable_int. Mais comment on ne redéfini pas les opérations, ce sont les opérations des int qui se font et donc on perd toute l'historique. |sam. févr. 13 18:57:45 EAT 2016
if isinstance(token, Explicable_float) or isinstance(token, float): # if isinstance(token, Explicable_float) or isinstance(token, float):
return Explicable_float(token) # return Explicable_float(token)
elif hasattr(token, 'simplify') and hasattr(token, 'explain'): # elif hasattr(token, 'simplify') and hasattr(token, 'explain'):
ans = expression.postfix_tokens[0] # ans = expression.postfix_tokens[0]
return ans # return ans
elif isinstance(token, str): # elif isinstance(token, str):
from .polynom import Polynom # from .polynom import Polynom
return Polynom([0,1], letter = token) # return Polynom([0,1], letter = token)
else: # else:
raise ValueError( # raise ValueError(
"Unknow token type in Expression: {}".format( # "Unknow token type in Expression: {}".format(
type(token))) # type(token)))
else: # else:
expression._isExpression = 1 # expression._isExpression = 1
return expression # return expression
expression._isExpression = 1
return expression
def __str__(self): def __str__(self):
""" """
@ -144,43 +146,77 @@ class Expression(Explicable):
def simplify(self): def simplify(self):
""" Compute entirely the expression and return the result with .steps attribute """ """ Compute entirely the expression and return the result with .steps attribute """
self.compute_exp() try:
self.compute_exp()
except ComputeError:
try:
self.simplified = self.postfix_tokens[0].simplify()
except AttributeError:
if isinstance(self.postfix_tokens[0],int):
self.simplified = Explicable_int(self.postfix_tokens[0])
elif isinstance(self.postfix_tokens[0],float):
self.simplified = Explicable_float(self.postfix_tokens[0])
else:
self.simplified = self
self.simplified = self.child.simplify() else:
self.simplified.steps = self.child.steps + self.simplified.steps self.simplified = self.child.simplify()
self.simplified.steps = self.child.steps + self.simplified.steps
return self.simplified return self.simplified
def compute_exp(self): def compute_exp(self):
""" Create self.child with and stock steps in it """ """ Create self.child with and stock steps in it """
ini_step = Expression(self.postfix_tokens) if len(self.postfix_tokens) == 1:
raise ComputeError("Nothing to compute in {}".format(self.postfix_tokens))
else:
ini_step = Expression(self.postfix_tokens)
tokenList = self.postfix_tokens.copy() tokenList = self.postfix_tokens.copy()
tmpTokenList = [] tmpTokenList = []
while len(tokenList) > 2: while len(tokenList) > 2:
# on va chercher les motifs du genre A B +, quand l'operateur est # on va chercher les motifs du genre A B +, quand l'operateur est
# d'arité 2, pour les calculer # d'arité 2, pour les calculer
if isNumerand(tokenList[0]) and isNumerand(tokenList[1]) \ if isNumerand(tokenList[0]) and isNumerand(tokenList[1]) \
and isOperator(tokenList[2]) and tokenList[2].arity == 2: and isOperator(tokenList[2]) and tokenList[2].arity == 2:
# S'il y a une opération à faire # S'il y a une opération à faire
op1 = tokenList[0] op1 = tokenList[0]
op2 = tokenList[1] op2 = tokenList[1]
operator = tokenList[2] operator = tokenList[2]
res = operator(op1, op2) res = operator(op1, op2)
tmpTokenList.append(res) tmpTokenList.append(res)
# Comme on vient de faire le calcul, on peut détruire aussi les # Comme on vient de faire le calcul, on peut détruire aussi les
# deux prochains termes # deux prochains termes
del tokenList[0:3] del tokenList[0:3]
# Et les motifs du gens A -, quand l'operateur est d'arité 1 # Et les motifs du gens A -, quand l'operateur est d'arité 1
elif isNumerand(tokenList[0]) \ elif isNumerand(tokenList[0]) \
and isOperator(tokenList[1]) and tokenList[1].arity == 1:
# S'il y a une opération à faire
op1 = tokenList[0]
operator = tokenList[1]
res = operator(op1)
tmpTokenList.append(res)
# Comme on vient de faire le calcul, on peut détruire aussi les
# deux prochains termes
del tokenList[0:2]
else:
tmpTokenList.append(tokenList[0])
del tokenList[0]
if len(tokenList) == 2 and isNumerand(tokenList[0]) \
and isOperator(tokenList[1]) and tokenList[1].arity == 1: and isOperator(tokenList[1]) and tokenList[1].arity == 1:
# S'il reste deux éléments dont un operation d'arité 1
# S'il y a une opération à faire
op1 = tokenList[0] op1 = tokenList[0]
operator = tokenList[1] operator = tokenList[1]
@ -192,34 +228,15 @@ class Expression(Explicable):
# deux prochains termes # deux prochains termes
del tokenList[0:2] del tokenList[0:2]
tmpTokenList += tokenList
self.child = Expression(tmpTokenList)
steps = self.develop_steps(tmpTokenList)
if self.child.postfix_tokens == ini_step.postfix_tokens:
self.child.steps = steps
else: else:
tmpTokenList.append(tokenList[0]) self.child.steps = [ini_step] + steps
del tokenList[0]
if len(tokenList) == 2 and isNumerand(tokenList[0]) \
and isOperator(tokenList[1]) and tokenList[1].arity == 1:
# S'il reste deux éléments dont un operation d'arité 1
op1 = tokenList[0]
operator = tokenList[1]
res = operator(op1)
tmpTokenList.append(res)
# Comme on vient de faire le calcul, on peut détruire aussi les
# deux prochains termes
del tokenList[0:2]
tmpTokenList += tokenList
self.child = Expression(tmpTokenList)
steps = self.develop_steps(tmpTokenList)
if self.child.postfix_tokens == ini_step.postfix_tokens:
self.child.steps = steps
else:
self.child.steps = [ini_step] + steps
def develop_steps(self, tokenList): def develop_steps(self, tokenList):
""" From a list of tokens, it develops steps of each tokens """ """ From a list of tokens, it develops steps of each tokens """
@ -363,6 +380,11 @@ class Expression(Explicable):
def __neg__(self): def __neg__(self):
return Expression(self.postfix_tokens + [op.sub1]) return Expression(self.postfix_tokens + [op.sub1])
class ExpressionError(Exception):
pass
class ComputeError(Exception):
pass
def untest(exp): def untest(exp):
a = Expression(exp) a = Expression(exp)

View File

@ -60,7 +60,7 @@ class Fraction(Explicable):
ini_step = [Expression(self.postfix_tokens)] ini_step = [Expression(self.postfix_tokens)]
if self._num == 0: if self._num == 0:
return Expression([0]) return Expression([0]).simplify()
elif isinstance(self._num, Fraction) or isinstance(self._denom, Fraction): elif isinstance(self._num, Fraction) or isinstance(self._denom, Fraction):
return self._num / self._denom return self._num / self._denom
@ -74,7 +74,7 @@ class Fraction(Explicable):
gcd_ = gcd(abs(self._num), abs(self._denom)) gcd_ = gcd(abs(self._num), abs(self._denom))
if gcd_ == self._denom: if gcd_ == self._denom:
n_frac = self._num // gcd_ n_frac = self._num // gcd_
return Expression([n_frac]) return Expression([n_frac]).simplify()
elif gcd_ != 1: elif gcd_ != 1:
n_frac = Fraction(self._num // gcd_, self._denom // gcd_) n_frac = Fraction(self._num // gcd_, self._denom // gcd_)