将方程与“groff eqn”中的多个标记和阵容对齐

问题描述

我正在尝试按照我通常在 LaTeX 中使用 groff 的方式对齐一些相当长的方程。我要达到的一般形式:

A = B + C
  = D * E
    + F * G
  = H + I   = J

LaTeX 中,我会这样做:

\documentclass[fleqn]{article}

\usepackage{amsmath}

\begin{document}
\begin{alignat*}{3}
A
  & = B + C \\
  & =
  \begin{aligned}[t]
    & D * E \\
    & + F * G
  \end{aligned} \\
  & = H + I
    && = J
\end{alignat*}
\end{document}

eqn 中,方程对齐是通过 marklineup 命令完成的。引用 typesetting Mathematics 2nd Ed(找到 here)中的 Kernighan 和 Cherry 来说明它们是如何工作的:

mark 这个词可以在等式中的任何地方出现一次。它记住它出现的水平位置。连续方程可以包含一个lineuplineup 出现的地方尽可能与前面mark标记的地方对齐。

在阅读本文时,我的印象是系统不会禁止lineup 与前一个标记对齐以及在同一行内设置新的 标记等式的,例如我希望以下内容

.PP
.EQ I
A mark =
B + C
.EN
.EQ I
lineup = mark
D * E
.EN
.EQ I
lineup + F * G
.EN

产生这样的东西:

A = B + C
  = D * E
    + F * G

然而,事实并非如此。 eqn 将加号与等号对齐:

A = B + C
  = D * E
  + F * G

并产生警告:

eqn:test.ms:10: multiple marks and lineups

我用一个小脚本编译我的 .ms 文件

eqn $1 -Tpdf | groff -ms -Tpdf > ${1/%.ms/.pdf}

我想知道是否有一些宏可以让我存储多个水平偏移(或如何定义一个)。对 marklineup 宏究竟是如何工作的进行一些说明也会有所帮助。

解决方法

非常令人失望的是,eqn 不允许设置新标记。这是一个可能有用的糟糕解决方法。它包括重复第一个方程,但在新位置使用关键字 mark,并将输出转移到任何地方,因此它不会出现。 .di 是开始和结束转移的基本 troff。

.EQ I
A mark = B + C
.EN
.EQ I
lineup = D * E
.EN
.di mydump
.EQ I
A = mark B + C
.EN
.di
.EQ I
lineup + F * G
.EN

注意,您还可以使用 fwd 99 等 eqn 命令向右移动 99/100 em,其中 em 大约是字符“m”的宽度。

,

这是在与 mark 相同的行上有第二个 lineup 的可能解决方案。它使用基本 troff 序列 \k 将当前水平位置标记到寄存器 myposn 中。然后有一个 eqn 宏 mylineup,它调用 eqn special 命令来运行 troff define MyLineup,它“返回”一个具有 myposn 单位水平移动的字符。在调用 eqn 之前,使用调用后的字设置一些寄存器,并期望它们被更新为此时所需的任何输出。我们不使用这个虚拟词,它可以是任何东西,但不能省略。例如,

.de MyLineup
. ds 0s "\h'\\n[myposn]u'
. nr 0w \\n[myposn]u
. nr 0h 0
. nr 0d 0
. nr 0skern 0
. nr 0skew 0
..

.EQ I
define mymark '\k[myposn]'
define mylineup 'special MyLineup'
A mark = B + C
.EN
.EQ I
lineup = mymark D * E
.EN
.EQ I
mylineup dummy + F * G
.EN

.de.. 的行是 MyLineup 的定义。两条 define 行应该在第一个等式中。此后,可以使用 mymarkmylineup dummy 代替 marklineup。原始标记和阵容不变。如有必要,可以在带有 mark 的行中再次使用真正的 mylineup,依此类推。


将此概括为具有许多标记是复杂的。第一个问题是 mymark 只是一个 eqn 定义,不能带数字参数。它不能使用 special 命令,因为它需要内联。一个简单的解决方案就是在开始时创建大量定义:

define mymark1 '\k[myposn1]'
define mymark2 '\k[myposn2]'

第二个问题是当 eqn 调用 MyLineup 时,它没有传递下面的参数(“dummy”,我们打算改为“1”)作为调用的参数,而是在变量 {{ 1}};该字符串也嵌入在格式化代码中,实际上(无论如何在我的测试中)0s。所以我们需要用 \f[R]\,1\/\fP 将数字从这个子串出来。修改后的宏和测试为:

.substring 0s 7 -6
,

我可能被您的示例中的多个 .EQ 调用误导了。我假设调用和方程之间会有文本。但是,如果打算使用单行多行方程,则可以使用 matrix(或者也可以使用 lpile)来完成。例如,

.nr PS 20p
.nr VS 24p
.PP
.EQ
matrix { 
 lcol { A }
 lcol { = above = above ~ above = }
 lcol { B + C above D * E above + F * G above H + I }
 lcol { ~ above ~ above ~ above = J }
}
.EN

equation