알고리즘(algorithm2e/algpseudocode)

원고에 코드를 싣는 방법은 하나가 아닙니다. verbatim은 입력한 그대로 재현하고, listings/minted는 실제 소스를 색과 행 번호와 함께 보여 줍니다. 또 하나의 방법은 언어에 의존하지 않는 절차를 “Algorithm 1”처럼 번호가 붙은 상자 안에 보이는 의사코드입니다. 의사코드는 실제 코드와 달리 그림이나 표처럼 페이지 위에서 떠다니는 *플로트*로 조판되며, 캡션, 일련 번호, 상호 참조, 알고리즘 목록을 갖습니다. 이 페이지는 그 의사코드를 *목록에 오르는 개체*로 보기 좋게 놓는 법, 특히 캡션과 번호 매기기에 초점을 맞춥니다. 같은 패키지의 명령별 완전한 해설은 /learn/math/algorithms에 있으므로, 여기서는 두 생태계의 큰 그림과 각각의 최소 완성 예만 보입니다.

의사코드는 플로트로 배치한다

verbatim이나 listings가 코드를 본문 흐름 안에 놓는 데 비해, 의사코드는 보통 플로트 안에 제시합니다. 플로트는 figuretable처럼 LaTeX가 페이지 경계를 피해 적절한 위치에 자동 배치하는 상자입니다. 여기서 두 가지 장점이 생깁니다. 첫째, “Algorithm 1”처럼 번호가 붙은 캡션이 생겨 본문에서 \ref로 참조할 수 있습니다. 둘째, 긴 알고리즘이 페이지 경계에서 보기 흉하게 쪼개지지 않습니다. 내부 본문 환경을 직접 놓으면 페이지를 넘어 갈라질 수 있지만, 플로트 상자는 하나로 유지되어 다음 페이지로 이동합니다.

처음 헷갈리는 지점은 비슷한 이름의 패키지가 여러 개 있다는 점입니다. 핵심은 번호가 붙은 부동 상자인 입구와 의사코드 자체인 내용을 서로 다른 패키지가 담당한다는 분업입니다. 다만 이 분업은 두 갈래 중 한쪽에만 해당합니다. 실제로는 크게 두 가지 선택지가 있습니다.

  • 두 층: algorithm(입구) + algpseudocode(내용). algorithm 플로트가 떠다니는 상자, 캡션, 번호를 제공하고, algpseudocode(algorithmicx의 표준 레이아웃)가 \State, \For, \If 같은 의사코드 본문을 제공합니다.
  • 하나의 패키지: algorithm2e. 자체 완결형으로, 플로트, 캡션, 본문 명령(\KwIn/\KwOut, \eIf 등)을 모두 포함합니다. algorithm은 추가하지 않습니다(둘을 함께 읽으면 플로트 환경 이름이 충돌합니다).

가장 중요한 원칙을 먼저 말하면, 문서 전체에서 한 가지 계열로 통일해야 합니다. algpseudocodealgorithm2e는 문법과 철학이 완전히 다르며, 둘을 모두 읽으면 \For\If 같은 같은 이름의 명령이 충돌해 오류가 납니다. 어느 쪽을 쓰든 번호, 상호 참조, 알고리즘 목록이 확정되도록 문서는 평소처럼 두 번 컴파일합니다.

캡션, 번호, 참조, 알고리즘 목록

이 페이지의 초점은 게재물로서의 모양입니다. 어느 계열이든 \caption{…}“Algorithm N” 제목을 만들고, N은 등장 순서대로 자동 번호가 붙습니다. 바로 뒤에 \label{key}를 두면 본문에서 \ref{key}로 그 번호를, \pageref{key}로 페이지 번호를 가져올 수 있습니다. 그림이나 표를 참조하는 방식과 완전히 같습니다.

번호가 붙은 플로트의 또 다른 장점은 알고리즘 목록입니다. \listoffigures, \listoftables와 나란한 기능으로, \listofalgorithms라고 쓰면 각 알고리즘의 번호와 캡션을 모은 목차 같은 목록이 생성됩니다. 여기에 실리는 것은 \caption에 준 문구이며, algorithm 플로트와 algorithm2e 모두에서 동일하게 작동합니다. algorithm2e에는 \caption과 별도로 제목만 붙이는 title 계열 명령도 있지만, 그것들은 알고리즘 목록에 항목을 추가하지 않는다는 점에 주의하세요.

캡션을 놓는 위치는 계열마다 관례가 다릅니다. algorithm 플로트에서는 그림처럼 \caption을 본문 앞이나 뒤 어디든 둘 수 있습니다(대개는 상자 위에 둡니다). 반면 algorithm2e에서는 \caption을 환경의 끝에 두는 것이 관례이며, 이 캡션이 알고리즘 목록의 참조 이름도 됩니다.

계열 1: algorithm + algpseudocode

바깥을 algorithm 플로트로 감싸고, 안쪽의 algorithmic 환경(패키지 이름은 algpseudocode지만 환경 이름은 algorithmic)에 의사코드를 씁니다. 본문 명령은 모두 첫 글자만 대문자(\State, \While 등)이며, 이것이 모두 대문자인 옛 algorithmic(\STATE)과 구별하는 방법입니다. 자주 쓰는 명령은 다음과 같습니다.

  • \State — 하나의 문장(행)의 시작. 문장마다 하나씩 둡니다.
  • \For{…}\EndFor / \While{…}\EndWhile — 반복문.
  • \If{…}\ElsIf{…}\Else\EndIf — 조건 분기.
  • \Function{name}{args}\EndFunction\Return — 함수와 반환값.
  • \Require / \Ensure — 전제 조건과 사후 조건(굵은 라벨 포함).
  • \Comment{…} — 행 끝 주석.

시작할 때의 선택 인수 [1]은 행 번호를 제어합니다. 1이면 모든 행에 번호를 붙이고, n이면 n행마다 번호를 붙이며, 생략하면 번호가 없습니다. 다음은 거듭제곱 y = xⁿ을 계산하는 최소 예입니다. \caption 바로 뒤에 \label을 둔 점에 주목하세요.

document.tex
\documentclass{article}
\usepackage{algorithm}
\usepackage{algpseudocode}
\begin{document}

\listofalgorithms

\begin{algorithm}
  \caption{Calculate $y = x^n$}\label{alg:power}
  \begin{algorithmic}[1]
    \Require $n \geq 0$
    \State $y \gets 1$
    \While{$n \neq 0$}
      \State $y \gets y \times x$
      \State $n \gets n - 1$ \Comment{count down}
    \EndWhile
    \State \Return $y$
  \end{algorithmic}
\end{algorithm}

アルゴリズム~\ref{alg:power} は累乗を計算する。

\end{document}

컴파일하면 위아래에 가로줄이 있는 상자가 페이지에 플로트로 배치되고, 위쪽에 “Algorithm 1 Calculate y = xⁿ”라는 제목이 붙습니다(번호는 자동). 각 행 왼쪽에는 1, 2, 3 … 행 번호가 붙고, 본문의 \ref{alg:power}는 그 번호(여기서는 1)로 바뀝니다. 문서 앞의 \listofalgorithms에는 “1 Calculate y = xⁿ … page” 같은 항목이 생성됩니다. \ElsIf\Function을 포함해 각 명령이 어떻게 출력되는지는 /learn/math/algorithms를 보세요.

계열 2: algorithm2e

algorithm2e는 입구와 내용을 하나의 패키지 안에서 자체 완결시키는 별도 계열입니다(현재 릴리스 5.2, 2017년). \begin{document}보다 앞에서 \usepackage[…]{algorithm2e}로 읽으며, algorithm 환경 자체가 플로트가 됩니다. 스타일은 로드 옵션으로 고릅니다. ruled(위아래 가로줄), boxed(전체 상자), vlined/lined(블록 세로줄), plain(기본, 장식 없음)이며, 행 번호는 linesnumbered를 붙입니다. 문법의 핵심은 세 가지입니다.

  • 입력/출력은 전용 명령 \KwIn{…}/\KwOut{…}(또는 \KwData{…}/\KwResult{…})을 쓰며, 굵은 “Input:”, “Output:” 등으로 조판됩니다.
  • 분기와 반복은 본문을 중괄호 인수로 넘깁니다. if–then–else는 \eIf{cond}{then}{else}이고, 반복은 \For{…}{body}, \While{…}{body}입니다(“to”는 \KwTo).
  • 모든 문장은 \\;로 끝납니다(백슬래시+세미콜론). 잊으면 다음 문장이 같은 행에 이어집니다. 출력에 “;”를 보이고 싶지 않으면 \DontPrintSemicolon을 씁니다.
document.tex
\documentclass{article}
\usepackage[ruled,linesnumbered]{algorithm2e}
\begin{document}

\listofalgorithms

\begin{algorithm}
  \caption{Sum of positive entries}\label{alg:sum}
  \KwIn{an array $a[1..n]$}
  \KwOut{the sum $s$ of its positive entries}
  $s \gets 0$\;
  \For{$i \gets 1$ \KwTo $n$}{
    \eIf{$a[i] > 0$}{
      $s \gets s + a[i]$\;
    }{
      skip\;
    }
  }
  \Return $s$\;
\end{algorithm}

アルゴリズム~\ref{alg:sum} は正の要素を合計する。

\end{document}

ruled는 위아래에 줄을 긋고 위쪽에 캡션 행을 붙이며, linesnumbered는 각 행에 번호를 붙입니다. 상자는 굵은 “Input:”, “Output:”으로 시작하고, \For 행은 for i ← 1 to n do처럼 조판되며 본문은 들여쓰기됩니다. \eIfifthen의 참 블록과 else의 거짓 블록을 위아래로 놓습니다. 각 \; 위치에서 줄바꿈이 일어나고, 마지막 행은 return s입니다. \caption 텍스트는 \listofalgorithms 목록에 그대로 실립니다. [H](플로트하지 않고 그 자리에 고정), \SetAlgoLined(블록에 세로줄) 등 세밀한 조정은 /learn/math/algorithms에 정리되어 있습니다.

어느 쪽을 쓸까

둘 다 널리 쓰이며, 우열이라기보다 관습의 차이입니다. 아래 빠른 표로 대략의 방향을 잡으세요.

관점algorithm + algpseudocodealgorithm2e
構成두 층, 두 패키지하나의 자체 완결 패키지
本体の書き方\State 중심의 직관적 명령 체계블록 본문을 중괄호로 전달
入出力\Require / \Ensure\KwIn / \KwOut(명시적)
行末필요 없음\\; 필수
向く人전통적 모양이나 학회 템플릿이 전제할 때입출력 선언, 세로줄, 다국어 키워드를 많이 쓸 때

어느 계열이든 게재물로서의 처리는 같습니다. \caption으로 번호가 붙은 제목을 주고, \label/\ref로 참조하며, \listofalgorithms로 목록을 만듭니다. 다시 말하지만 본문 패키지는 하나로 좁히세요. algorithm2e를 쓴다면 입구인 algorithm은 읽지 않습니다. 명령의 전체 목록과 더 긴 완성 예는 /learn/math/algorithms에 있습니다. 의사코드가 아니라 실제 소스 코드를 색과 행 번호와 함께 싣고 싶다면 /learn/code-verbatim/code-listingslistings/minted가 적합합니다.