정리와 증명(amsthm)

증명 끝에 놓이는 빈 사각형은 사실 어떤 글꼴의 문자도 아닙니다. LaTeX의 amsthm은 그 기호를 세로 괘선 두 개와 가로 괘선 두 개로 그 자리에서 그려 냅니다(amsthm.sty\openbox. 실측 너비 7.77786pt, 높이 6.75003pt로, 10pt 문서에서는 0.77778em × 0.675em입니다). 정리 환경도 같은 발상으로 되어 있습니다. LaTeX은 완성된 “정리”를 건네주지 않고 \newtheorem이라는 선언 장치 만 건네며, 무엇을 정리라 부르고 번호를 어떻게 매길지는 글쓴이가 정합니다. 이 페이지에서는 \newtheorem이 실제로 무엇을 생성하는지, 두 개의 대괄호를 왜 함께 쓸 수 없는지, \theoremstyle이 정말로 바꾸는 것이 무엇인지, 그리고 증명 종료 기호가 엉뚱한 줄에 떨어지는 \qedhere 문제까지 실제 조판 결과와 함께 따라갑니다.

\newtheorem이 생성하는 것: 환경과 카운터

\newtheorem{theorem}{Theorem}환경 하나와 그것을 세는 카운터 하나 를 만듭니다. 로그를 보면 \c@theorem=\count196 같은 줄이 나오는데, 카운터가 실제로 할당된 것입니다. 첫 번째 인수는 본문에서 \begin{…}에 쓰는 환경 이름이고, 두 번째 인수는 제목에 굵게 찍히는 단어입니다. 이 둘이 서로 다른 것이라는 점이 핵심입니다. 환경 이름은 theorem 그대로 두고 찍히는 단어만 SatzThéorème로 바꿔 쓸 수 있습니다.

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

이 선언 뒤에는 theorem 환경을 쓸 때마다 Theorem 1, Theorem 2 처럼 굵은 제목과 연속 번호가 붙고, 안의 문장은 기본 스타일에서 이탤릭으로 조판됩니다. 번호는 LaTeX 카운터가 들고 있으므로 중간에 정리를 끼워 넣으면 뒤의 번호가 자동으로 밀립니다. 정리 번호를 검색할 때 정말 원하는 성질이 바로 이것입니다. 번호를 손으로 적지만 않으면 번호가 어긋날 일이 없습니다.

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}

두 번째 예처럼 \begin{theorem} 바로 뒤에 대괄호로 이름을 넘기면 번호 뒤에 괄호로 붙어 “Theorem 2 (Pythagoras).” 가 됩니다. 이는 번호의 유무와 무관 하며, 아래에서 \newtheorem*으로 만드는 번호 없는 환경에서도 똑같이 쓸 수 있습니다. 또한 \newtheorem 자체는 표준 LaTeX2e에도 들어 있습니다. 기본 \newtheorem만으로도 번호 있는 환경을 만들 수 있지만, 이어서 다룰 \theoremstyle, \newtheorem*, proof 환경, \qedhere는 모두 amsthm의 확장이라 \usepackage{amsthm}을 써야 사용할 수 있습니다.

두 개의 대괄호: 공유와 종속은 함께 쓸 수 없습니다

\newtheorem은 대괄호를 하나만 받으며, 그것을 어디에 두느냐로 의미가 달라집니다. 환경 이름 바로 뒤에 두면 “기존 카운터를 공유한다”는 뜻이고, 두 번째 인수 뒤에 두면 “그 부모 카운터에 종속되어 함께 재설정된다”는 뜻입니다. 정리와 보조정리를 따로 세면 “Theorem 1, Lemma 1, Theorem 2, Lemma 2…”처럼 같은 번호가 흩어져 헷갈리므로, 대부분의 수학 글은 앞쪽을 택해 “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"

뒤쪽 대괄호에는 section 대신 기존 정리 환경을 넣을 수도 있습니다. \newtheorem{corollary}{Corollary}[theorem]이라 쓰면 따름정리 번호가 정리가 나올 때마다 재설정되어 “Corollary 3.1”은 “Theorem 3에 딸린 첫 따름정리”로 읽힙니다.

선언효과
\newtheorem{theorem}{Theorem}자체 카운터로 1, 2, 3, … 번호를 매깁니다
\newtheorem{lemma}[theorem]{Lemma}theorem의 카운터를 공유해 정리와 보조정리가 한 번호열이 됩니다
\newtheorem{theorem}{Theorem}[section]\section마다 1로 돌아가고 절 번호를 앞에 붙여 “2.1” 형태로 나옵니다
\newtheorem{corollary}{Corollary}[theorem]theorem이 나올 때마다 재설정되고 부모 번호를 이어받아 “3.1”로 나옵니다
\newtheorem*{remark}{Remark}카운터를 만들지 않고 번호 없이 제목 단어만 찍습니다(amsthm 필요)

그렇다면 둘을 동시에 쓰면 어떻게 될까요. TeX Live 2024에서 \newtheorem{lemma}[theorem]{Lemma}[section]을 통과시키면 오류가 나기는 하지만 \newtheorem에 대해서는 아무 말도 해 주지 않습니다. \newtheorem은 두 번째 대괄호를 읽지 않으므로 [section]그냥 글자로 프리앰블에 남고, LaTeX은 본문이 시작된 줄로 착각합니다. 나오는 메시지는 다음과 같습니다.

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

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

즉 공유와 종속은 둘 중 하나만 고를 수 있습니다. 둘 다 원한다면——“보조정리는 정리와 번호를 공유하고, 그 번호는 절마다 재설정되면 좋겠다”——[section]부모 쪽에만 씁니다. \newtheorem{theorem}{Theorem}[section]으로 선언해 두면, \newtheorem{lemma}[theorem]{Lemma}로 공유한 보조정리도 자동으로 절 번호가 붙습니다. 카운터가 하나뿐이므로 이렇게 하면 모순 없이 양쪽이 모두 성립합니다.

Command \theorem already defined. 오류가 났을 때

이 오류는 같은 환경 이름을 두 번 선언했다 는 뜻입니다. \newtheorem은 새 환경을 만드는 명령이므로 이미 있는 이름을 덮어쓰는 것을 허용하지 않습니다. 한 프리앰블에 \newtheorem{theorem}{Theorem}을 두 번 쓰면 다음과 같이 나옵니다.

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

실제로는 같은 줄을 두 번 쓴 탓인 경우가 드뭅니다. 보통은 문서 클래스나 이미 불러온 패키지가 theorem을 먼저 선언해 두었기 때문입니다. 학회 템플릿, amsart, elsarticle 등은 정리 환경을 미리 준비해 두기도 합니다. 해결책은 셋입니다. 내가 쓴 줄을 지우거나, mytheorem처럼 이름을 바꾸거나, 기존 선언을 그대로 쓰고 \theoremstyle만 조정하는 것입니다. 이미 있는 환경의 제목 단어만 바꾸고 싶다면 \newtheorem을 꺼내기보다 그 클래스가 제공하는 방법을 찾는 편이 빠릅니다.

\theoremstyle이 바꾸는 것: 제목과 본문의 글꼴

amsthm\theoremstyle은 제목(head)과 본문(body)에 쓰는 글꼴 조합 을 바꿉니다. 내장 스타일은 plain, definition, remark 셋입니다. 결정적으로 중요한 점은 \theoremstyle{…}그 뒤에 쓴 \newtheorem에만 적용된다 는 것입니다. 선언 아래에 스타일을 두어도 소급 적용되지 않으므로 프리앰블에서는 스타일별로 선언을 묶습니다. 아무것도 쓰지 않으면 plain입니다.

  • plain: 제목은 굵게, 본문은 이탤릭. 정리, 보조정리, 명제, 따름정리처럼 강조해 말하는 주장에 씁니다. 아무것도 지정하지 않았을 때의 기본값입니다.
  • definition: 제목은 굵게, 본문은 직립체(로만체). 정의, 예, 문제, 조건처럼 보통 문장으로 읽히게 할 내용에 씁니다. 수식이 섞이거나 길어질 때는 직립체가 읽기 편합니다.
  • remark: 제목이 이탤릭, 본문은 직립체. 비고, 주석, claim처럼 덧붙이는 문장에 씁니다. 제목까지 가벼워지므로 주변 본문의 흐름을 끊지 않습니다.
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}

이 구성에서는 theorem, lemma, corollary, definition, example 다섯이 절마다 재설정되는 하나의 번호열(Theorem 2.1, Definition 2.2, Lemma 2.3…)을 공유하고, 앞의 셋은 본문이 이탤릭, 뒤의 둘은 직립체가 됩니다. remark만 번호가 없고 “Remark” 제목이 이탤릭으로 나옵니다. 번호는 공유하면서 글꼴만 나눌 수 있는 것은 카운터와 스타일이 서로 독립된 두 축 이기 때문입니다.

proof 환경과 증명 종료 기호가 엉뚱한 줄에 놓이는 문제

amsthmproof 환경은 처음에 이탤릭 “Proof.”를 놓고, 끝에 \qedsymbol(기본값 □)을 자동으로 붙입니다. 그런데 proof는 기호를 마지막 문단 줄의 끝 에 두려 하므로, 증명이 별행 수식으로 끝나면 붙일 줄이 없어 □가 혼자 다음 줄로 떨어집니다. 이는 인상이 아니라 치수로 확인할 수 있습니다. 같은 증명을 \vbox에 넣고 높이를 재면 이렇게 나옵니다.

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

차이는 19.16667pt, 정확히 한 줄입니다. \qedhere는 “기호를 여기에 두라”는 지시로, 별행 수식 끝에 쓰면 □가 그 수식 줄의 오른쪽 끝에 들어가고 여분의 한 줄이 사라집니다. \qedhereequation, align, gather* 안에서도, enumerate의 마지막 항목에서도 동작합니다(모두 TeX Live 2024에서 오류 없이 통과함을 확인했습니다). 기호를 깔끔히 놓을 수 없는 자리에서는 amsthmPackage amsthm Warning: The \qedhere command may not work correctly here 라고 경고하므로 로그를 보면 알 수 있습니다.

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

제목 단어와 종료 기호는 모두 바꿀 수 있습니다. 개별 증명에는 \begin{proof}[Proof of Theorem 1]처럼 대괄호로 제목을 넘길 수 있고, 문서 전체의 기본 단어는 \proofname을 재정의해 바꿉니다(\renewcommand{\proofname}{Demonstration}으로 제목이 “Demonstration.”이 되는 것을 확인했습니다). 종료 기호는 \qedsymbol을 재정의하면 됩니다. 앞머리에서 말했듯 기본 \qedsymbol은 괘선으로 그린 빈 사각형 \openbox이므로, $\blacksquare$로 바꾸면 검은 사각형이 되고 빈 값으로 재정의하면 표시 자체가 사라집니다. 다만 \blacksquareamssymb(amssymb.sty 48행)의 기호라서 amsthm만으로는 ! Undefined control sequence. 가 납니다. \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: 대괄호 위치를 key=value로 바꾸기

선언이 열 개를 넘어설 무렵이면 “대괄호 위치로 의미가 정해진다”는 \newtheorem의 방식은 읽기 어려워집니다. thmtools(TeX Live 2024 동봉판은 2023/05/04 v0.76)는 amsthm(또는 ntheorem) 위에 얹히는 상위 인터페이스로, \declaretheorem을 통해 같은 설정을 key=value 로 쓸 수 있게 해 줍니다. 자체 번호 장치는 없고 뒤에서 amsthm\newtheorem을 부를 뿐이라 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}

키의 대응은 단순합니다. 절에 종속시키는 것은 numberwithin=(동의어 parent=, within=), 카운터 공유는 sibling=(동의어 numberlike=, sharecounter=), 번호 없음은 numbered=no, 제목 단어는 name=(동의어 title=, heading=), 모양은 style= 입니다. 위 프리앰블을 실제로 조판하면 Theorem 1.1 다음에 Lemma 1.2가 나옵니다. sibling=이 실제로 하나의 번호열을 만든다는 것을 출력으로 확인할 수 있습니다.

thmtools를 넣는 진짜 이유는 amsthm 만으로는 번거로운 두 기능입니다. 첫째는 재게시(restatable) 입니다. 함께 들어 있는 thm-restate를 불러오고 정리를 restatable 환경에 쓰면, 그 내용이 매크로로 저장되어 나중에 같은 번호 그대로 다시 조판할 수 있습니다. 주장은 본문에 번호와 함께 두고 증명만 부록으로 보내고 싶을 때의 정석입니다. 실제로 조판해 보니 본문의 Theorem 1.1이 부록에서도 그대로 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은 생략 가능한 이름, 그다음 사용할 정리 환경, 마지막으로 내용을 기억할 매크로 이름 을 받습니다. 나중에 \firsteuclid를 펼치면 그 정리가 다시 조판되고 번호는 처음 나온 자리에 고정된 채로 남습니다. 별을 붙인 \firsteuclid*\label\ref사본이 아니라 원래 선언 위치 를 가리키도록 유지한 채 재게시하는 형태입니다. 또 하나의 기능은 정리 목록 입니다. \listoftheorems라고 쓰면 목차 같은 목록이 생성되고, ignoreallshow={…}로 실을 환경을 좁힐 수 있습니다. \begin{…}[name]으로 이름을 붙인 정리만 골라내는 onlynamed도 있으며, hyperref를 함께 쓰면 각 항목이 본문으로 가는 링크가 됩니다.

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

모양을 직접 만들고 싶다면 \declaretheoremstyle로 스타일을 정의하고 \declaretheorem[style=…]{…}에서 호출합니다. 키로 제목 글꼴 headfont, 본문 글꼴 bodyfont, 위아래 여백 spaceabovespacebelow, 이름을 감싸는 괄호 notebraces, 제목과 본문 사이 간격 postheadspace, 종료 기호 qed 등을 지정할 수 있습니다. 판단 기준은 이렇습니다. 선언이 몇 개로 끝난다면 amsthm만으로 충분 하고, \newtheorem의 대괄호를 세는 일이 성가셔지거나 재게시와 정리 목록이 필요해지면 그때 thmtools를 더하면 무리가 없습니다.