Skip to content
This repository was archived by the owner on Jun 26, 2018. It is now read-only.

Nouvelle classe d'exercice ; trois nouveaux exercices#20

Merged
paternal merged 29 commits into
developfrom
jinja2
Jun 16, 2018
Merged

Nouvelle classe d'exercice ; trois nouveaux exercices#20
paternal merged 29 commits into
developfrom
jinja2

Conversation

@paternal

@paternal paternal commented May 24, 2018

Copy link
Copy Markdown
Member

Nouvel exercice. L'intérêt réside surtout dans la nouvelle manière de générer l'exercice : avec un template jinja2.

Jusqu'à présent, le code LaTeX des exercices est construit de cette manière :

def tex_answer(self):
exo = [r'\exercice*']
exo.append(ur'\begin{enumerate}')
# Question 0
exo.append(ur" \item Selon l'énoncé, le premier terme de ${notation}$ est $u_{indice0}={terme0}$. Puisque chaque terme (sauf le premier) est égal {suivant}, on a :".format(**self.questions[0].latex_params))
termes = dict([(self.questions[0].indice0, self.questions[0].terme0)])
calcul_termes = []
for indice in xrange(self.questions[0].indice0, max(self.rang[0] + self.questions[0].indice0 - 1, self.rang[1], self.rang[2])):
calcul = ur"$u_{indice}={fonction}".format(
indice=indice+1,
fonction=self.questions[0].fonction.expression("u_{}".format(indice)),
)
for etape in self.questions[0].fonction.calcul(termes[indice]):
calcul += " =" + etape
calcul += "$"
termes[indice+1] = self.questions[0].fonction.resultat(termes[indice])
calcul_termes.append(calcul)
exo.append(" ; ".join(calcul_termes) + ".")
exo.append(ur'\begin{enumerate}')
exo.append(ur' \item Calcul du {} terme :'.format(FRANCAIS_ORDINAL[self.rang[0]]))
enumeration = []
for indice in range(0, self.rang[0]):
enumeration.append(u"le {ordinal} terme est $u_{indice}$".format(ordinal=FRANCAIS_ORDINAL[indice+1], indice=self.questions[0].indice0+indice))
exo.append(" ; ".join(enumeration) + ".")
exo.append(ur"Le terme demandé est donc : $u_{}={}$.".format(self.rang[0] + self.questions[0].indice0 - 1, termes[self.rang[0] + self.questions[0].indice0 - 1].latex()))
exo.append(ur'\item Le terme de rang {indice} est : $u_{indice}={valeur}$.'.format(indice=self.rang[1], valeur=termes[self.rang[1]].latex()))
exo.append(ur'\item Nous avons calculé que : $u_{indice}={valeur}$.'.format(indice=self.rang[2], valeur=termes[self.rang[2]].latex()))
exo.append(ur'\end{enumerate}')
# Question 1
exo.append(ur' \item La suite ${notation}$ est définie pour $n\geq{indice0}$ par : $u_n={fonction}$.'.format(**self.questions[1].latex_params))
exo.append(ur"Elle est donc définie par son terme général : pour calculer un terme de rang $n$, on peut calculer directement l'image de $n$ par la suite.")
exo.append(ur'\begin{enumerate}')
exo.append(ur' \item Calcul du {} terme :'.format(FRANCAIS_ORDINAL[self.rang[0]]))
enumeration = []
for indice in range(0, self.rang[0]):
enumeration.append(u"le {ordinal} terme est $u_{indice}$".format(ordinal=FRANCAIS_ORDINAL[indice+1], indice=self.questions[1].indice0+indice))
exo.append(" ; ".join(enumeration) + ".")
exo.append(ur"Le terme demandé est donc : $u_{}=".format(self.rang[0] + self.questions[1].indice0 - 1))
calcul = []
for etape in self.questions[1].fonction.calcul(Entier(self.rang[0] + self.questions[1].indice0 - 1)):
calcul.append(etape)
exo.append(u" = ".join(calcul) + ur"$.")
exo.append(ur"La solution est $u_{{ {} }}={}$.".format(self.rang[0] + self.questions[1].indice0 - 1, self.questions[1].fonction.resultat(Entier(self.rang[0] + self.questions[1].indice0 - 1)).latex()))
exo.append(ur"\item Le terme de rang {rang} est $u_{{ {rang} }}$.".format(rang=self.rang[1]))
if self.rang[0] + self.questions[1].indice0 - 1 == self.rang[1]:
exo.append(ur"Ce terme a déjà été calculé, et $u_{{ {} }}={}$.".format(self.rang[1], self.questions[1].fonction.resultat(Entier(self.rang[1])).latex()))
else:
calcul = []
for etape in self.questions[1].fonction.calcul(Entier(self.rang[1])):
calcul.append(etape)
exo.append(ur"Le terme demandé est donc : $u_{{ {} }}=".format(self.rang[1]) + " = ".join(calcul) + ur"$.")
exo.append(ur"La solution est donc : $u_{{ {} }}={}$.".format(self.rang[1], self.questions[1].fonction.resultat(Entier(self.rang[1])).latex()))
exo.append(ur"\item")
if self.rang[0] + self.questions[1].indice0 - 1 == self.rang[2]:
exo.append(ur"Ce terme a déjà été calculé, et $u_{{ {} }}={}$.".format(self.rang[2], self.questions[1].fonction.resultat(Entier(self.rang[2])).latex()))
else:
calcul = []
for etape in self.questions[1].fonction.calcul(Entier(self.rang[2])):
calcul.append(etape)
exo.append(ur"On a : $u_{{ {} }}=".format(self.rang[2]) + " = ".join(calcul) + ur"$.")
exo.append(ur"La solution est donc : $u_{{ {} }}={}$.".format(self.rang[2], self.questions[1].fonction.resultat(Entier(self.rang[2])).latex()))
exo.append(ur'\end{enumerate}')
# Question 2
exo.append(textwrap.dedent(ur"""
\item La suite ${notation}$ est définie par récurrence, pour $n\geq{indice0}$, par :
\[\left\{{\begin{{array}}{{l}}
u_{indice0}={terme0}\\
\text{{Pour tout $n\geq{indice0}$ : }} u_{{n+1}}={fonction}.
\end{{array}}\right.\]
""").format(**self.questions[2].latex_params))
termes = dict([(self.questions[2].indice0, self.questions[2].terme0)])
calcul_termes = []
for indice in xrange(self.questions[2].indice0, max(self.rang[0] + self.questions[2].indice0 - 1, self.rang[1], self.rang[2])):
calcul = ur"u_{indice} &= {fonction}".format(
indice=indice+1,
fonction=self.questions[2].fonction.expression("u_{}".format(indice)),
)
for etape in self.questions[2].fonction.calcul(termes[indice]):
calcul += " =" + etape
termes[indice+1] = self.questions[2].fonction.resultat(termes[indice])
calcul_termes.append(calcul)
exo.append(ur"\begin{align*}")
exo.append(ur" \\".join(calcul_termes))
exo.append(ur"\end{align*}")
exo.append(ur'\begin{enumerate}')
exo.append(ur' \item Calcul du {} terme :'.format(FRANCAIS_ORDINAL[self.rang[0]]))
enumeration = []
for indice in range(0, self.rang[0]):
enumeration.append(u"le {ordinal} terme est $u_{indice}$".format(ordinal=FRANCAIS_ORDINAL[indice+1], indice=self.questions[2].indice0+indice))
exo.append(" ; ".join(enumeration) + ".")
exo.append(ur"Le terme demandé est donc : $u_{}={}$.".format(self.rang[0] + self.questions[2].indice0 - 1, termes[self.rang[0] + self.questions[2].indice0 - 1].latex()))
exo.append(ur'\item Le terme de rang {indice} est : $u_{indice}={valeur}$.'.format(indice=self.rang[1], valeur=termes[self.rang[1]].latex()))
exo.append(ur'\item Nous avons calculé que : $u_{indice}={valeur}$.'.format(indice=self.rang[2], valeur=termes[self.rang[2]].latex()))
exo.append(ur'\end{enumerate}')
exo.append(ur'\end{enumerate}')
return exo

C'est parfaitement illisible. Avec cette nouvelle méthode, il y a deux parties : la classe exercice en elle même :

class EtatStableSysteme2(Jinja2Exercice):
description = u"Recherche d'état stable (avec un système)"
level = u"0.TermES"
def __init__(self):
super(EtatStableSysteme2, self).__init__()
ab = random.choice(CANDIDATS)
random.shuffle(ab)
self.context = {
"a": ab[0],
"b": ab[1],
}
@property
def environment(self):
environment = super(EtatStableSysteme2, self).environment
environment.filters.update({
'decimal': decimaux,
})
return environment

Et un template :

https://github.com/Pyromaths/pyromaths/blob/b39a7d7fe450c7253c09a199a832ba78516a7119/data/ex/templates/EtatStableSysteme2-answer.tex

Il est beaucoup plus lisible : c'est du code LaTeX ; le principal à savoir est que les expressions entre double parenthèse (( comme ça )) sont évaluées. Ainsi, dans (( (1-b) | decimal )), le nombre 1-b est d'abord calculé, puis on y applique la fonction decimal, et le résultat de cette fonction est affiché.

C'est beaucoup, beaucoup, beaucoup plus confortable d'écrire des exercices ainsi.

Ce qu'il reste à faire :

  • Documenter tout ça, pour les nouveaux venus.
  • Accepter (ou non) l'import d'une bibliothèque externe jinja2 (c'est une bibliothèque très utilisée, écrite et maintenue par une équipe très active dans le monde de python, donc elle est robuste, et il y a très très peu de chance qu'elle cesse d'être maintenue un jour).
  • Vérifier que l'intégration de jinja2 à la liste des dépendances fonctionne (@JeromeO , c'est pour tout : ça se passe dans b39a7d7#diff-2eeaed663bd0d25b7e608891384b7298).
  • Prévoir la traduction des exercices (pour le moment, ils ne peuvent pas être traduits).
  • Plus les remarques, questions, améliorations que vous pourrez apporter. ☺️

Bonne lecture ! Et au dodo… 🌜💤

@JeromeO

JeromeO commented May 25, 2018

Copy link
Copy Markdown
Contributor

Bonjour Louis. Je suis absolument d'accord avec toi sur le constat et ton exemple semble effectivement très prometteur.
Je testerai l'intégration de Jinja2 au paquet mais il n'y a pas de raison que ça ne fonctionne pas... Enfin j'espère.
La traduction est un travail titanesque qui n'a peut-être qu'un intérêt limité. Je pense qu'il est plus motivant de travailler sur de nouveaux exercices.
Je n'ai pas le temps de regarder ça de près ce week-end, mais je m'y attellerai dès que possible. Merci beaucoup pour cette trouvaille.

@paternal

Copy link
Copy Markdown
Member Author

Du coup, je te laisse valider ça dés que tu as vérifié le setup.py. Il faut aussi ajouter jinja2 à la liste des dépendances du paquet .deb (il est paquagé : c'était aussi un de mes critère pour l'utiliser).

Pour la documentation, j'ai marqué ça dans ma todo-liste perso, mais ça n'est pas bloquant.
Pour la traduction, ça n'est pas bloquant non plus.

@paternal

paternal commented May 29, 2018

Copy link
Copy Markdown
Member Author

La documentation de la création d'un nouvel exercice est terminée (le premier jet, du moins ; il faudrait que je me relise). Bonne lecture !

@paternal

paternal commented Jun 3, 2018

Copy link
Copy Markdown
Member Author

Je suis en train d'écrire un exercice bilan sur les trinômes en seconde, en utilisant jinja2 comme proposé ici. Je me rends compte qu'il y a encore de bonnes pistes d'améliorations à tout ça, donc ce qui est proposé ici n'est pas gravé dans le marbre, mais le cœur sera conservé : cette pull-request peut être acceptée dés maintenant.

Louis added 3 commits June 12, 2018 22:30
La fonction pyromaths.outils.jinja2.facteur a été enrichie.
La documentation a été modifiée en conséquence.
@paternal paternal changed the title Nouvel exercice : Recherche d'état stable en terminale ES (spé) Nouvelle classe d'exercice ; trois nouveaux exercices Jun 12, 2018
@paternal

paternal commented Jun 12, 2018

Copy link
Copy Markdown
Member Author

Les exercices proposés :

Bonne lecture !

@paternal

Copy link
Copy Markdown
Member Author

@JeromeO Merci pour ta relecture. J'ai corrigé quelques détails et mis à jour les tests. Ça me convient.

@paternal paternal merged commit 6c7ce95 into develop Jun 16, 2018
@paternal

Copy link
Copy Markdown
Member Author

J'ai l'impression que tu es d'accord dans les grandes lignes. Si tu as encore des modifications à apporter, il sera toujours temps de les faire dans la branche develop

@JeromeO

JeromeO commented Jun 17, 2018

Copy link
Copy Markdown
Contributor

Absolument. À ce propos, est-ce qu'on intègre cette branche dans develop dès maintenant ? On ne reviendra pas en arrière, tu as trop bossé.

@kiarn

kiarn commented Jun 17, 2018

Copy link
Copy Markdown
Member

D'autant plus que le système via template jinja est très bien.
Maintenant je me demande si il ne faudrait pas déjà structurer l'arborescence du dossier templates.

@JeromeO

JeromeO commented Jun 17, 2018

Copy link
Copy Markdown
Contributor

Je confirme que c'est super. Relire le code tex d'un exercice devient relativement simple. Concernant la structure, c'est clair qu'il y a quelque chose à faire. Ça va devenir vite illisible.

@paternal

Copy link
Copy Markdown
Member Author

Je confirme que c'est super. Relire le code tex d'un exercice devient relativement simple.

🎉 Génial ! C'était le but recherché… 🎉

Concernant la structure, c'est clair qu'il y a quelque chose à faire. Ça va devenir vite illisible.

Je ne suis pas sûr que ça devienne si illisible que ça, et je ne vois pas vraiment comment organiser cela. Il a été évoqué ailleurs que le classement des exercices par niveau n'était plus pertinent (dans la mesure où avec la réforme des collèges, la répartition des exercices dans chacun des quatre niveaux n'est plus stricte ; dans la mesure où au lycée, un exercice peut appartenir à plusieurs séries différentes…). Du coup, quelle organisation proposez-vous ? J'en vois deux possibles :

  • à chaque exercice son répertoire (MesuresAngles/answer.tex et MesuresAngles/statement.tex plutôt que MesuresAngles-answer.tex et MesuresAngles-statement.tex), mais on ne gagne pas grand'chose ;
  • un répertoire par module Python. Par exemple, l'exercice InterpolationMatrices est dans le module lycee/matrices.py, donc les templates seraient lycee/matrices/InterpolationMatrices-statement.tex, ou matrices/InterpolationMatrices-statement.tex, mais j'ai peur que ce soit moins clair et moins pratique que la solution actuelle.

Actuellement, les vignettes sont organisées de la même manière : toutes dans le même répertoire. Trouvez-vous vraiment que ça pose problème ?

Ces répertoires ne sont pas manipulés par l'utilisateur final : ils sont manipulés par l'ordinateur (la plupart du temps) et par le développeur (quelques fois). La situation actuelle ne me semble donc pas génante.

@paternal

Copy link
Copy Markdown
Member Author

La nuit porte conseil. Autre proposition : inverser l'ordre des répertoires.

Actuellement, le répertoire data/ex contient trois répertoires : un pour les vignettes, un pour les templates, un pour les tests. Au sein de chacun des répertoires se trouvent tous les fichiers de tous les exercices. Pour l'exercice InterpolationMatrices, cela donne :

$ tree data/ex
data/ex
 ├── img
 │   └── InterpolationMatrices.png
 ├── templates
 │   ├── InterpolationMatrices-answer.tex
 │   └── InterpolationMatrices-statement.tex
 └── tests
     ├── InterpolationMatrices.0.answer
     └── InterpolationMatrices.0.statement

On peut aussi inverser cela : le répertoire data/ex contientrait un répertoire par exercice, qui contiendrait les fichiers susmentionnés. Cela donnerait :

$ tree data/ex
 ex
 └── InterpolationMatrices
     ├── test.0.answer
     ├── test.0.statement
     ├── answer.tex
     ├── statement.tex
     └── thumbnail.png

-- Louis

juanma1980 pushed a commit to lliurex/pyromaths that referenced this pull request Oct 17, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants