Category ArchiveMathématiques

Bac 2019 : un exercice inédit pour la filière S

Voici un exercice inédit, tout droit sorti de mon imagination machiavélique. Il est ici question de probabilités continues (avec la loi exponentielle), d’étude de fonction (oui oui !), de loi normale et d’intervalle de fluctuation… Tout ça en un seul exercice ! Avec son corrigé… bien sûr !

Amusez-vous bien !

Lemniscate et parabole

Le but est de créer le GIF suivant:

Code Python

tikz = open("tikz.tex", "w")
text = ''
      
x = -5
while x < 5:
    y = 1/x
    r = (x**2+y**2)**0.5
    if r<10 and abs(y)<10:
        text = text + '\\begin{tikzpicture}[>=latex]\\labase'
        k = -5
        while k <= x:
            p = 1/k
            rr = (k**2+p**2)**0.5
            if rr<10 and abs(p)<10:
                text = text+'\\draw[red] ('+str(k)+','+str(p)+') circle ('+str(rr)+' cm);\n'
            k += 0.1
        text = text + '\\end{tikzpicture}\n'
    x += 0.1

tikz.write(text)
tikz.close()

Ce script génère un fichier tikz.tex dans lequel les dessins sont faits.

Le fichier \(LaTeX\)

\documentclass{article}
\usepackage{tikz}
\usepackage[paperwidth=10cm,paperheight=10cm,margin=0cm]{geometry}
\setlength{\parindent}{0pt}
\newcommand{\labase}{%
\clip (-5,-5) rectangle (5,5);
\draw[->] (-5,0) -- (5,0);
\draw[->] (0,-5) -- (0,5);
\draw plot[domain=-5:-0.1,samples=100] (\x,{1/\x});
\draw plot[domain=0.1:5,samples=100] (\x,{1/\x});
\node[below left] at (0,0) {$O$};
}
\begin{document}
\include{tikz}
\end{document}

En compilant via PdfLaTeX (par exemple), on génère un PDF de 49 pages.

Construction du GIF

J’ai pour habitude d’utiliser GIMP en ouvrant le PDF, puis en inversant l’ordre des calques, puis en sauvegardant en tant qu’animation dans un fichier .gif. Et voilà !

Avec Pythontex

On peut bien entendu créer un tel GIF directement avec pythontex:

% en utilisant Pythontex
\documentclass{article}
\usepackage{tikz}
\usepackage{pythontex}
\usepackage[paperwidth=10cm,paperheight=10cm,margin=0cm]{geometry}
\setlength{\parindent}{0pt}
\newcommand{\labase}{%
\clip (-5,-5) rectangle (5,5);
\draw[->] (-5,0) -- (5,0);
\draw[->] (0,-5) -- (0,5);
\draw plot[domain=-5:-0.1,samples=100] (\x,{1/\x});
\draw plot[domain=0.1:5,samples=100] (\x,{1/\x});
\node[below left] at (0,0) {$O$};
}
\begin{document}
\begin{pycode}
x = -5
while x < 5:
    y = 1/x
    r = (x**2+y**2)**0.5
    if r<10 and abs(y)<10:
        print('\\begin{tikzpicture}[>=latex]\\labase')
        k = -5
        while k <= x:
            p = 1/k
            rr = (k**2+p**2)**0.5
            if rr<10 and abs(p)<10:
                print('\\draw[red] ('+str(k)+','+str(p)+') circle ('+str(rr)+' cm);')
            k += 0.1
        print('\\end{tikzpicture}')
    x += 0.1
\end{pycode}
\end{document}

Baccalauréat mai 2019 série ES Amérique du Nord

Le sujet a été pris sur le site de l’APMEP. J’ai fait un corrigé rapide de l’enseignement obligatoire.

Bien entendu, si vous constatez une anomalie dans ce corrigé, n’hésitez pas à le mentionner en commentaire afin que je la rectifie dans les plus brefs délais.

Bac S 2019 Amérique du Nord, série S : un corrigé

Le sujet se trouve sur le site de l’APMEP ici :

https://www.apmep.fr/IMG/pdf/S_Amerique_Nord_28_05_2019-3.pdf

Je vous propose un corrigé rapide (qui peut aider les élèves) :

Une question impossible à faire correctement…

Dans ce sujet, il y avait une question qu’il était impossible de traiter correctement : dans l’exercice 3, la dernière question (à savoir de trouver le premier entier n tel que \(u_n\leq 10^{-15}\), a dû poser problèmes aux candidats… En effet, dès lors que l’on parle de 15 chiffres après la virgules, il faut se méfier des résultats donnés par les calculatrices car il est rare qu’elles fassent de bons calculs sur des nombres aussi proches de 0.

Pour trouver les valeurs les plus exactes possibles des premiers termes de la suite, je vais m’aider du développement limité de ln(1+x) pour x proche de 0 (puisque c’est ainsi dans le sujet):$$\ln(1+x)=\sum_{n=1}^{+\infty}\frac{(-1)^{n+1}x}{n!}$$Ainsi, comme \(u_{n+1}=u_n-\ln(1+u_n)\), je vais écrire:$$u_{n+1}=\sum_{k=2}^{+\infty}\frac{(-1)^ku_n^k}{k!}$$

Un programme en Python

Je ne vais pas utiliser le module math (car en définitive, il donne des résultats aussi faux que les calculatrices) mais je vais créer moi-même ma fonction “suivant”: je ne vais pas aller jusqu’à l’infini (bien sûr) pour calculer la somme du développement limité, mais je vais aller jusqu’à 100000.

def suivant(x):
    s = 0
    for i in range(100000):
        if i%2 ==0:
            s = s + x**i/i
        else:
            s = s - x**i/i
    return s
        
u,n = 1,0
while n<7:
    n = n+1
    u = suivant(u)
    print(n,':',u)

Ce programme m’affiche alors les 7 termes qui suivent le premier:

1 : 0.30684781941506745
2 : 0.03922982658261975
3 : 0.0007499391358166527
4 : 2.8106384197651534e-07
5 : 3.9498434232245516e-14
6 : 7.800631533994917e-28
7 : 3.042492616457795e-55

En utilisant le module math, on obtient:

from math import log
       
u,n = 1,0
while n<7:
    n = n+1
    u = u-log(u+1)
    print(n,':',u)
1 : 0.3068528194400547
2 : 0.03923100059562018
3 : 0.0007499834542035178
4 : 2.8109705414345546e-07
5 : 3.9573363731490506e-14
6 : 4.9424054835715754e-17
7 : 4.9424054835715754e-17

Vous remarquerez alors que \(u_6\) ne prend pas la même valeur que précédemment…

Et sur les calculatrices, c’est encore pire car les tableurs affichent des nombres en “E-14”:

Tableur généré sur une CASIO

Aie ! Là, ça coince grave ! Les candidat.e.s n’avaient donc pas de chance de trouver la bonne réponse…

Triangle de Pascal construit avec Python et \(\LaTeX\)

Le code Python

def trianglePascal(n):
    T = [[0] * (n+1) for p in range(n+1)]
    for n in range(n+1):
        if n == 0:
            T[n][0] = 1
        else:
            for k in range(n+1):
                if k == 0:
                    T[n][0] = 1
                else:
                    T[n][k] = T[n-1][k-1] + T[n-1][k]
    return T

T = trianglePascal(9)

Ce premier code est intéressant pour voir comment construire une matrice (dont les coefficients sont ceux du triangle de Pascal).

On commence par initialiser notre matrice T en la remplissant de “0”. Puis on la remplit selon la propriété bien connue : \(\binom{n}{k}=\binom{n-1}{k-1}+\binom{n-1}{k}\).

Le code \(\LaTeX\)

On va utiliser PythonTeX :

% sous windows 
% pdflatex --shell-escape -synctex=1 -interaction=nonstopmode %.tex|python C:\Users\trash\AppData\Local\Programs\MiKTeX\scripts\pythontex\pythontex.py %.tex|pdflatex --shell-escape -synctex=1 -interaction=nonstopmode %.tex
% Sous Linux, remplacer "--shell-espace" par "-write18"

\documentclass[10pt,a0paper,landscape]{article}
\usepackage[utf8]{inputenc}
\usepackage[french]{babel}
\usepackage[T1]{fontenc}
\usepackage{lmodern}
\usepackage{diagbox}
\usepackage{pythontex}
\usepackage{nopageno}
\usepackage{colortbl}
\usepackage{tikz}
\usepackage[margin=5mm]{geometry}
\setlength{\parindent}{0pt}
\newcommand{\dashed}{\tikz[baseline=1mm]\draw[gray!50,dashed](0,0)--(0,0.5);}
\begin{document}

\begin{pycode}
n = 50

def trianglePascal(n):
    T = [[0] * (n+1) for p in range(n+1)]
    for n in range(n+1):
        if n == 0:
            T[n][0] = 1
        else:
            for k in range(n+1):
                if k == 0:
                    T[n][0] = 1
                else:
                    T[n][k] = T[n-1][k-1] + T[n-1][k]
    return T


T = trianglePascal(n)

print('\\begin{tabular}{|>{\\columncolor{orange!10}}c|*{',n,'}{c!{\\dashed}}c|}\\rowcolor{orange!10}\\hline\\diagbox[height=8mm]{$n$}{$k$}')
for k in range(n+1):
    print('&',k)
    
for j in range(n+1):
	print('\\\\\\hline ',j)
	for k in range(n+1):
		if k == 0:
			print('&1')
		else:
			if T[j][k] != 0:
				print('&',T[j][k])
			else:
				print('&')

print('\\\\\\hline\\end{tabular}')
\end{pycode} 

\end{document}

Une précision ici : j’ai souhaité séparer chaque colonne par des pointillés. Pour cela, j’ai utilisé une macro TiKZ (pour si peu, ça fait un peu mal quand-même…) car le package arydshln (qui permet de le faire simplement) rentre en conflit avec diagbox… Il fallait donc en sacrifier un! (en fait, ils ne rentrent pas vraiment en conflit mais si on utilise des pointillés dans le tableau, une boîte noire apparaît à la place de l’étiquette “n”). On obtient le document suivant :

Pour les curieux, voici un aperçu des premières lignes et colonnes:

Aperçu du document affichant le triangle de Pascal pour n = 50

Construire le graphe d’une suite avec Python

Dans cet article, nous allons nous intéresser à la construction du graphe d’une suite définie par \(u_{n+1}=f(u_n)\).

Mon objectif est de créer un programme Python qui demande à la personne utilisatrice :

  • la fonction;
  • le premier terme de la suite;
  • le nombre de termes à construire;
  • la fenêtre \( (x_{\min}) \), \( (x_{\max}) \), \( (y_{\min}) \) et \( (y_{\max}) \);
  • le nom sous lequel la figure sera sauvegardée (vide si on ne souhaite pas la sauvegarder).

Les modules

import numpy as np
import matplotlib.pyplot as plt
from sympy import *
x=Symbol('x')
  • Nous aurons besoin du module numpy pour effectuer quelques calculs;
  • ensuite, matplotlib nous servira à effectuer les tracés;
  • le module sympy nous servira à interpréter la saisie de la fonction comme une fonction. À ce titre, on indique que le symbole de la variable est ‘x’.

Saisie de la fonction

def definite_function():
    fonction = input("Entrez l'expression de la fonction : ")
    # convertit la chaîne de caractères en 'fonction'
    f = lambdify(x,fonction,'math') # on utilise le module 'math' ici plutôt que 'numpy' car plus pratique
    fonction_latex = input('Syntaxe LaTeX : ')
    return f,fonction_latex

Ici, on demande de saisir d’une part la fonction (avec une syntaxe “classique”), chaîne de caractères que l’on s’empresse tout de suite de transformer en fonction avec la fonction lambdify du module simpy. Puis, on demande la syntaxe \(\LaTeX\) pour que l’affichage du titre soit plus joli. La fonction retourne un couple constitué de la fonction et de la syntaxe “latexienne” de la fonction.

Les autres saisies

def window():
    xmin = float(input('xmin = '))
    xmax = float(input('xmax = '))
    ymin = float(input('ymin = '))
    ymax = float(input('ymax = '))
    return xmin,xmax,ymin,ymax
    
def definite_first_term():
    u = float(input("Entrez le premier terme : "))
    return u

def definite_nb_terms():
    n = int(input('Nombre de termes à construire : '))
    return n

def definite_name():
    name = input("Entrez le nom de l'image à sauvegarder (appuyez sur [Entrée] si vous ne voulez pas sauvegarder l'image) : ")
    return name

Rien de bien compliqué pour ces quelques fonctions qui permettent de saisir le reste des paramètres.

La fonction de construction du graphe

Nous allons la nommer :

def construct_graph(xmin,xmax,ymin,ymax,f,fonction,u,n,name):

et pour commencer, nous allons nommer la figure:

fig = plt.gcf()

dans l’objectif de la sauvegarder (éventuellement) plus tard.

Tracé de la grille

# tracé du repère et de la grille
    ax = axes([xmin,ymin,xmax,ymax])
    ax.set_xlim(xmin,xmax)
    ax.set_ylim(ymin,ymax)
    ax.xaxis.set_major_locator(MultipleLocator(1.0))
    ax.xaxis.set_minor_locator(MultipleLocator(0.1))
    ax.yaxis.set_major_locator(MultipleLocator(1.0))
    ax.yaxis.set_minor_locator(MultipleLocator(0.1))
    ax.grid(which='minor', axis='x', linewidth=0.25, linestyle='--', color='0.75')
    ax.grid(which='minor', axis='y', linewidth=0.25, linestyle='--', color='0.75')

Tracé de la courbe

# tracé des courbes
    x = np.linspace(xmin, xmax, 201)
    y = [f(x) for x in [xmin+i*(xmax-xmin)/200 for i in range(201)]]
    plt.plot(x,y,color='green')
    plt.plot(x,x,color='red')

On trace ici la courbe représentative de la fonction f ainsi que la droite d’équation \(y=x\).

Construction des termes

for i in range(0,n):
        x = [u,u]
        y = [u,f(u)]
        plt.plot(x,y,linestyle='--',color='blue',linewidth=0.5)
        x = [u,f(u)]
        y = [f(u),f(u)]
        plt.plot(x,y,linestyle='--',color='blue',linewidth=0.5)
        if i != n-1:
            x = [f(u),f(u)]
            y = [f(u),0]
            plt.plot(x,y,linestyle='--',color='orange',linewidth=0.5)
        if i%2 == 0:
            yunder=-0.05
        else:
            yunder = -0.1
        plt.text(u-0.02,yunder,np.around(u,2))
        u = f(u)

On fait une boucle dont le nombre d’itérations est égal au nombre de points que l’on veut. Dans un premier temps, on trace en pointillés la ligne verticale qui va de (u,0) à (u,f(u)), dans un deuxième temps, la ligne horizontale qui va de (u,f(u)) à (f(u),f(u)) puis la ligne verticale qui va de (f(u),f(u)) à (f(u),0) pour avoir le terme suivant sur l’axe des abscisses.

Le titre

#params = {'mathtext.default': 'regular' }
#plt.rcParams.update(params) 
    plt.rc('text', usetex=True)
    plt.rc('font', family='serif')
    title = "Construction des "+str(n)+" premiers termes de la suite définie par\n$u_{n+1}=f(u_n)$ avec $f(x)="+fonction+"$"
    plt.title(title)
    if name != '':
        fig.savefig(name+'.png',dpi=100,bbox_inches='tight')
    plt.show()

On insère maintenant le titre; les deux premières lignes commentées affichent un titre avec une police de caractères par défaut sous Python (ce qui ne me convient pas, mais qui peut plaire à certaines personnes). Les deux lignes suivantes spécifient que l’on souhaite un affichage \(\LaTeX\).

Fonction principale

if __name__ == '__main__':
    f,fonction = definite_function()
    u = definite_first_term()
    xmin,xmax,ymin,ymax = window()
    n = definite_nb_terms()
    name = definite_name()
    construct_graph(xmin,xmax,ymin,ymax,f,fonction,u,n,name)

En exécutant ce programme avec les paramètres suivants:

Saisie

on obtient l’image suivante:

Résultat

Retrouvez le programme complet sur cette page.

Pourquoi le volume d’une boule est égal à \(\frac{4}{3}\pi r^3\) ?

J’ai expliqué dans l’article précédent d’où venait la formule qui permet de calculer l’aire d’un disque. Il est donc naturel de passer à la dimension supérieure et de parler de boules…

Nous avons vu dans ce dernier article que l’outil d’intégration pouvait nous permettre d’effectuer une somme continue. Nous allons continuer d’utiliser cet outil en considérant, dans un repère orthonormé de l’espace, une sphère centrée en l’origine:

Boule de rayon r centrée en l’origine d’un repère orthonormé de l’espace

puis en considérant un disque parallèle au plan horizontal de hauteur h:

Disque coupant une boule à une hauteur de h.

L’idée est d’ajouter tous ces disques pour h variant de 0 à r ; ainsi, on aura la demi-boule supérieure. Le volume de la demi-boule supérieure est donc égal à:$$\mathcal{V}_{1/2}=\int_0^r \mathcal{A}(h)\text{d}h$$où \(\mathcal{A}(h)\) est l’aire du disque de hauteur h.

Le rayon p du disque de hauteur h est, d’après le théorème de Pythagore:$$p=\sqrt{r^2-h^2}.$$Ainsi,$$\mathcal{A}(h)=\pi \times p^2=\pi(r^2-h^2)$$et donc:$$\begin{align}\mathcal{V}_{1/2}&=\pi\int_0^r\left(r^2-h^2\right)\text{d}h\\&=\pi\left[r^2h-\frac{h^3}{3} \right]_0^r\\&=\pi\left(r^3-\frac{r^3}{3}\right)\\&=\frac{2}{3}\pi r^3.\end{align}$$

Ayant le volume de la demi-boule, il ne reste plus qu’à le doubler pour obtenir celui de la boule; on obtient bien alors: $$\mathcal{V}_{\text{boule}}=\frac{4}{3}\pi r^3.$$

Pourquoi l’aire d’un disque est égale à \(\pi r^2\) ?

Considérons un disque de rayon r. Nous allons rapporté le plan à un repère orthonormé d’origine O, et nous allons centrer notre disque en O.

Disque de centre O et de rayon r

Afin de déterminer l’aire du disque, considérons uniquement son enveloppe : le cercle de centre O et de rayon r :

Cercle de centre O et de rayon r

Maintenant, considérons un point M sur ce cercle d’abscisse x > 0 et d’ordonnée y > 0. Alors, d’après le théorème de Pythagore,$$x^2+y^2=r^2.$$

Le point M est sur le cercle

Ainsi,$$y=\sqrt{r^2-x^2}.$$On peut donc considérer le quart de cercle supérieur droit comme la représentation graphique de la fonction $f$ définie par:$$f(x)=\sqrt{r^2-x^2}$$sur [0;r].

Pour connaître l’aire du domaine délimité par l’axe des abscisses et la courbe représentative de f sur [0;r], il existe un outil mathématique : l’intégration. L’aire cherchée est:$$I=\int_0^rf(x)\text{d}x=\int_0^r\sqrt{r^2-x^2}\text{d}x.$$

Pour calculer une intégrale, il faut connaître une primitive de la fonction, mais en terminale, nous ne connaissons pas de primitive à la fonction f. On va donc utiliser une méthode pour arriver à nos fins (qui n’est pas au programme de Terminale, rassurez-vous).

Nous allons d’abord écrire f(x) autrement:$$\sqrt{r^2-x^2}=r\sqrt{1-\left(\frac{x}{r}\right)^2}.$$On peut ainsi écrire:$$I=r\int_0^r\sqrt{1-
\left(\frac{x}{r}\right)^2}\text{d}x.$$

Considérons alors une variable u telle que:$$u=\frac{x}{r}.$$Si x varie de 0 à r alors u varie de 0 à 1. De plus, si on considère u comme une fonction de x alors sa dérivée par rapport à x est:$$u'(x)=\frac{\text{d}u}{\text{d}x}=\frac{1}{r}.$$On peut alors écrire:$$\text{d}x=r\text {d}u.$$Ainsi, si nous voulons exprimer l’intégrale I en fonction de u, on écrit:$$I=r\int_0^1\sqrt{1-u^2}r\text{d}u=r^2\int_0^1\sqrt{1-u^2}\text{d}u .$$

Maintenant, la variable d’intégration est u, et varie de 0 à 1. On peut donc dire que c’est un sinus (par exemple). Posons alors:$$u=\sin(t).$$Alors,$$\text{d}u=\cos(t)\text{d}t.$$De plus, si u varie de 0 à 1 alors t varie de 0 à \(\frac{\pi}{2}\), d’où:$$I=r^2\int_0^{\frac{\pi}{2}}\sqrt{1-\sin^2(t)}\cos(t)\text{d}t=r^2\int_0^{\frac{\pi}{2}}\cos^2(t)\text{d}t.$$En effet, \(\cos^2(t)+\sin^2(t)=1\) donc \(1-\sin^2(t)=\cos^2(t)\); et comme t varie entre 0 et \(\frac{\pi}{2}\), son cosinus est positif donc \(\sqrt{\cos^2(t)})\cos(t)\) dans notre intégrale.

Il ne reste plus qu’à trouver une primitive de \(\cos^2(t)\). Pour cela, il faut se souvenir que:$$\cos(2t)=2\cos^2(t)-1$$et donc que:$$\cos^2(t)=\frac{1}{2}(\cos(2t)+1).$$Ainsi,$$\begin{align}I&=r^2\int_0^{\frac{\pi}{2}}\frac{1}{2}(\cos(2t)+1)\text{d}t\\&=\frac{r^2}{2}\int_0^{\frac{\pi}{2}}(\cos(2t)+1)\text{d}t\\&=\frac{r^2}{2}\left[ \frac{1}{2}\sin(2t)+t\right]_0^{\pi/2}\\&=\frac{r^2}{2}\times\frac{\pi}{2}\\&=\frac{\pi r^2}{4}. \end{align}$$

L’aire du disque étant égale au quadruple de l’aire trouvée, on obtient finalement que l’aire du disque est égale à :$$\mathcal{A}_{\mathcal{D}}=4I=\pi r^2.$$

Une précision sur l’outil d’intégration

Pour un réel x quelconque de l’intervalle [0;r], le segment tracé a une longueur égale à f(x).

Trouver l’aire du quart de cercle revient à “additionner” la longueur de tous les segments obtenus en faisant varier x de 0 à r. Mais x est un nombre réel donc il existe une infinité de valeurs. On ne peut donc pas additionner “une à une” toutes ces longueurs. On dit que la somme n’est pas discrète (une somme discrète est une somme où l’on peut compter un à un tous ses termes, même s’il y en a une infinité, comme 1+2+3+…). La somme est qualifiée de continue. Et donc l’intégrale représente une somme continue.

Représentation schématique d’une somme continue des longueurs d segments sur [0 ; r]

Sur le schéma ci-dessus, il faut imaginer que l’on rapproche de plus en plus les segments jusqu’à ce qu’ils soient tous “collés”. Ils couvrent alors toute la surface. Ainsi, la somme de leurs longueurs sera égale à l’aire.

Avec cela, nous pouvons continuer et nous demander pourquoi le volume d’une boule est égal à \(\frac{4}{3}\pi r^3\) : c’est l’objet de l’article suivant.

Section d’un cube par un plan défini par 3 points sur différentes faces

Nous allons voir dans cet article comment trouver la section d’un cube par un plan quand on connaît 3 points sur 3 arêtes de ce cube, chacun des points n’étant pas sur une face où se trouve l’un des deux autres.

On souhaite trouver la section du cube par le plan (IJK)

Etape 1 : on projette orthogonalement un point sur l’arête parallèle à celle où il se trouve et contenue dans une face où se trouve l’un des deux autres points.

Ici, on va projeter le point J sur [BF] car [BF] est contenue dans une face où se trouve K. On obtient un point que l’on nomme \(P_1\).

Projeté orthogonal d’un point sur une arête opposée

Etape 2 : on trace un triangle passant par le sommet opposé à la face contenant le point choisi et son projeté.

Ici, on trace \(AP_1\) et \(AJ\). Elles se coupent en un point \(P_2\).

On trace un triangle

Etape 4 : on trouve enfin un point qui appartient à la section cherchée.

Les points K et \(P_2\) appartiennent à la même face (ABFE) donc la droite \((KP_2)\) coupe l’arête [AE] (car elles ne sont pas parallèles). On obtient alors le point \(P_3\).

Un point appartenant à la section

On a ainsi l’intersection des plans (IJK) et (ADHE):

Intersection d’une face du cube avec le plan (IJK)

ainsi que celle des plans (IJK) et (ABFE):

Intersection d’une autre face du cube avec (IJK)

Etape 5 : on trace des parallèles

On trace maintenant la droite parallèle à \((KP_3)\) passant par J : elle coupe l’arête [DC] en \(P_4\):

On trace une parallèle pour trouver un autre côté de la section du cube par le plan (IJK)

On trace ensuite \([IP_4]\) qui est un autre côté de la section cherchée:

Puis la parallèle à \((IP_3)\) passant par J, qui coupe [GF] en \(P_5\):

On trace une deuxième parallèle

On trace enfin \([KP_5]\) qui ferme la section cherchée:

La section est désormais fermée

La section du cube par le plan (IJK) est le polygone \(KP_5JP_4IP_3\):

La section du cube par le plan est obtenue

Créer un fichier LaTeX avec Python

Dans un article précédent, je vous expliquais comment, dans un fichier \(\LaTeX\), on pouvait se servir de Python grâce à l’extension Pythontex.

Maintenant, je vais vous expliquer comment faire l’inverse, à savoir comment créer et compiler un fichier \(\LaTeX\) avec un programme Python.

L’objectif va être le même que dans l’article précédent (cas d’école) : créer 20 développements (avec double distributivité) aléatoires.

Créer un fichier TeX et le compiler sous Python

Importation des modules nécessaires

import os.path
import random
from sympy import Symbol
from sympy import expand
x=Symbol('x')

J’importe le module os car il va me servir à exécuter des commandes en lignes.

Ensuite, j’importe le module random car il est nécessaire dans notre contexte (dès lors qu’il y a choix aléatoire…).

J’utilise ensuite sympy pour les manipulations algébriques (c’est spécifique ici à ce que je souhaite faire). Je définis alors “x” comme le symbole désignant l’inconnue.

Construction du fichier

Le contenu du fichier va être défini par une succession de texte.

Définir le préambule

def preambule(*packages):
	p = ""
	for i in packages:
		p = p+"\\usepackage{"+i+"}\n"
	return p

Cette fonction a pour but d’appeler tous les packages nécessaires.

start = "\\documentclass[12pt,a4paper,french]{article}\n\\usepackage[utf8]{inputenc}\n"
start = start+preambule('amsmath','lmodern','babel')
start = start+"\\begin{document}\n\\begin{align*}\n"

end = "\\end{align*}\n\\end{document}"

On commence par définir la classe utilisée (avec les options souhaitées) ainsi que l’encodage. Puis, on appelle tous les packages souhaités. Enfin, on commence le document.

Génération des égalités

body = ""

for n in range(21):
    a = random.choice([1, -1]) * random.randint(2, 9)
    b = random.choice([1, -1]) * random.randint(2, 9)
    c = random.choice([1, -1]) * random.randint(2, 9)
    d = random.choice([1, -1]) * random.randint(2, 9)
    e = (a*x+b)*(c*x+d)
    eresultchain = str(expand(e)) # on convertit le résultat en chaîne de caractères
    eresultchain = eresultchain.replace('**','^') # on met au format TeX les exposants
    eresultchain = eresultchain.replace('*','') # on élimine les symboles '*'
    echain = str(e)
    echain = echain.replace('*','')

    body = body+echain+" & = "+eresultchain+"\\\\\n"

Il est ici nécessaire d’anticiper sur la syntaxe \(\LaTeX\) pour remplacer certains caractères…

Ecriture du fichier

container = start+body+end

file = "monfichier.tex"
if os.path.exists(file):
	os.remove(file)

fichier = open("monfichier.tex","x") # "x" pour la création et l'écriture
fichier.write(container)
fichier.close()

Compilation

Une fois le fichier créé, il est pratique de le compiler directement puis de l’afficher.

instructions = "pdflatex "+file#"
os.system(instructions)

readpdf = "START "+file[:-4]+".pdf"
os.system(readpdf)

Et voilà ! Une feuille d’exercices créée en à peine 2 secondes…

Le code complet

Les abonné.e.s de ce site trouveront le code complet sur cette page.