\documentclass[UTF8,a4paper,scheme=plain,%
punct=quanjiao]{ctexart}

\usepackage{tikz-cd}

\usepackage{amsmath}
\usepackage{commath}
\usepackage[backend=biber,style=authoryear,%
bibstyle=trad-plain]{biblatex}
\usepackage{filecontents}
\begin{filecontents}{refs.bib}
  @book{TeXbook,
    title={The \TeX book},
    author={Donald Ervin Knuth},
    publisher={Addison-Wesley Professional},
    year={1984},
    month={1},
  }
  @manual{MathMode,
    title={Math Mode},
    author={Herbert Voß},
    year={2014},
    month={1},
    url={http://ctan.math.utah.edu/ctan/tex-archive/obsolete/info/math/voss/mathmode/Mathmode.pdf},
  }
  @manual{AmSmath,
    title={User's Guide for the \texttt{amsmath} package},
    author={American Mathematical Society and \LaTeX 3 Project},
    date={1999-12-13},
    url={http://mirrors.concertpass.com/tex-archive/macros/latex/required/amsmath/amsldoc.pdf},
  }
  @techreport{ISO80000-2,
    type={Standard},
    author={{ISO 80000-2:2009(E)}},
    year={2009},
    month={12},
    title={Quantities and units -- Part 2: Mathematical signs and symbols to be used in the natural sciences and technology},
    institution={International Organization for Standardization},
    url={https://www.iso.org/standard/31887.html}
  }
\end{filecontents}
\addbibresource[location=local]{refs.bib}

\usepackage{fancyvrb}
% 显示一个列子，并把对应的代码保存下来
\newenvironment{exampleshow}[1]
{\makeatletter
  \def\filename@es{\jobname-#1.aux}
  \typeout{Writing file \filename@es}
  \VerbatimOut{\filename@es}}
{\endVerbatimOut
  \input{\filename@es}
  \makeatother}

% 显示对应例子的代码
\newcommand{\examplecode}[1]{\VerbatimInput{\jobname-#1.aux}}

\usepackage{enumitem}
\setlist[enumerate]{font=\bfseries}

\usepackage{makeidx}
\makeindex

\usepackage[skip=2ex plus 1ex]{parskip}

\usepackage[unicode=true,pdfusetitle,
 bookmarks=true,bookmarksnumbered=false,bookmarksopen=false,
 breaklinks=false,pdfborder={0 0 0},pdfborderstyle={},backref=false,colorlinks=false]
 {hyperref}

%\setlength{\parskip}{4ex}

\title{Math formula exercise}
\author{\textsc{Peng Guanwen}}
\newcommand*{\cmd}[1]{\texttt{\char`\\#1}}
\newcommand*{\bracite}[1]{[\cite{#1}]}
\renewcommand*{\indexname}{Unusual math command}

\begin{document}

\maketitle

\begin{abstract}
\LaTeX 是一款非常优秀的文档准备系统，它强大的数学排版功能
举世闻名。由于 Mathjax\footnote{\url{https://www.mathjax.org/}}的广泛采用，\LaTeX 数学公式也成为了
Web 技术上数学公式排版的事实标准。但 \LaTeX 的学习曲线陡峭，
基本的命令难以轻松应对实际写作中遇到的复杂公式。本文选取
并实现了 \citetitle{TeXbook}第18章末尾提供的20个Chanllenge。
以期为想要深入学习 \LaTeX 公式排版的读者提供参考。

\citeauthor{TeXbook}在\citetitle{TeXbook}的附录中给出
了全部习题的答案，但全部使用的是原始的 \TeX 命令，而本文则采用了
适用于 \LaTeX 的命令。
为提供最大兼容性，本文原则上只使用 \LaTeX 与 \AmS 宏集提供
的命令排版数学公式。一个例外是 \texttt{commath} 宏包提供的
\cmd{dif}命令。但即使不引用这个宏包，也可以轻易地通过定义
\verb|\DeclareMathOperator{\dif}{d\!}|
来使用这个命令。

\end{abstract}

\begin{enumerate}[label=Challenge \arabic*]
\item\label{i:textmathrm}
  \begin{exampleshow}{nthroot}
    \(n^\textrm{th}\) root
  \end{exampleshow}

  \examplecode{nthroot}

  \cmd{textrm}命令与 \cmd{mathrm}命令都可以在数学模式
  显示直的罗马体“th”。在本例中效果也是一样的。但根
  据\citetitle{MathMode}，\cmd{mathrm}是竖直字体的数学模式
  而 \cmd{textrm}是“真正的”文本模式，在这个公式下应该选择后者。

  \index{\cmd{textrm}}

\item
  \begin{exampleshow}{sts}
    \(\mathbf{S}^{-1}\mathbf{TS}=
    \mathbf{dg}(\omega_1,\dots,\omega_n)=\boldsymbol\Lambda\)
  \end{exampleshow}

  \examplecode{sts}

  与 \ref{i:textmathrm} 类似，本题中\(\mathbf{S}\)是粗体数学符号，所以
  采用 \cmd{mathbf}而不是 \cmd{textbf}。

  \index{\cmd{mathbf}}

  \LaTeX 下直接使用 \verb|\mathbf\Lambda| 不能得到正常
  的\(\boldsymbol\Lambda \)粗体效果，我们采用 \AmS 宏集
  的 \cmd{boldsymbol}命令完成。

  \index{\cmd{boldsymbol}}

  \LaTeX 数学模式有两种省略号“\(\ldots\)”和“\(\cdots\)”，分别
  用\cmd{cdots}和 \cmd{ldots}生成。\AmS 宏集提供
  了 \cmd{dots}、\cmd{dotsi}、\cmd{dotsc}、\cmd{dotsb}、
  \cmd{dotsm}、
  \cmd{dotso}等命令，可以更方便灵活地使用这两种省略号。用法详
  见 \citetitle[p14]{AmSmath}。

  \index{\cmd{dots}}

\item
  \begin{exampleshow}{pr}
    \(\Pr(m=n\mid m+n=3)\)
  \end{exampleshow}

  \examplecode{pr}

  \cmd{mid}与\texttt{|}、\cmd{lvert}、\cmd{rvert}都是显示为\(|\)的同一
  个字符。不同的是它们的语义不同，如 \cmd{mid}是一个关系符，
  而 \cmd{lvert}是一个左分隔符。这些语义能帮助\LaTeX 产生正确的空白。

  \index{\cmd{vert}!vert@$\vert$}
  \index{\cmd{vert}!\cmd{lvert}}
  \index{\cmd{vert}!\cmd{rvert}}
  \index{\cmd{mid}}

  \citetitle{TeXbook}认为这个式子可以与集合记号类比，在括号两侧添加窄空
  格。但我认为\(\Pr\)还是应该被认为是一个函数，所以使用默认的空白方案。

\item
  \begin{exampleshow}{sin18}
    \(\sin18^\circ=\frac14 (\sqrt5-1)\)
  \end{exampleshow}

  \examplecode{sin18}

  \cmd{frac}的参数如果只有一个字符，可以直接省略大括号，以增加可读性。

  \index{\cmd{circ}}

\item
  \begin{exampleshow}{k}
    \(k=1.38\times10^{-16}\,\textrm{erg}/^\circ\textrm K\)
  \end{exampleshow}

  \examplecode{k}

  单位\(\textrm{erg}/^\circ\textrm{K}\)与数字之间应该有一个窄空
  格\cmd{,}。

  \index{\cmd{,}}

\item
  \begin{exampleshow}{phiinnl}
    \(\bar\Phi\subset NL_1^*/N=
    \bar L_1^*\subseteq\dots\subseteq NL_n^*/N=\bar L_n^*\)
  \end{exampleshow}

  \examplecode{phiinnl}

\item
  \begin{exampleshow}{ilambda}
    \(I(\lambda)=\iint_Dg(x,y)e^{i\lambda h(x,y)}\dif x\dif y\)
  \end{exampleshow}

  \examplecode{ilambda}

  在 \citetitle{TeXbook}中微分符号都是写作斜体的\(dx\)，但根
  据\citeauthor{ISO80000-2}，应该采用竖直的罗马体。所以使
  用 \texttt{commath}宏包的 \cmd{dif}命令以符合标准的要求。

  \index{\cmd{dif}}

\item
  \begin{exampleshow}{intdotsint}
    \(\int_0^1\dotsi\int_0^1f(x_1,\dots,x_n)\dif x_1\dots\dif x_n\)
  \end{exampleshow}

  \examplecode{intdotsint}

  \citetitle{TeXbook}认为应该在第一个积分符号后面插入一个负空
  格 \cmd{!}。 但我认为没有合适的排版上的理由这要做。

\item
  \begin{exampleshow}{x2m}
    \[x_{2m}\equiv\begin{cases}
        Q(X_m^2-P_2W_m^2)-2S^2&(m\textrm{ odd})\\
        P_2^2(X_m^2-P_2W_m^2)-2S^2&(m\textrm{ even})
      \end{cases}\pmod N
    \]
  \end{exampleshow}

  \examplecode{x2m}

  两行公式略显拥挤。如果采用 \texttt{mathtools}宏包的
  \cmd{dcases}将会取得更好的结果。

  \index{\cmd{pmod}}

\item
  \begin{exampleshow}{1x1z}
    \[(1+x_1z+x_1^2z^2+\dotsb)\dots(1+x_nz+x_n^2z^2+\dotsb)=
      \frac1{(1-x_1z)\dots(1-x_nz)}
    \]
  \end{exampleshow}

  \examplecode{1x1z}

  \cmd{dots}自动判断在这个例子中不起作用，所以需要语义化的版本
  \cmd{dotsb}。

  \index{\cmd{dots}!\cmd{dotsb}}

  \citetitle{TeXbook}在两处“\(+\dotsb\)”后面都增加了窄空格。

\item
  \begin{exampleshow}{pi}
    \[\prod_{j\ge0}\biggl(\sum_{k\ge0}a_{jk}z^k\biggr)=
      \sum_{n\ge0}z^n\Biggl(\sum_{\substack{
          k_0,k_1,\dotsc\ge0\\
          k_0+k_1+\dots=n}} a_{0k_0}a_{1k_1}\dots\Biggr)
    \]
  \end{exampleshow}

  \examplecode{pi}

  如果采用 \cmd{left}和 \cmd{right}自动调整括号高度，会设置
  为括号内部整个公式的高度，效果不令人满意。于是使用 \cmd{Biggl}
  和 \cmd{Biggr}手动调整大小。

  \index{\cmd{Bigg}!\cmd{Biggl}}
  \index{\cmd{Bigg}!\cmd{Biggr}}

  \citetitle{TeXbook}在\(z^n\)后面增加了窄空格。
\item
  \begin{exampleshow}{fracn1}
    \[\frac{(n_1+n_2+\dots+n_m)!}{n_1!\,n_2!\dots n_m!}=
      \binom{n_1+n_2}{n_2}\binom{n_1+n_2+n_3}{n_3}\dots
      \binom{n_1+n_2+\dots+n_m}{n_m}
    \]
  \end{exampleshow}

  \examplecode{fracn1}

  \LaTeX 不能很好的计算后缀运算符周围的空白，所以我们需要在
  \(n_2!\)前面插入一个窄空格。

\item
  \begin{exampleshow}{pir}
    \[\Pi_R\genfrac[]{0pt}{}
      {a_1,a_2,\dots,a_M}
      {b_1,b_2,\dots,b_N}
      =\prod_{n=0}^R\frac{
        (1-q^{a_1+n})(1-q^{a_2+n})\dots(1-q^{a_M+n})}{
        (1-q^{b_1+n})(1-q^{b_2+n})\dots(1-q^{b_N+n})}
    \]
  \end{exampleshow}

  \examplecode{pir}

  使用 \cmd{genfrac} 可以生成向分数一样上下排列的两个公式，
  将第三个参数设置为零就可以取消掉中间的横线。

  \index{\cmd{genfrac}}

\item
  \begin{exampleshow}{sigmap}
    \[\sum_{p\textrm{ prime}}f(p)=\int_{t>1}f(t)\dif\pi(t)\]
  \end{exampleshow}

  \examplecode{sigmap}

\item
  \begin{exampleshow}{underbrace}
    \[\{\underbrace{\overbrace{\mathstrut a,\dots,a}^{k\;a\textrm{'s}},
        \overbrace{\mathstrut b,\dots,b}^{l\;b\textrm{'s}}
      }_{k+l\textrm{ elements}}\}
    \]
  \end{exampleshow}

  \examplecode{underbrace}

  \cmd{mathstrut}等价于 \verb|\vphanthom(|，这相当于插入
  了一个宽度为0，但高度与一个括号相等的盒子，使得两边的大括号
  一样高。

  \index{\cmd{mathstrut}}

\item
  \begin{exampleshow}{matrix}
    \[\begin{pmatrix}
        \begin{pmatrix}a&b\\c&d\end{pmatrix} &
        \begin{pmatrix}e&f\\g&h\end{pmatrix} \\
        \noalign{\smallskip} 0 &
        \begin{pmatrix}i&j\\k&l\end{pmatrix}
      \end{pmatrix}
    \]
  \end{exampleshow}

  \examplecode{matrix}

  \verb|\noalign{\smallskip}|用于增加两行之间的间距。

  \index{\cmd{noalign}\{\cmd{smallskip}\}}

\item
  \begin{exampleshow}{det}
    \[\det\left|
        \begin{array}{*{5}{l}}
          c_0&c_1&c_2&\dots&c_n\\
          c_1&c_2&c_3&\dots&c_{n+1}\\
          c_2&c_1&c_4&\dots&c_{n+2}\\
          \,\vdots&\,\vdots&\,\vdots& &\,\vdots\\
          c_n&c_{n+1}&c_{n+2}&\dots&c_{2n}
        \end{array}\right|>0\]
  \end{exampleshow}

  \examplecode{det}

  为了实现对齐，这里采用了 \texttt{array}环境。
  \texttt{mathtools}宏包提供了 \texttt{pmatrix*}环境，
  可以更方便地实现矩阵对齐。

  \index{\cmd{left}}
  \index{\cmd{right}}

\item
  \begin{exampleshow}{sumprime}
    \[\mathop{{\sum}'}_{x\in A}f(x)\stackrel{\textrm{def}}=
      \sum_{\substack{x\in A\\x\neq0}}f(x)\]
  \end{exampleshow}

  \examplecode{sumprime}

  由于在数学模式中 \texttt{'}等价于 \verb|^\prime|，
  而巨算符会改变上标
  的位置，所以直接采用 \verb|\sum'_{x\in A}|是不可行的。
  我们需要用 \cmd{mathop}临时制作一个新的巨算符。

  \index{\cmd{mathop}}

\item
  \begin{exampleshow}{genfrac}
    \newcommand*{\bottomalign}[1]%
    {\genfrac{}{}{0pt}{}{#1}{}}
    \[2\uparrow\uparrow k\stackrel{\textrm{def}}=
      2^{2^{2^{\cdot^{\cdot^{\cdot^2}}}}}
      \bottomalign{\Bigr\}\scriptstyle k}
    \]
  \end{exampleshow}

  \examplecode{genfrac}

  \citetitle{TeXbook}采用了 \cmd{vbox}和 \cmd{hbox}
  的组合实现了大括号沿下侧对齐。而这里使用了 \cmd{genfrac}
  命令，可以达到相同的效果，同时兼容了 Mathjax。

\item
  \begin{exampleshow}{tikzcd}
    \[\begin{tikzcd}
        & & & 0 \arrow[d]
        & \\
        0 \arrow[r] & \mathcal O_C \arrow[r,"\imath"]
        \arrow[d,equal] & \mathcal E \arrow[r,"\rho"]
        \arrow[d,"\phi"] & \mathcal L \arrow[r] \arrow[d,"\psi"]
        & 0 \\
        0 \arrow[r] & \mathcal O_C \arrow[r] & \pi_*\mathcal O_D
        \arrow[r,"\delta"] & R^1F_*\mathcal O_V(-D) \arrow[r]
        \arrow[d]
        & 0 \\
        & & & R^1F_*(\mathcal O_V(-iM))\otimes\gamma^{-1} \arrow[d] & \\
        & & & 0 &
      \end{tikzcd}
    \]
  \end{exampleshow}

  \examplecode{tikzcd}

  这个交换图在 \citetitle{TeXbook}是用矩阵实现的。但利用宏包
  \texttt{tikz-cd}，可以更方便，灵活地绘制交换图。

\end{enumerate}

\printindex

\printbibliography
\end{document}

%%% Local Variables:
%%% mode: latex
%%% TeX-engine: xetex
%%% End: