Documentation de Pyromaths 21.8.2

pyromaths.outils.Priorites3

Contenu

Code source de pyromaths.outils.Priorites3

#!/usr/bin/env python3

# Pyromaths
# Un programme en Python qui permet de créer des fiches d'exercices types de
# mathématiques niveau collège ainsi que leur corrigé en LaTeX.
# Copyright (C) 2006 -- Jérôme Ortais (jerome.ortais@pyromaths.org)
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
#----------------------------------------------------------------------
# Pyromaths : GESTION DES PRIORITES
#----------------------------------------------------------------------

# from Affichage import decimaux
from pyromaths.outils import Arithmetique


[docs]def cherche_classe(calcul, index): """**cherche_classe**\ (*calcul*\ , *index*) Recherche le premier objet polynôme ou fraction dans la chaîne calcul à une position supérieure ou égale à index, sans expression régulière :param calcul: le calcul à tester :type calcul: string :param index: position à partir de laquelle effectuer le test :type index: integer >>> from pyromaths.classes.PolynomesCollege import Polynome >>> from pyromaths.classes.Fractions import Fraction >>> from pyromaths.outils import Priorites3 >>> Priorites3.cherche_classe('Polynome([[-4, 2]], "x")-Polynome([[-5, 1], [4, 2], [1, 0]], "x")+Polynome([[6, 0], [5, 1]], "x")', 5) Polynome([[-5, 1], [4, 2], [1, 0]], "x") >>> Priorites3.cherche_classe('Polynome([[-4, 2]], "x")+Fraction(3,2)+Polynome([[6, 0], [5, 1]], "x")', 5) Fraction(3,2) :rtype: string """ classes = ["Polynome(", "Fraction(", "SquareRoot("] indexes = [calcul.find(classe, index) for classe in classes] position, i = 0, 1 while i < len(classes): if 0 <= indexes[i] and (indexes[position] < 0 or indexes[i] < indexes[position]): position = i i += 1 if indexes[position] < 0: return None classe = classes[position] index = indexes[position] par, i = 1, index + len(classe) # nombre de parenthèses ouvertes, début de recherche while par: if calcul.find("(", i) > 0: i = min(calcul.find("(", i), calcul.find(")", i)) else: i = calcul.find(")", i) if calcul[i] == ")": par += -1 else: par += 1 i += 1 return calcul[index:i]
[docs]def cherche_decimal(calcul, index): """**cherche_decimal**\ (*calcul*\ , *index*) Recherche le premier nombre décimal dans la chaîne calcul à une position supérieure ou égale à index, sans expression régulière. Un nombre décimal peut être entouré de parenthèses s'il a un signe, ou avoir un signe s'il est en début de chaîne. Cette fonction est 130 fois plus rapide qu'avec une expression régulière. :param calcul: le calcul à tester :type calcul: string :param index: position à partir de laquelle effectuer le test :type index: integer >>> from pyromaths.outils import Priorites3 >>> p = '-Polynome([[-4, 2]], "x")*6**2+3' >>> Priorites3.cherche_decimal(p, 1) 4 >>> p = '-6*(-11)*(-5)' >>> Priorites3.cherche_decimal(p, 1) 6 >>> Priorites3.cherche_decimal(p, 0) 6 **TODO :** vérifier ces deux derniers exemples. Je pense que je devrais récupérer -6 :rtype: string """ end = len(calcul) while index <= end: try: int(calcul[index]) except: index += 1 else: break if index > end: return None while end > index: try: float(calcul[index:end]) except ValueError: end -= 1 else: break if index > 1 and (calcul[index - 2:index] == "(+" or calcul[index - 2:index] == "(-") : if end < len(calcul) and calcul[end] == ")": index -= 2 end += 1 else: index -= 1 return calcul[index:end]
def cherche_string(calcul, index): apostrophes = ["'", "\""] indexes = [calcul.find(apostrophe, index) for apostrophe in apostrophes] position, i = 0, 1 while i < len(apostrophes): if 0 <= indexes[i] and (indexes[position] < 0 or indexes[i] < indexes[position]): position = i i += 1 if indexes[position] < 0: return None apostrophe = apostrophes[position] index = indexes[position] + 1 i = calcul.find(apostrophe, index) return calcul[index:i]
[docs]def cherche_operateur(calcul, index): """**cherche_operateur**\ (*calcul*\ , *min_i*) Recherche le premier opérateur +, -, \*, /, ^ dans la chaîne calcul à une position supérieure ou égale à min_i, sans expression régulière. :param calcul: le calcul à tester :type calcul: string :param min_i: position à partir de laquelle effectuer le test :type min_i: integer >>> from pyromaths.outils import Priorites3 >>> Priorites3.cherche_operateur('-Polynome([[-4, 2]], "x")*6**2+3', 1) - >>> p = '-6*(-11)*(-5)' >>> Priorites3.cherche_operateur(p, 1) * >>> Priorites3.cherche_operateur(p, 0) - :rtype: string """ operateur = ['**', '+', '-', '*', '/', '^'] l = [] for op in operateur: try: l.append(calcul[index:].index(op) + index) except: l.append(None) min_i = 0 for i in range (1, len(l)): if l[i] is not None and (l[min_i] is None or l[i] < l[min_i]): min_i = i if l[min_i] != None: return operateur[min_i] else: return None
[docs]def split_calcul(calcul): """**split_calcul**\ (*calcul*) Partitionne la chaîne de caractères pour obtenir une liste d'opérateurs, de parenthèses, de polynômes et de nombres :param calcul: le calcul à traiter :type calcul: string >>> from pyromaths.outils import Priorites3 >>> Priorites3.split_calcul('-Polynome([[-4, 2]], "x")*6**2+3') ['-', 'Polynome([[-4, 2]], "x")', '*', '6', '**', '2', '+', '3'] >>> Priorites3.split_calcul('-6*(-11)*(-5)') ['-', '6', '*', '(-11)', '*', '(-5)'] >>> Priorites3.split_calcul("Polynome('Fraction(1,3)x')+Polynome('x')") ["Polynome('Fraction(1,3)x')", '+', "Polynome('x')"] **TODO :** vérifier ce dernier exemple. Je pense que je devrais récupérer -6 :rtype: list """ l = [] findings = (cherche_classe, cherche_string, cherche_decimal) # , cherche_operateur) for finding in findings: nb = finding(calcul, 0) while nb: l.extend(calcul.partition(nb)) l[-3] = l[-3].strip() l[-2] = l[-2].strip() l[-1] = l[-1].strip() if l[-3] and l[-2]: l0 = split_calcul(l[-3]) if l0: l0.extend(l[-2:]) l = l[:-3] l.extend(l0) elif not l[-3]: l.pop(-3) calcul = l[-1] nb = finding(calcul, 0) l = l[:-1] if calcul: l.append(calcul) while l and not l[0]: l.pop(0) return l
[docs]def EstNombre(value): """**EstNombre**\ (*value*) Teste si `value` est une valeur, c'est à dire un entier, un réel, un polynôme, une fraction, une racine carrée. Attention : (-11) est considéré comme un nombre :param value: la valeur à traiter :type value: string >>> from pyromaths.outils import Priorites3 >>> Priorites3.EstNombre('-15') True >>> Priorites3.EstNombre('Polynome([[-4, 2]], "x")') True :rtype: list """ from pyromaths.classes.PolynomesCollege import Polynome from pyromaths.classes.Fractions import Fraction from pyromaths.classes.SquareRoot import SquareRoot classe = cherche_classe(value, 0) if classe: if classe != value: return False else: return True #=========================================================================== # if cherche_operateur(value, 1): # return False #=========================================================================== try: return isinstance(eval(value), (float, int, Polynome, Fraction, SquareRoot)) except: return False
[docs]def splitting(calcul): """**splitting**\ (*calcul*) Partitionne la chaîne de caractères pour obtenir une liste d'opérateurs, de parenthèses, de polynômes et de nombres puis arrange la liste des opérandes et opérateurs :param calcul: le calcul à traiter :type calcul: string >>> from pyromaths.outils import Priorites3 >>> Priorites3.splitting('-Polynome([[-4, 2]], "x")*6**2+3') ['-', 'Polynome([[-4, 2]], "x")', '*', '6', '**', '2', '+', '3'] >>> Priorites3.splitting('-6*(-11)*(-5)') ['-6', '*', '(-11)', '*', '(-5)'] >>> Priorites3.splitting("Fraction(1,7)x^2-Fraction(3,8)x-1") ['Fraction(1,7)', 'x', '^', '2', '-', 'Fraction(3,8)', 'x', '-', '1'] >>> Priorites3.splitting('-7**2') ['-', '7', '**', '2'] :rtype: list """ if calcul == "": return [] l = split_calcul(calcul) if l[0] == "+" and len(l) > 1: l[0] += l.pop(1) elif l[0] == "-" and len(l) > 1 and l[1][0] in "0123456789": if len(l)==2 or (len(l)>2 and l[2]!="**" and l[2]!="^"): l[0] += l.pop(1) j = 0 while j < len(l): op, i, t = l[j], 0, [] if op == "**": j += 1 else: if not EstNombre(op): while i < len(op): if op[i:i + 2] == "**": t.append("**") i += 2 else: t.append(op[i]) i += 1 l[j:j + 1] = t j += len(t) else: j += 1 # Recherche les erreurs d'écriture du style 3+-5 à la place de 3+(-5) index = 0 while l[index:].count('-'): i = l.index('-', index) if i and l[i - 1][-1] in '+-*/^': del l[i] if l[i][0] == '-': l[i] == l[i][1:] else:l[i] = '(-%s)' % l[i] index = i + 1 for dummy in range(l.count('\'')): l.remove('\'') for dummy in range(l.count('"')): l.remove('"') return l
[docs]def recherche_parentheses(calcul): """**recherche_parentheses**\ (*calcul*) Recherche les premières parenthèses (éventuellement intérieures) dans une expression :param calcul: le calcul à traiter :type calcul: list >>> from pyromaths.outils import Priorites3 >>> Priorites3.recherche_parentheses(['-6', '*', '(-11)', '*', '(-5)']) None >>> Priorites3.recherche_parentheses(['-9', '-', '6', '*', '(', '(-2)', '-', '4', ')']) (4, 9) :rtype: tuple """ if calcul.count("("): debut = calcul.index("(") if calcul[debut + 1:].count(")"): fin = calcul[debut:].index(")") + debut else: return None for dummy in range(calcul[debut + 1:fin].count("(")): debut += calcul[debut + 1:].index("(") + 1 return (debut, fin + 1) else: return None
[docs]def recherche_puissance(calcul): """**recherche_puissance**\ (*calcul*) Recherche la première occurrence d'une puissance dans une liste de calculs. Elle doit être entourée de deux nombres. :param calcul: le calcul à traiter :type calcul: list >>> from pyromaths.outils import Priorites3 >>> c = ['-6', '**', '(-11)', '*', '(-5)'] >>> Priorites3.recherche_puissance(c) (0, 3) >>> p = ['-', 'Polynome([[-4, 2]], "x")', '**', '2', '+', '3'] >>> Priorites3.recherche_puissance(p) (1, 4) :rtype: tuple """ if calcul.count("**"): i = calcul.index("**") # Si le calcul commence par '**', il n'y a rien à faire if i: return (i - 1, i + 2) return None
[docs]def recherche_operation(calcul, op, l_interdit, debut=0): """**recherche_operation**\ (*calcul*\ , *op*\ , *l_interdit*\ [, *debut*]) Recherche la première occurrence de l'opération op dans la liste de calculs list. L'opérateur doit être entouré de deux nombres, le premier ne doit pas être précédé d'un opérateur inclus dans la liste l_interdit. L'opérateur à trouver doit être avant la position debut (si debut est non nul). :param calcul: le calcul à traiter :type calcul: list :param op: l'opérateur à chercher :type op: string :param l_interdit: liste des opérateurs à ignorer, pour respecter les priorités :type l_interdit: list :param debut: À partir d'où chercher l'opérateur dans l'expression :type debut: integer >>> from pyromaths.outils import Priorites3 >>> c = ['-6', '**', '(-11)', '*', '(-5)'] >>> Priorites3.recherche_operation(c, "*", ("**", "/")) None >>> c = ['-9', '-', '6', '*', '2', '-', '4'] >>> Priorites3.recherche_operation(c, "*", ("**", "/")) 3 :rtype: integer """ ind, fin = 0, len(calcul) for dummy in range(calcul.count(op)): ind = calcul.index(op, ind) if ind == 1 and ind < fin - 1 and EstNombre(calcul[ind - 1]) and\ EstNombre(calcul[ind + 1]): if debut: debut = min(debut, ind) else: debut = ind break elif ind > 1 and ind < fin - 1 and EstNombre(calcul[ind - 1]) and\ EstNombre(calcul[ind + 1]) and calcul[ind - 2] not in l_interdit: if debut: debut = min(debut, ind) else: debut = ind break else: ind += 1 if debut: return debut else: return None
[docs]def recherche_fin_operation(calcul, op, l_interdit, debut): """**recherche_fin_operation**\ (*calcul*\ , *op*\ , *l_interdit*\ , *debut*) Recherche la fin de la suite d'opération @op situé à la position @debut de la liste de calculs @calcul, en vérifiant que cet enchaînement n'est pas suivi par un opérateur compris dans @l_interdit. :param calcul: le calcul à traiter :type calcul: string :param op: l'opérateur à chercher :type op: string :param l_interdit: liste des opérateurs à ignorer, pour respecter les priorités :type l_interdit: list :param debut: À partir d'où chercher l'opérateur dans l'expression :type debut: integer >>> from pyromaths.outils import Priorites3 >>> c = ['-9', '-', '6', '*', '2', '*', '5', '-', '4'] >>> Priorites3.recherche_fin_operation(c, "*", ("**", "/"),0) 2 >>> Priorites3.recherche_fin_operation(c, "*", ("**", "/"),4) 6 :rtype: integer """ index, fin = debut + 2, len(calcul) while index < fin - 1 and calcul[index] == op and EstNombre(calcul[index + 1]): index += 2 if index < fin and calcul[index] in l_interdit: index -= 2 if index == debut: return None return index
[docs]def recherche_produit(calcul): """**recherche_produit**\ (*calcul*) Recherche la première occurrence d'une multiplication ou divisions dans une liste de calculs. Elle doit être précédée d'un nombre qui ne doit pas être précédé d'une puissance ou d'une division, ni suivie d'un exposant. :param calcul: le calcul à traiter :type calcul: list >>> from pyromaths.outils import Priorites3 >>> c = ['-9', '-', '6', '*', '2', '*', '5', '-', '4'] >>> Priorites3.recherche_produit(c) (2, 7) :rtype: tuple """ debut = recherche_operation(calcul, "*", ("**", "/")) debut = recherche_operation(calcul, "/", ("**", "/"), debut) if debut is not None: fin = recherche_fin_operation(calcul, calcul[debut], ("**"), debut) if fin is not None: return (debut - 1, fin) return None
[docs]def recherche_somme(calcul): """**recherche_somme**\ (*calcul*) Recherche la première occurrence d'une addition ou soustraction dans une liste de calculs. Elle doit être précédée d'un nombre qui ne doit pas être précédé d'une puissance, d'une multiplication, d'une division ou d'une soustraction, ni suivie d'un exposant, d'une multiplaication ou d'une division. >>> from pyromaths.outils import Priorites3 >>> Priorites3.recherche_somme(['1', '-', '2', '-', '3']) (0, 5) >>> Priorites3.recherche_somme(['Polynome("x+1")', '-', 'Polynome("x+2")', '-', 'Polynome("x+3")']) (0, 5) :param calcul: le calcul à traiter :type calcul: list :rtype: tuple """ debut = recherche_operation(calcul, "+", ("**", "*", "/", "-")) debut = recherche_operation(calcul, "-", ("**", "*", "/", "-"), debut) if debut is not None: fin = recherche_fin_operation(calcul, calcul[debut], ("**", "*", "/"), debut) if fin is not None: return (debut - 1, fin) return None
[docs]def recherche_neg(calcul): """**recherche_neg**\ (*calcul*) Recherche la première occurence d'un opposé `-(-5)` ou `-Polynome` ou d'une écriture du style `+(-5)` dans une liste de calculs qui ne doit pas être suivie d'un exposant. :param calcul: le calcul à traiter :type calcul: list :rtype: tuple """ ind, debut, fin = 0, None, len(calcul) for dummy in range(calcul.count("-")): ind = calcul.index("-", ind) if ind < fin - 1 and EstNombre(calcul[ind + 1]): if calcul[ind + 1][0] == "(" or ind == 0: # or isinstance(n, Polynome): # or (isinstance(n, Polynome) and (len(n)>1 or n.monomes[0][0]<0)): debut = ind break else: ind += 1 for dummy in range(calcul[ind + 1:].count("+")): ind = calcul.index("+", ind) if ind < fin - 1 and EstNombre(calcul[ind + 1]) and calcul[ind + 1][0] == "(": if debut is not None: debut = min(debut, ind) else: debut = ind break else: ind += 1 if debut is not None and (debut + 2 == fin or (debut + 2 < fin and calcul[debut + 2] != "**")): return (debut, debut + 2) else: return None
[docs]def effectue_calcul(calcul): """**effectue_calcul**\ (*calcul*) Effectue une étape du calcul en respectant les priorités :param calcul: le calcul à traiter :type calcul: list >>> from pyromaths.outils import Priorites3 >>> Priorites3.effectue_calcul(['-5', '-', '(', '(-6)', '-', '1', '+', '(-3)', ')', '*', '(-1)']) ['-5', '-', '(', '-7', '-', '3', ')', '*', '(-1)'] >>> Priorites3.effectue_calcul(['-5', '-', '(', '-7', '-', '3', ')', '*', '(-1)']) ['-5', '-', '-10', '*', '(-1)'] >>> Priorites3.effectue_calcul(['-5', '-', '-10', '*', '(-1)']) ['-5', '-', '10'] >>> Priorites3.effectue_calcul(['-5', '-', '10']) ['-15'] >>> Priorites3.effectue_calcul(['-', 'Polynome("x-1")', '*', '2']) ['-', '(', 'Polynome([[2, 1]], "x", 0)', '+', 'Polynome([[-2, 0]], "x", 0)', ')'] >>> Priorites3.effectue_calcul(['4', '*', 'Polynome("x+1")', '**', '2']) ['4', '*', '(', 'Polynome([[1, 1]], "x", 0)', '**', '2', '+', '2', '*', 'Polynome([[1, 1]], "x", 0)', '*', 'Polynome([[1, 0]], "x", 0)', '+', 'Polynome([[1, 0]], "x", 0)', '**', '2', ')'] :rtype: list """ from pyromaths.classes.PolynomesCollege import Polynome from pyromaths.classes.Fractions import Fraction from pyromaths.classes.SquareRoot import SquareRoot serie = (recherche_parentheses, recherche_puissance, recherche_produit, recherche_neg, recherche_somme) result, post, break_somme = [], "", False for recherche in serie: if break_somme and recherche == recherche_somme: break if calcul: test = recherche(calcul) else: test = None while test: pre = calcul[:test[0]] calc = calcul[test[0]:test[1]] post = calcul[test[1]:] # On essaie d'utiliser les priorités sur la première partie du # calcul pour raccourcir la résolution de l'expression if test != recherche_neg and pre: # Si on simplifie les écritures, on n'essaie pas les sommes tmp = effectue_calcul(pre) if tmp and result and result[-1] not in "+-**/(" and tmp[0][0]\ not in "+-*/)": # un signe + si l'expression en a besoin result.append("+") # On ajoute le résultat ou l'expression if tmp: result.extend(tmp) else: result.extend(pre) else: result.extend(pre) if recherche == recherche_parentheses: # On supprime les parenthèses autour de l'expression calc = calc[1:-1] # On réduit directement les calculs numériques dans une # expression littérale "Effectue les calculs entre parenthèses et remet les parenthèses si l'expression est de longueur supérieure à 1" sol = effectue_calcul(calc) if len(sol) > 1: sol.insert(0, "(") sol.append(")") elif sol and isinstance(eval(sol[0]), (int, float, Fraction)) and post and post[0] == "*" and \ _('Polynome(') in post[1] and len(eval(post[1])) == 1 and eval(post[1])[0][0] == 1: # Sans doute une factorisation de sommes de polynômes sol = [repr(eval(sol[0]) * eval(post[1]))] post = post[2:] # Suppression des parenthèses autour de ((9.0-80.0)*Polynome("x")) devenu (Polynome("-71.0x")) if post and result and post[0] == ")" and result[-1] == "(" : result, post = result[:-1], post[1:] else: if recherche == recherche_somme: # Permet les cas 1 + Fraction(1, 2) + 1 # ou 3 + Polynome("5x") + 4 frac, poly, nombres = False, False, [] for i in range(0, len(calc), 2): nombres.append(eval(calc[i])) if isinstance(nombres[-1], Fraction): frac = True elif isinstance(nombres[-1], Polynome): poly, var, details = True, nombres[-1].var, nombres[-1].details if poly: nombres = [(Polynome([[i, 0]], var, details) , i)[isinstance(i, Polynome)] for i in nombres] elif frac: nombres = [(Fraction(i, 1), i)[isinstance(i, Fraction)] for i in nombres] if poly: classe = Polynome elif frac: classe = Fraction if poly or frac: if calc[1] == '+': operation = classe.__add__ else: operation = classe.__sub__ if isinstance(nombres[0], (int, float)): sol = operation(classe(nombres[0]), *nombres[1:]) else: sol = operation(nombres[0], *nombres[1:]) else: sol = eval("".join(calc)) elif recherche == recherche_produit and calc[1] == "*": frac, poly, nombres = False, False, [] for i in range(0, len(calc), 2): nombres.append(eval(calc[i])) if isinstance(nombres[-1], Fraction): frac = True elif isinstance(nombres[-1], Polynome): poly, var, details = True, nombres[-1].var, nombres[-1].details if poly: nombres = [(Polynome([[i, 0]], var, details) , i)[isinstance(i, Polynome)] for i in nombres] elif frac: nombres = [(Fraction(i, 1), i)[isinstance(i, Fraction)] for i in nombres] if poly: classe = Polynome elif frac: classe = Fraction if poly or frac: if isinstance(nombres[0], (int, float)): sol = classe.__mul__(classe(nombres[0]), *nombres[1:]) else: sol = classe.__mul__(nombres[0], *nombres[1:]) else: sol = eval("".join(calc)) elif recherche == recherche_puissance: sol = eval('(' + calc[0] + ')**' + calc[2]) else: sol = eval("".join(calc)) if isinstance(sol, str): sol = splitting(sol) elif isinstance(sol, (int, float)): sol = [str(sol)] elif isinstance(sol, (Polynome, Fraction, SquareRoot)): sol = [repr(sol)] else : raise ValueError(_(u"Le résultat %s a un format inattendu") % sol) if recherche == recherche_neg and (pre or result): # Ajoute le "+" ou sépare le "-": # "1-(-9)" => "1 + 9" et "1+(-9)" => "1 - 9" if sol[0][0] == "-": sol = ["-", sol[0][1:]] else: sol = ["+", sol[0]] #=================================================================== # if recherche == recherche_produit and len(sol) > 1: # # Ajoute les parenthèses si produit précédé d'un "-" ou "*" # # ou suivi d'un "*" #=================================================================== if len(sol) > 1 and sol[0] != "(" and sol[-1] != ")": # Ajoute les parenthèses si le résultat est précédé d'un "-" ou "*" # ou suivi d'un "*" if (result and result[-1] in "*-") or (pre and pre[-1] in "*-") or (post and post[0] == "*"): sol.insert(0, "(") sol.append(")") # Si @sol est négatif et @result se termine par un "+", on l'enlève if result and result[-1] == "+" and sol and sol[0][0] == "-": result[-1] = "-" sol[0] = sol[0].lstrip("-") result.extend(sol) calcul = post if calcul: test = recherche(calcul) else: test = None if post and recherche == recherche_neg: break_somme = True result.extend(post) if not result: result = calcul return result
[docs]def priorites(calcul): r"""**priorites**\ (*calcul*) Effectue un enchaînement d'opérations contenues dans calcul en respectant les priorités et en détaillant les étapes. :param calcul: le calcul à traiter :type calcul: string >>> from pyromaths.outils import Priorites3 >>> Priorites3.priorites('-1+5-(-5)+(-6)*1') [['4', '+', '5', '-', '6'], ['9', '-', '6'], ['3']] >>> Priorites3.priorites('-5**2+6') [['-', '25', '+', '6'], ['-25', '+', '6'], ['-19']] >>> Priorites3.priorites('Polynome([[Fraction(6, 7), 0]], "x")*Polynome([[Fraction(1,3), 1], [1,0]], "x")') [['Polynome([[Fraction(6, 21, "s"), 1]], "x", 0)', '+', 'Polynome([[Fraction(6, 7), 0]], "x", 0)'], ['Polynome([[Fraction(2, 7), 1], [Fraction(6, 7), 0]], "x", 0)']] >>> Priorites3.priorites('-Fraction(-6,1)/Fraction(-4,1)') [['-', '(', 'Fraction(-6, 1)', '*', 'Fraction(1, -4)', ')'], ['-', 'Fraction("2*-3", "2*-2", "s")'], ['Fraction(-3, 2)']] :rtype: list """ calcul = splitting(calcul) #calcul = split_calcul(calcul) solution = [] while len(calcul) > 1: s = effectue_calcul(calcul) if s: if s == calcul: s, solution[0] solution.append(s) calcul = list(s) # dissocie calcul et s if 'Polynome(' in calcul[0][:9]: from pyromaths.classes.PolynomesCollege import Polynome from pyromaths.classes.Fractions import Fraction p = eval(calcul[0]) p = p.nreduction() while (solution and repr(p) != solution[-1][0]) or (not solution and repr(p) != calcul[0]): solution.append([repr(p)]) p = p.nreduction() if 'Fraction(' in calcul[0][:9]: from pyromaths.classes.Fractions import Fraction from pyromaths.classes.SquareRoot import SquareRoot f = eval(calcul[0]) f = f.traitement(True) while (solution and repr(f) != solution[-1][0]) or (not solution and repr(f) != calcul[0]): solution.append([repr(f)]) # si la fraction est écrite sous la forme d'un entier, c'est fini if isinstance(f, str): f = eval(f) if isinstance(f, int): break f = f.traitement(True) return solution
[docs]def texifystring(calcul): r"""**texify**\ (*calcul*) convertit la chaîne de caractères en chaîne au format TeX. """ return texify([splitting(calcul)])[0]
[docs]def texify(liste_calculs): r"""**texify**\ (*liste_calculs*) Convertit la liste de chaînes de caractères `liste_calculs` contenant des polynômes en liste de chaînes de caractères au format TeX **TODO :** intégrer cela dans :mod:`outils.Affichage` et gérer l'ensemble des classes de Pyromaths. :param calcul: le calcul à traiter :type calcul: string >>> from pyromaths.outils import Priorites3 >>> from pyromaths.classes.PolynomesCollege import Polynome >>> l = [['4', '+', '5', '-', '6'], ['9', '-', '6'], ['3']] >>> Priorites3.texify(l) ['4+5-6', '9-6', '3'] >>> Priorites3.texify(Priorites3.priorites('(-7)+8-Polynome([[-4, 1], [-9, 2], [-5, 0]], "x")')) ['1-\\left( -4\\,x-9\\,x^{2}-5\\right) ', '1+4\\,x+9\\,x^{2}+5', '9\\,x^{2}+4\\,x+6'] >>> Priorites3.texify([['Fraction(5,6)', '**', '2']]) ['\\left( \\dfrac{5}{6} \\right) ^{2}'] :rtype: list """ from pyromaths.classes.PolynomesCollege import Polynome from pyromaths.classes.Fractions import Fraction from pyromaths.classes.SquareRoot import SquareRoot from .Affichage import decimaux ls = [] enluminures = {'indice': r'_{', 'cancel':r'\cancel{'} isEnlumine = {'indice': False, 'cancel':False} for calcul in liste_calculs: if isinstance(calcul, str): calcul = splitting(calcul) s = "" puiss = 0 for index in range(len(calcul)): el = calcul[index] for cle in list(isEnlumine.keys()): if isEnlumine[cle] and (not isinstance(el, list) or el[1] != cle): s += '}' isEnlumine[cle] = False if isinstance(el, list): if not isEnlumine[el[1]]: s += enluminures[el[1]] isEnlumine[el[1]] = True el = el[0] if el[:9] == "Polynome(": # Doit-on entourer ce polynôme de parenthèses ? p = eval(el) if index + 1 < len(calcul): q = calcul[index + 1] else: q = "" """ 3 cas : * {*,-}(2x+3) ou {*,-}(-2x) * (2x+3)*... * (2x+1)**2""" if type(p.monomes[0][0])==str: a=eval(priorites(p.monomes[0][0])[0][-1]) else: a=p.monomes[0][0] if (s and s[-1] in "*-" and (len(p) > 1 or a < 0)) \ or (q and q == "*" and len(p) > 1) \ or ((len(p) > 1 or (a != 1 and p.monomes[0][1] > 0) or \ a < 0 or \ (a != 1 and isinstance(a, Fraction) and a.d != 1)) and q and q == "**"): s += "(" + str(p) + ")" elif s and s[-1] == "+" and type(a) == int and a < 0: s = s[:-1] s += str(p) else: s += str(p) elif el[:9] == "Fraction(": # Doit-on entourer cette fraction de parenthèses ? p = splitting(el[9:-1]) # Gère le cas ou la fraction comprend des objets SquareRoot t = [""] for i in range(len(p)): if p[i] == ',': t.append("") else: t[-1] += p[i] p = t if len(p) == 2: # texfrac = str(Fraction(eval(p[0]), eval(p[1]))) texfrac = str(Fraction(p[0], p[1])) else: texfrac = str(Fraction(p[0], p[1], p[2])) if index + 1 < len(calcul): q = calcul[index + 1] else: q = "" if (eval(p[0]) < 0 or p[1] != "1") and q == "**": s += "( " + texfrac + " )" else: s += texfrac elif el[:11] == "SquareRoot(": p = eval(el) if index + 1 < len(calcul): q = calcul[index + 1] else: q = "" """ 3 cas : * {*,-}(2x+3) ou {*,-}(-2x) * (2x+3)*... * (2x+1)**2""" if (s and s[-1] in "*-" and (len(p) > 1 or p[0][0] < 0)) \ or (q and q == "*" and len(p) > 1) \ or ((len(p) > 1 or (p[0][0] != 1 and p[0][1] > 0) or \ p[0][0] < 0 or \ (p[0][0] != 1 and isinstance(p[0][0], Fraction) and p[0][0].d != 1)) and q and q == "**"): s += "(" + str(p) + ")" elif s and s[-1] == "+" and p[0][0] < 0: s = s[:-1] s += str(p) else: s += str(p) elif EstNombre(el): if index + 1 < len(calcul): q = calcul[index + 1] else: q = "" if el[0] == "(": s += "(" + decimaux(el[1:-1]) + ")" elif el[0] == '-' and ((s and s[-1] in "+/*-") \ or (q and q == "**")): s += "(" + decimaux(el) + ")" else: s += decimaux(el) elif el == "**": s += "**{" puiss = 1 elif el == "(": if puiss: puiss += 1 s += "(" elif el == ")": if puiss: puiss -= 1 s += ")" else : # "+", "-", "*", "/" s += el if puiss == 1 and s[-1] != r"{": puiss = 0 s += "}" for cle in list(isEnlumine.keys()): if isEnlumine[cle] and (not isinstance(el, list) or el[1] != cle): s += '}' s = s.replace("**{", "^{") s = s.replace("(", "\\left( ") s = s.replace(")", "\\right) ") s = s.replace("\\left\\left", "\\left ") s = s.replace("\\right\\right", "\\right ") s = s.replace("*", "\\times ") s = s.replace("/", "\\div ") if not ls or s != ls[-1]: ls.append(s) return ls
[docs]def plotify(calcul): r"""**plotify**\ (*calcul*) Convertit la chaîne de caractères `calcul` contenant des polynômes une chaîne de caractères au format psplot **TODO :** intégrer cela dans :mod:`outils.Affichage` et gérer l'ensemble des classes de Pyromaths. :param calcul: le calcul à traiter :type calcul: string >>> from pyromaths.outils import Priorites3 >>> Priorites3.plotify('Polynome([[Fraction(-5, 192), 4], [Fraction(2, 96), 3], [Fraction(41, 48), 2], [Fraction(-7, 12), 1], [-4, 0]], "x", False)') -5/192*x^4+2/96*x^3+41/48*x^2-7/12*x^1-4 :rtype: str """ from pyromaths.classes.PolynomesCollege import Polynome from pyromaths.classes.Fractions import Fraction from .Affichage import decimaux if isinstance(calcul, str): calcul = splitting(calcul) s = "" puiss = 0 for i in range(len(calcul)): el = calcul[i] if el[:9] == "Polynome(": # Doit-on entourer ce polynôme de parenthèses ? p = eval(el) if i + 1 < len(calcul): q = calcul[i + 1] else: q = "" """ 3 cas : * {*,-}(2x+3) ou {*,-}(-2x) * (2x+3)*... * (2x+1)**2""" res = [] for m in p.monomes: texte = '' if isinstance(m[0], Fraction): texte = str(m[0].n) + "/" + str(m[0].d) elif isinstance(m[0], (float, int)): texte = str(m[0]) if m[1]: texte += "*x^%s" % m[1] res.append(texte) t = "+".join(res) t = t.replace("+-", "-") if (s and s[-1] in "*-" and (len(p) > 1 or p.monomes[0][0] < 0)) \ or (q and q == "*" and len(p) > 1) \ or ((len(p) > 1 or p.monomes[0][0] != 1) and q and q == "**"): s += "(" + t + ")" elif s and s[-1] == "+" and p.monomes[0][0] < 0: s = s[:-1] s += t else: s += t elif el[:9] == "Fraction(": # Doit-on entourer cette fraction de parenthèses ? p = el[9:-1].split(",") if len(p) == 2: texfrac = p[0] + "/" + p[1] else: raise ValueError(_(u'On ne devrait pas rencontrer de fraction non simplifiée ici')) if i + 1 < len(calcul): q = calcul[i + 1] else: q = "" if (eval(p[0]) < 0 or p[1] != "1") and q and q == "**": s += "( " + texfrac + " )" else: s += texfrac elif EstNombre(el): if el[0] == "(": s += "(" + decimaux(el[1:-1]) + ")" else: s += decimaux(el) elif el == "**": s += "^(" puiss += 1 elif el == "(": if puiss: puiss += 1 s += "(" elif el == ")": if puiss: puiss -= 1 s += ")" else : # "+", "-", "*", "/" s += el if puiss == 1 and s[-1] != "": puiss = 0 s += ")" s = s.replace("**{", "^(") s = s.replace(r"\,", "*") return s

Contenu