Le générateur d'exemples arithmétiques simples pour les nuls et pas seulement

Salut

Dans cet "article", ou plutôt l'essai, je vais vous montrer un moyen très simple de vous amuser en connaissant les bases du latex et du python.




Pourquoi?


Eh bien, vous pouvez générer des expressions simples pour que les enfants puissent compter. Ou juste comme ça. Oui, au moins mets le papier peint, si tu es aussi fanatique que moi.

Comment est-ce censé fonctionner?


L'idée est vraiment très simple, absolument n'importe qui peut écrire un tel programme. Nous voulons générer une expression égale à un certain nombre n (que l'utilisateur entre). Tout nombre peut être remplacé par une expression arithmétique, par exemple, 3 = 1 + 2. Et 2 est 4/2. C'est ainsi que nous avons généré 3 = 1 + 4/2. De même, nous introduisons plusieurs opérations différentes et l'enveloppons dans LaTeX, le langage de formule.

Vous aurez besoin de ...
Expérience d'une semaine en python et matplotlib. Je suis sérieux.

Mécanisme principal


Nous devons analyser l'expression afin de tirer les chiffres de là. Appelons notre classe comme un générateur de problèmes (ça nous manque tous tellement!)

import random from math import log import math import sys sys.setrecursionlimit(1000) #       class ProblemGenerator: def extract_nums(self, exp): symbols = list(exp) NUM = "1234567890." for i in range(len(symbols)): symbols[i] = "N" if symbols[i] in NUM else "T" begins = [] ends = [] for i in range(len(symbols) - 1): fn = symbols[i] + symbols[i + 1] if fn == "TN": begins.append(i) elif fn == "NT": ends.append(i) if exp[-1] in NUM: ends.append(len(exp) - 1) if exp[0] in NUM: begins = [-1] + begins return [(x + 1, y + 1) for x, y in zip(begins, ends)] 

Le sens de la fonction extract_nums est d'obtenir n paires de nombres (a, b), où a est la position du premier caractère, b est la position du dernier + 1.

Par exemple, si nous exécutons le code suivant:

 gen = ProblemGenerator() print(gen.extract_nums("13+256/355+25")) 

Nous verrons:

 [(0, 2), (3, 6), (7, 10), (11, 13)] 

Autrement dit, il s'agit d'un tableau de tuple. (0, 2) signifie qu'il existe un nombre compris entre 0 (inclus) et 2 (non inclus).

Maintenant, nous aimerions créer différents opérateurs, commençons par la multiplication et la somme. Déclarez trois fonctions

 def unmin(*args, acc=2): r = [] for arg in args: f = round(arg, acc) if f > 0: f = str(f) else: f = "(" + str(f) + ")" r.append(f) return r def __c_sum(num): a = round(random.random() * 100, 3) b = num - a a, b = unmin(a, b) return a + " + " + b def __c_mul(num): a = num / (random.random() * 100 + 10) if a == 0.0: b = random.random() else: b = num / a a, b = unmin(a, b) return a + " * " + b 

L'essence de la fonction unmin est non seulement de convertir simplement tous les arguments en chaînes, mais aussi de mettre entre crochets l'un des opérandes s'il est inférieur à zéro. Par exemple, nous avons obtenu les nombres a = 3, b = -4. Si nous écrivons

 a = 3 b = -4 a, b = unmin(a, b) 

Alors a = "3", b = "(- 4)"

Eh bien, les autres fonctions sont claires: __c_sum renvoie une chaîne de la forme «13 + 4» et __c_mul «13 * 4».
Il reste à combiner ces deux pièces et à remplacer chaque numéro de l'expression par l'expression.
Ajoutez le code suivant à ProblemGenerator:

 class ProblemGenerator: ... def __init__(self): self.funcs = [] def add_expander(self, func): self.funcs.append(func) def complexify(self, num): return random.choice(self.funcs)(num) def __rxp__(self, exp): x, y = random.choice(self.extract_nums(exp)) exp = exp[:x] + "(" + self.complexify(float(exp[x:y])) + ")" + exp[y:] return exp def randexpr(self, ans, steps): e = str(ans) for i in range(steps): e = self.__rxp__(e) return e 

complexify prend un certain nombre et renvoie une chaîne - une expression compliquée. Par exemple, si nous écrivons:

 gen = ProblemGenerator() gen.add_expander(__c_sum) print(gen.complexify(13)) 

Nous obtenons:

 31.2 + (-18.2) 

Comment fonctionne __rxp__? Nous sélectionnons au hasard la position d'un nombre dans une expression (par exemple, s'il existe une expression «13 + 35/45», alors disons que nous avons sélectionné (3, 5)) et remplaçons ce nombre par une expression égale à ce nombre. Autrement dit, je voudrais:

"13 + 35/45" - un nombre aléatoire (3, 5)
"13+" + "(12 + 23)" + "/ 45"
"13+ (12 + 23) / 45"

Voilà comment fonctionne __rxp__
Eh bien, randexpr fonctionne tout simplement. Par exemple, si nous avons quatre étapes, l'expression s'ouvrira comme ceci:

 13 (5.62 + 7.38) ((20.63 + (-15.01)) + 7.38) ((20.63 + (-(67.5 + (-52.49)))) + 7.38) ((20.63 + (-((15.16 + 52.34) + (-52.49)))) + 7.38) 

Essayons d'exécuter:

 gen = ProblemGenerator() gen.add_expander(__c_sum) gen.add_expander(__c_mul) exp = gen.randexpr(1, 5) print(exp) 

Résultat:

 ((6.63 + (56.62 + 16.8)) + (-((60.53 + 3.61) + 14.91))) 

LaTeX


Curieusement, le plus simple reste. Nous annoncerons un certain nombre d'opérateurs LaTeX différents:

 def __l_sum(num): a = 100 ** (random.random() * 2) b = num - a a, b = unmin(a, b) return a + " + " + b def __l_div(num): a = num * (random.random() * 100 + 10) if a == 0.0: b = random.random() else: b = a / num a, b = unmin(a, b) return "\\frac{" + a + "}{" + b + "}" def __l_pow(num): if num == 0: return str(random.randint(2, 7)) + "^{-\\infty}" a = random.randint(0, 10) + 3 b = math.log(abs(num), a) a, b = unmin(a, b) return ("-" if num < 0 else "") + a + "^{" + b + "}" def __l_sqrt(num): a = num ** 0.5 a = unmin(a)[0] return "\\sqrt{" + a + "}" def __l_int(num): patterns = [ ("x^{2}", (3 * num) ** (1/3), "dx"), ("y^{3}", (4 * num) ** (1/4), "dy"), ("\sqrt{t}", (1.5 * num) ** (2/3), "dt") ] p, b, f = random.choice(patterns) b = str(round(b, 3)) return "\\int_{0}^{" + b + "} " + p + " " + f def __l_sig(num): a = random.randint(1, 10) b = random.randint(1, 10) + a s = sum([i for i in range(a, b + 1)]) c = num / s a, b, c = unmin(a, b, c) return "\\sum_{i=" + a + "}^{" + b + "} i*" + c 

Ajoutez toutes les fonctions à gen:

 gen = ProblemGenerator() gen.add_expander(__l_sum) #    gen.add_expander(__l_div) #  gen.add_expander(__l_pow) #  gen.add_expander(__l_sqrt) #   gen.add_expander(__l_int) #   gen.add_expander(__l_sig) #   

Enfin, ajoutez la sortie du résultat:

 import matplotlib.pyplot as plt plt.axis("off") latex_expression = gen.randexpr(1, 30) # 30  .    1 plt.text(0.5, 0.5, "$" + latex_expression + "$", horizontalalignment='center', verticalalignment='center', fontsize=20) plt.show() 

C’est tout.

Code entier
 import random from math import log import math import sys sys.setrecursionlimit(1000) class ProblemGenerator: def extract_nums(self, exp): symbols = list(exp) NUM = "1234567890." for i in range(len(symbols)): symbols[i] = "N" if symbols[i] in NUM else "T" begins = [] ends = [] for i in range(len(symbols) - 1): fn = symbols[i] + symbols[i + 1] if fn == "TN": begins.append(i) elif fn == "NT": ends.append(i) if exp[-1] in NUM: ends.append(len(exp) - 1) if exp[0] in NUM: begins = [-1] + begins return [(x + 1, y + 1) for x, y in zip(begins, ends)] def __init__(self): self.funcs = [] def add_expander(self, func): self.funcs.append(func) def complexify(self, num): return random.choice(self.funcs)(num) def __rxp__(self, exp): x, y = random.choice(self.extract_nums(exp)) exp = exp[:x] + "(" + self.complexify(float(exp[x:y])) + ")" + exp[y:] return exp def randexpr(self, ans, steps): e = str(ans) for i in range(steps): e = self.__rxp__(e) return e def unmin(*args, acc=2): r = [] for arg in args: f = round(arg, acc) if f > 0: f = str(f) else: f = "(" + str(f) + ")" r.append(f) return r def __c_sum(num): a = round(random.random() * 100, 3) b = num - a a, b = unmin(a, b) return a + " + " + b def __c_mul(num): a = num / (random.random() * 100 + 10) if a == 0.0: b = random.random() else: b = num / a a, b = unmin(a, b, acc=5) return a + " * " + b def __c_sub(num): a = num + 100 ** (random.random() * 2) b = (a - num) a, b = unmin(a, b) return a + " - " + b def __c_log(num): fr = random.randint(300, 500) a = math.e ** (num / fr) a, fr = unmin(a, fr, acc=5) return "log(" + a + ") * " + fr def __l_sum(num): a = 100 ** (random.random() * 2) b = num - a a, b = unmin(a, b) return a + " + " + b def __l_div(num): a = num * (random.random() * 100 + 10) if a == 0.0: b = random.random() else: b = a / num a, b = unmin(a, b) return "\\frac{" + a + "}{" + b + "}" def __l_pow(num): if num == 0: return str(random.randint(2, 7)) + "^{-\\infty}" a = random.randint(0, 10) + 3 b = math.log(abs(num), a) a, b = unmin(a, b) return ("-" if num < 0 else "") + a + "^{" + b + "}" def __l_sqrt(num): a = num ** 0.5 a = unmin(a)[0] return "\\sqrt{" + a + "}" def __l_int(num): patterns = [ ("x^{2}", (3 * num) ** (1/3), "dx"), ("y^{3}", (4 * num) ** (1/4), "dy"), ("\sqrt{t}", (1.5 * num) ** (2/3), "dt") ] p, b, f = random.choice(patterns) b = str(round(b, 3)) return "\\int_{0}^{" + b + "} " + p + " " + f def __l_sig(num): a = random.randint(1, 10) b = random.randint(1, 10) + a s = sum([i for i in range(a, b + 1)]) c = num / s a, b, c = unmin(a, b, c) return "\\sum_{i=" + a + "}^{" + b + "} i*" + c gen = ProblemGenerator() gen.add_expander(__l_sum) gen.add_expander(__l_div) gen.add_expander(__l_pow) gen.add_expander(__l_sqrt) gen.add_expander(__l_int) gen.add_expander(__l_sig) import matplotlib.pyplot as plt plt.axis("off") latex_expression = gen.randexpr(1, 30) # 30  .    1 plt.text(0.5, 0.5, "$" + latex_expression + "$", horizontalalignment='center', verticalalignment='center', fontsize=15) plt.show() 


Résultat (3 captures d'écran)






Source: https://habr.com/ru/post/fr468457/


All Articles