Théorèmes et démonstrations (amsthm)

Le carré évidé qui clôt une démonstration n’est un caractère d’aucune fonte. Le paquet amsthm de LaTeX le dessine sur place à partir de deux filets verticaux et deux filets horizontaux (\openbox dans amsthm.sty ; mesuré à 7.77786pt de large sur 6.75003pt de haut, soit 0.77778em × 0.675em dans un document en 10pt). Les environnements de théorème reposent sur la même idée. LaTeX ne livre pas un « théorème » tout fait : il livre \newtheorem, un mécanisme de déclaration, et laisse décider ce qui mérite le nom de théorème et comment il sera numéroté. Cette page suit ce que \newtheorem engendre réellement, pourquoi ses deux arguments optionnels ne se combinent pas, ce que \theoremstyle change vraiment, et le problème \qedhere qui fait tomber le symbole de fin sur la mauvaise ligne — chaque fois avec le résultat de compilations réelles.

Ce que \newtheorem engendre : un environnement et un compteur

\newtheorem{theorem}{Theorem} crée un environnement et un compteur pour le numéroter. Le journal affiche une ligne comme \c@theorem=\count196 : le compteur est bel et bien alloué. Le premier argument est le nom de l’environnement que l’on écrit dans \begin{…}, le second le mot imprimé en gras dans l’en-tête. L’essentiel est que ce sont deux choses distinctes : on peut garder le nom d’environnement theorem tel quel et ne changer que le mot imprimé en Satz, Théorème ou autre.

latex
\usepackage{amsthm}
\newtheorem{theorem}{Theorem}   % declares the environment AND allocates a counter

Après cette déclaration, chaque emploi de l’environnement theorem reçoit un en-tête en gras et un numéro courant — Theorem 1, Theorem 2 — et son texte est composé en italique dans le style par défaut. Le numéro réside dans un compteur LaTeX : insérer un théorème au milieu renumérote automatiquement les suivants. C’est exactement la propriété recherchée quand on cherche comment numéroter des théorèmes : tant qu’aucun numéro n’est tapé à la main, la numérotation ne peut pas se désynchroniser.

latex
\begin{theorem}
  There are infinitely many primes.
\end{theorem}

\begin{theorem}[Pythagoras]
  In a right triangle, $a^2 + b^2 = c^2$.
\end{theorem}

Comme dans le second exemple, un nom passé entre crochets juste après \begin{theorem} s’ajoute entre parenthèses après le numéro : « Theorem 2 (Pythagoras). ». C’est indépendant de la présence d’un numéro et cela fonctionne aussi bien avec les environnements non numérotés créés plus bas par \newtheorem*. Notons également que \newtheorem fait partie du LaTeX2e standard. Le \newtheorem nu suffit à créer des environnements numérotés, mais \theoremstyle, \newtheorem*, l’environnement proof et \qedhere — tout ce qui suit — sont des extensions de amsthm et n’existent qu’après \usepackage{amsthm}.

Les deux crochets : partager et subordonner ne se combinent pas

\newtheorem n’accepte qu’un seul crochet, et sa position en détermine le sens. Juste après le nom de l’environnement, il signifie « partager un compteur existant » ; après le second argument, « subordonner le compteur à ce parent et le réinitialiser avec lui ». Numéroter séparément théorèmes et lemmes disperse les mêmes numéros — « Theorem 1, Lemma 1, Theorem 2, Lemma 2… » —, aussi la plupart des textes mathématiques retiennent la première option et suivent une seule suite : « Theorem 1, Lemma 2, Theorem 3… ».

latex
\newtheorem{theorem}{Theorem}
\newtheorem{lemma}[theorem]{Lemma}        % bracket BEFORE: share theorem's counter
\newtheorem{definition}{Definition}[section]  % bracket AFTER: reset per section, "2.1"

Le crochet placé après peut aussi contenir un environnement de théorème existant plutôt que section. Avec \newtheorem{corollary}{Corollary}[theorem], le numéro du corollaire se réinitialise à chaque théorème, si bien que « Corollary 3.1 » se lit « le premier corollaire attaché à Theorem 3 ».

DéclarationEffet
\newtheorem{theorem}{Theorem}Numérote 1, 2, 3, … sur son propre compteur
\newtheorem{lemma}[theorem]{Lemma}Partage le compteur de theorem : lemmes et théorèmes forment une seule suite
\newtheorem{theorem}{Theorem}[section]Redémarre à chaque \section et s’affiche avec le numéro de section, « 2.1 »
\newtheorem{corollary}{Corollary}[theorem]Se réinitialise à chaque theorem et hérite de son numéro, affiché « 3.1 »
\newtheorem*{remark}{Remark}N’alloue aucun compteur et n’imprime que le mot d’en-tête, sans numéro (nécessite amsthm)

Que se passe-t-il alors si l’on écrit les deux à la fois ? Soumettre \newtheorem{lemma}[theorem]{Lemma}[section] à TeX Live 2024 produit bien une erreur — mais elle ne dit rien de \newtheorem. Comme \newtheorem ne lit jamais de second crochet, le [section] reste dans le préambule sous forme de texte ordinaire, et LaTeX en conclut que le corps du document a commencé. Voici ce que l’on obtient.

log
! LaTeX Error: Missing \begin{document}.

l.4 \newtheorem{lemma}[theorem]{Lemma}[
                                       section]

Partager et subordonner sont donc mutuellement exclusifs. Quand on veut les deux — « les lemmes partagent la numérotation des théorèmes, et celle-ci repart à chaque section » —, il faut mettre le [section] sur le parent seulement. Déclarez \newtheorem{theorem}{Theorem}[section] : un lemme qui le partage via \newtheorem{lemma}[theorem]{Lemma} hérite automatiquement de la numérotation par section. Comme il n’y a qu’un compteur, les deux exigences se concilient sans contradiction.

Quand surgit Command \theorem already defined.

Cette erreur signifie que le même nom d’environnement a été déclaré deux fois. \newtheorem crée un environnement neuf et refuse donc d’écraser un nom déjà pris. Voici ce que produisent deux lignes \newtheorem{theorem}{Theorem} dans un même préambule.

log
! LaTeX Error: Command \theorem already defined.
               Or name \end... illegal, see p.192 of the manual.

En pratique, on tombe rarement là-dessus pour avoir tapé la ligne deux fois. Le plus souvent, la classe de document ou un paquet déjà chargé a déclaré theorem à votre place. Les modèles de conférence, amsart ou elsarticle préparent parfois les environnements de théorème à l’avance. Trois issues : supprimer votre ligne, la renommer en mytheorem par exemple, ou conserver la déclaration existante et n’ajuster que \theoremstyle. Si vous ne voulez qu’un autre mot d’en-tête pour un environnement existant, cherchez le point d’entrée propre à la classe plutôt que \newtheorem.

Ce que change \theoremstyle : la police du titre et du corps

Le \theoremstyle de amsthm change la combinaison de polices de l’en-tête (head) et du corps (body). Trois styles sont intégrés : plain, definition et remark. Le point décisif : \theoremstyle{…} n’agit que sur les \newtheorem écrits après lui. Placer un style sous une déclaration ne s’applique pas rétroactivement ; regroupez donc les déclarations par style dans le préambule. Sans indication, c’est plain.

  • plain : en-tête en gras, corps en italique. Pour les énoncés affirmés avec emphase : théorèmes, lemmes, propositions, corollaires. C’est le style par défaut.
  • definition : en-tête en gras, corps droit (romain). Pour ce qui doit se lire comme une prose ordinaire : définitions, exemples, problèmes, conditions. Le romain se lit mieux dès que le texte contient des formules ou s’allonge.
  • remark : en-tête en italique, corps droit. Pour les apartés : remarques, notes, claims. L’en-tête s’allégeant lui aussi, le passage n’interrompt pas le fil du texte environnant.
preamble
\usepackage{amsmath, amsthm}

\theoremstyle{plain}            % italic body
\newtheorem{theorem}{Theorem}[section]
\newtheorem{lemma}[theorem]{Lemma}
\newtheorem{corollary}[theorem]{Corollary}

\theoremstyle{definition}       % upright body
\newtheorem{definition}[theorem]{Definition}
\newtheorem{example}[theorem]{Example}

\theoremstyle{remark}           % italic head
\newtheorem*{remark}{Remark}

Avec cette configuration, theorem, lemma, corollary, definition et example partagent une même suite par section (Theorem 2.1, Definition 2.2, Lemma 2.3…), les trois premiers en corps italique, les deux derniers en romain. Seul remark n’a pas de numéro et son en-tête « Remark » est en italique. Si l’on peut partager les numéros tout en séparant les polices, c’est que le compteur et le style sont deux axes indépendants.

L’environnement proof et le symbole QED qui tombe à la mauvaise ligne

L’environnement proof de amsthm s’ouvre sur un « Proof. » en italique et se referme automatiquement par \qedsymbol, par défaut □. Mais proof cherche à poser le symbole en fin de la dernière ligne de paragraphe ; si la preuve se termine par une équation hors texte, cette ligne manque et le □ tombe seul sur une ligne à lui. Ce n’est pas une impression, cela se mesure. En plaçant la même preuve dans une \vbox et en relevant la hauteur :

log
% \vbox{\hsize=8cm \begin{proof}Compute:\[a^2+b^2=c^2.\]\end{proof}}
without \qedhere   h = 66.94444pt
with    \qedhere   h = 47.77777pt      % 19.16667pt shorter: one whole line saved

L’écart est de 19.16667pt, soit exactement une ligne. \qedhere est l’instruction « place le symbole ici » : écrite à la fin d’un affichage mathématique, elle cale le □ contre le bord droit de cette ligne d’équation et la ligne surnuméraire disparaît. \qedhere fonctionne dans equation, align et gather*, ainsi qu’au dernier item d’un enumerate (le tout compilé sans erreur sous TeX Live 2024). Là où le symbole ne peut être placé proprement, amsthm signale Package amsthm Warning: The \qedhere command may not work correctly here : le journal vous le dira.

latex
\begin{proof}
  Rearranging both sides gives
  \[
    a^2 + b^2 = c^2. \qedhere
  \]
\end{proof}

Le mot d’en-tête comme le symbole final peuvent être remplacés. Une preuve isolée accepte un crochet, ainsi \begin{proof}[Proof of Theorem 1] ; la valeur par défaut pour tout le document vient de \proofname, que l’on redéfinit (\renewcommand{\proofname}{Demonstration} produit bien un en-tête « Demonstration. »). Le symbole final se change en redéfinissant \qedsymbol. Comme signalé en tête, la valeur par défaut est \openbox, le carré évidé tracé au filet — le remplacer par $\blacksquare$ donne un carré plein, et le redéfinir vide supprime purement et simplement la marque. Attention : \blacksquare vient de amssymb (ligne 48 de amssymb.sty) ; avec amsthm seul on obtient ! Undefined control sequence. — n’oubliez pas \usepackage{amssymb}.

preamble
\usepackage{amssymb}                         % \blacksquare lives here, not in amsthm
\renewcommand{\proofname}{Demonstration}     % heading word for every proof
\renewcommand{\qedsymbol}{$\blacksquare$}    % filled square instead of the hollow one
% \renewcommand{\qedsymbol}{}                % no end-of-proof marker at all

thmtools : remplacer la position des crochets par des key=value

Passé une dizaine de déclarations, la convention de \newtheorem — le sens déterminé par la position des crochets — devient difficile à lire. thmtools (2023/05/04 v0.76 dans TeX Live 2024) est une interface de plus haut niveau posée sur amsthm (ou ntheorem) : \declaretheorem permet d’écrire les mêmes réglages en key=value. Il ne possède aucune machinerie de numérotation propre et se contente d’appeler le \newtheorem de amsthm en dessous ; on le charge donc avec amsthm.

preamble
\usepackage{amsmath, amsthm, thmtools, thm-restate}

\declaretheorem[numberwithin=section]{theorem}      % same as [section] after arg 2
\declaretheorem[sibling=theorem]{lemma}             % same as [theorem] after arg 1
\declaretheorem[style=definition, sibling=theorem]{definition}
\declaretheorem[numbered=no, name=Remark]{remark}

La correspondance des clés est directe. La subordination à une section est numberwithin= (synonymes parent=, within=), le partage d’un compteur sibling= (synonymes numberlike=, sharecounter=), l’absence de numéro numbered=no, le mot d’en-tête name= (synonymes title=, heading=) et l’aspect style=. Composez réellement le préambule ci-dessus : Theorem 1.1 est suivi de Lemma 1.2 — la sortie confirme que sibling= construit bien une suite unique.

La vraie raison d’ajouter thmtools tient à deux fonctions pénibles avec amsthm seul. La première est la reformulation (restatable). Chargez le thm-restate fourni, écrivez un théorème dans un environnement restatable : son contenu est stocké dans une macro que l’on peut recomposer plus loin avec le même numéro. C’est la façon habituelle d’énoncer un résultat numéroté dans le corps du texte et d’en renvoyer la preuve en annexe. À la compilation, le Theorem 1.1 du corps réapparaît en annexe comme Theorem 1.1.

latex
\begin{restatable}[Euclid]{theorem}{firsteuclid}
  \label{thm:euclid}
  There are infinitely many primes.
\end{restatable}

% later, e.g. in an appendix — same number, references still point at the original
\firsteuclid*

restatable prend un nom optionnel, puis l’environnement de théorème à employer, puis le nom de macro qui mémorise le contenu. Développer \firsteuclid plus loin recompose le théorème, le numéro restant fixé à la première occurrence. La forme étoilée \firsteuclid* le réaffiche tout en gardant \label/\ref pointés vers la déclaration d’origine et non vers la copie. La seconde fonction est la liste des théorèmes : \listoftheorems engendre une liste comparable à une table des matières, et ignoreall associé à show={…} la restreint aux environnements voulus. Il existe aussi onlynamed, qui ne retient que les théorèmes nommés via \begin{…}[name] ; avec hyperref chargé, chaque entrée devient un lien vers le théorème.

latex
\listoftheorems                                     % everything
\listoftheorems[ignoreall, show={theorem, lemma}]   % only these two
\listoftheorems[ignoreall, show={theorem}, onlynamed]  % only the ones you named

Pour composer votre propre aspect, définissez un style avec \declaretheoremstyle et appelez-le depuis \declaretheorem[style=…]{…}. Des clés règlent la police de l’en-tête headfont, celle du corps bodyfont, les espaces avant et après (spaceabove, spacebelow), les parenthèses autour du nom (notebraces), l’écart après l’en-tête (postheadspace), le symbole final (qed), et davantage. En pratique : si quelques déclarations suffisent, amsthm seul fait l’affaire ; on ajoute thmtools quand compter les crochets de \newtheorem devient agaçant, ou quand on veut des théorèmes restatable et une liste des théorèmes.