Sage, LaTeX 及其朋友们

Sage 与 TeX 的 LaTeX 方言之间存在着密切的协同关系。 本节旨在介绍各种交互方式,从最基本的开始,然后介绍一些不常见的用法。

基本使用

Sage 中的每个“对象”都必须有 LaTeX 表示。你可以通过执行 latex(foo) 来获取这种表示, 其中 foo 是 Sage 中的某个对象。输出是一个字符串,当在 TeX 的数学模式中使用时 (例如,包围在一对单美元符号之间),该字符串应该能够准确地呈现 foo。以下是一些示例。

sage: var('z')
z
sage: latex(z^12)
z^{12}
sage: latex(sqrt(z^2 + 1/2))
\sqrt{z^{2} + \frac{1}{2}}
sage: latex('a string')
\text{\texttt{a{ }string}}
sage: latex(QQ)
\Bold{Q}
sage: latex(ZZ['x'])
\Bold{Z}[x]
sage: latex(matrix(QQ, 2, 3, [[2,4,6],[-1,-1,-1]]))
\left(\begin{array}{rrr}
2 & 4 & 6 \\
-1 & -1 & -1
\end{array}\right)
>>> from sage.all import *
>>> var('z')
z
>>> latex(z**Integer(12))
z^{12}
>>> latex(sqrt(z**Integer(2) + Integer(1)/Integer(2)))
\sqrt{z^{2} + \frac{1}{2}}
>>> latex('a string')
\text{\texttt{a{ }string}}
>>> latex(QQ)
\Bold{Q}
>>> latex(ZZ['x'])
\Bold{Z}[x]
>>> latex(matrix(QQ, Integer(2), Integer(3), [[Integer(2),Integer(4),Integer(6)],[-Integer(1),-Integer(1),-Integer(1)]]))
\left(\begin{array}{rrr}
2 & 4 & 6 \\
-1 & -1 & -1
\end{array}\right)

通过这种方式,Sage 可以有效地用于构建 LaTeX 文档的各个部分: 在 Sage 中创建或计算一个对象 foo,对该对象执行 latex(foo), 然后将 LaTeX 字符串剪切并粘贴到你的文档中。

命令 view(foo) 会显示对象 foo 的渲染后的 LaTeX 表示。 在后台,该命令会运行 latex(foo) 并将 LaTeX 字符串合并到一个简单的 LaTeX 文档中, 用系统范围内的 TeX 安装处理该文档,然后调用合适的查看器来显示输出。

在 Jupyter Notebook 中,你可以自动看到输入命令输出的渲染 LaTeX 表示。 你可以通过执行 %display latex 来启动自动渲染(并通过执行 %display plain 停止)。

因此,在 Jupyter notebook 中,你得到

%display latex
var('z')
z^12
\(\displaystyle z^{12}\)
sqrt(z^2 + 1/2)
\(\displaystyle \sqrt{z^{2} + \frac{1}{2}}\)
'a string'
\(\displaystyle \verb|a|\verb| |\verb|string|\)
QQ
\(\displaystyle \newcommand{\Bold}[1]{\mathbf{#1}}\Bold{Q}\)
ZZ['x']
\(\displaystyle \newcommand{\Bold}[1]{\mathbf{#1}}\Bold{Z}[x]\)
matrix(QQ, 2, 3, [[2,4,6],[-1,-1,-1]])
\(\displaystyle \left(\begin{array}{rrr} 2 & 4 & 6 \\ -1 & -1 & -1 \end{array}\right)\)
%display plain

Jupyter Notebook 使用 MathJax 在网页浏览器中清晰地渲染数学内容。 MathJax 是一个开源的 JavaScript 数学显示引擎,可以在所有现代浏览器中使用。 它能够渲染大部分 LaTex,但并不支持完整的 LaTeX,是 LaTex 的子集。 它不支持复杂表格、分段或文档管理,因为它主要用于准确渲染 LaTeX 数学片段。

在 Jupyter Notebook 中自动 LaTeX 渲染(启用 %display latex) 是通过 sage.misc.html.MathJax 类内部实现的。 该类的对象将 Sage 对象通过 latex() 转换为 MathJax 需要的 HTML 形式,然后将其包装在 HTML 中。

sage: from sage.misc.html import MathJax
sage: mj = MathJax()
sage: var('z')
z
sage: mj(z^12)
<html>\[z^{12}\]</html>
sage: mj(sqrt(z^2 + 1/2))
<html>\[\sqrt{z^{2} + \frac{1}{2}}\]</html>
sage: mj('a string')
<html>\[\verb|a|\verb| |\verb|string|\]</html>
sage: mj(QQ)
<html>\[\newcommand{\Bold}[1]{\mathbf{#1}}\Bold{Q}\]</html>
sage: mj(ZZ['x'])
<html>\[\newcommand{\Bold}[1]{\mathbf{#1}}\Bold{Z}[x]\]</html>
sage: mj(matrix(QQ, 2, 3, [[2,4,6],[-1,-1,-1]]))
<html>\[\left(\begin{array}{rrr}
2 & 4 & 6 \\
-1 & -1 & -1
\end{array}\right)\]</html>
>>> from sage.all import *
>>> from sage.misc.html import MathJax
>>> mj = MathJax()
>>> var('z')
z
>>> mj(z**Integer(12))
<html>\[z^{12}\]</html>
>>> mj(sqrt(z**Integer(2) + Integer(1)/Integer(2)))
<html>\[\sqrt{z^{2} + \frac{1}{2}}\]</html>
>>> mj('a string')
<html>\[\verb|a|\verb| |\verb|string|\]</html>
>>> mj(QQ)
<html>\[\newcommand{\Bold}[1]{\mathbf{#1}}\Bold{Q}\]</html>
>>> mj(ZZ['x'])
<html>\[\newcommand{\Bold}[1]{\mathbf{#1}}\Bold{Z}[x]\]</html>
>>> mj(matrix(QQ, Integer(2), Integer(3), [[Integer(2),Integer(4),Integer(6)],[-Integer(1),-Integer(1),-Integer(1)]]))
<html>\[\left(\begin{array}{rrr}
2 & 4 & 6 \\
-1 & -1 & -1
\end{array}\right)\]</html>

如果你需要了解 Sage 对象的 LaTeX 渲染,那么了解这一点很有用。

自定义 LaTeX 生成

有几种方法可以自定义由 latex() 命令生成的实际 LaTeX 代码。 预定义对象 latex 包含多个方法,可以通过输入 latex. (注意这里有一个点)后按 Tab 键来列出这些方法。

latex.matrix_delimiters 方法是一个很好的例子。 它可以用来更改矩阵周围的符号 -- 大括号、方括号、花括号、竖线。 不强制执行任何样式,你可以随意混合搭配。 注意,LaTeX 所需的反斜杠在 Python 字符串中需要额外加一个斜杠以便正确转义。

sage: A = matrix(ZZ, 2, 2, range(4))
sage: latex(A)
\left(\begin{array}{rr}
0 & 1 \\
2 & 3
\end{array}\right)
sage: latex.matrix_delimiters(left='[', right=']')
sage: latex(A)
\left[\begin{array}{rr}
0 & 1 \\
2 & 3
\end{array}\right]
sage: latex.matrix_delimiters(left='\\{', right='\\}')
sage: latex(A)
\left\{\begin{array}{rr}
0 & 1 \\
2 & 3
\end{array}\right\}
>>> from sage.all import *
>>> A = matrix(ZZ, Integer(2), Integer(2), range(Integer(4)))
>>> latex(A)
\left(\begin{array}{rr}
0 & 1 \\
2 & 3
\end{array}\right)
>>> latex.matrix_delimiters(left='[', right=']')
>>> latex(A)
\left[\begin{array}{rr}
0 & 1 \\
2 & 3
\end{array}\right]
>>> latex.matrix_delimiters(left='\\{', right='\\}')
>>> latex(A)
\left\{\begin{array}{rr}
0 & 1 \\
2 & 3
\end{array}\right\}

latex.vector_delimiters 方法的工作原理与之类似。

常见环和域(整数、有理数、实数等)的排版方式可以通过 latex.blackboard_bold 方法来控制。 这些集合默认以粗体排版,但有时可以选择以双重划线格式书写,如某些书面作品所做的那样。 这可以通过重新定义 Sage 内置的 \Bold{} 宏来实现。

sage: latex(QQ)
\Bold{Q}
sage: from sage.misc.html import MathJax
sage: mj = MathJax()
sage: mj(QQ)
<html>\[\newcommand{\Bold}[1]{\mathbf{#1}}\Bold{Q}\]</html>
sage: latex.blackboard_bold(True)
sage: mj(QQ)
<html>\[\newcommand{\Bold}[1]{\mathbb{#1}}\Bold{Q}\]</html>
sage: latex.blackboard_bold(False)
>>> from sage.all import *
>>> latex(QQ)
\Bold{Q}
>>> from sage.misc.html import MathJax
>>> mj = MathJax()
>>> mj(QQ)
<html>\[\newcommand{\Bold}[1]{\mathbf{#1}}\Bold{Q}\]</html>
>>> latex.blackboard_bold(True)
>>> mj(QQ)
<html>\[\newcommand{\Bold}[1]{\mathbb{#1}}\Bold{Q}\]</html>
>>> latex.blackboard_bold(False)

在 Jupyter notebook 中,

%display latex
QQ
\(\displaystyle \newcommand{\Bold}[1]{\mathbf{#1}}\Bold{Q}\)
latex.blackboard_bold(True)
QQ
\(\displaystyle \newcommand{\Bold}[1]{\mathbb{#1}}\Bold{Q}\)
latex.blackboard_bold(False)
%display plain

可以通过加入新的宏来利用 LaTeX 的可扩展性。可以添加单个宏,以便在 MathJax 解释 LaTeX 片段时使用。

sage: latex.add_macro(r"\newcommand{\sqrt}[1]{(#1)^\frac{1}{2}}")
sage: latex.extra_macros()
'\\newcommand{\\sqrt}[1]{(#1)^\\frac{1}{2}}'
sage: var('x y')
(x, y)
sage: latex(sqrt(x+y))
\sqrt{x + y}
sage: from sage.misc.html import MathJax
sage: mj = MathJax()
sage: mj(sqrt(x + y))
<html>\[\newcommand{\sqrt}[1]{(#1)^\frac{1}{2}}\sqrt{x + y}\]</html>
sage: latex.extra_macros('')
>>> from sage.all import *
>>> latex.add_macro(r"\newcommand{\sqrt}[1]{(#1)^\frac{1}{2}}")
>>> latex.extra_macros()
'\\newcommand{\\sqrt}[1]{(#1)^\\frac{1}{2}}'
>>> var('x y')
(x, y)
>>> latex(sqrt(x+y))
\sqrt{x + y}
>>> from sage.misc.html import MathJax
>>> mj = MathJax()
>>> mj(sqrt(x + y))
<html>\[\newcommand{\sqrt}[1]{(#1)^\frac{1}{2}}\sqrt{x + y}\]</html>
>>> latex.extra_macros('')

在 Jupyter notebook 中,

%display latex
var('x y')
sqrt(x + y)
\(\displaystyle \sqrt{x + y}\)
latex.add_macro(r"\newcommand{\sqrt}[1]{(#1)^\frac{1}{2}}")
sqrt(x + y)
\(\displaystyle \newcommand{\sqrt}[1]{(#1)^\frac{1}{2}}\sqrt{x + y}\)
latex.extra_macros('')
%display plain

自定义 LaTeX 处理

系统范围内的 TeX 被调用来处理完整的 LaTeX 文档,例如,当你 view(foo) 时, 其中 foo 是一个复杂的 Sage 对象,太复杂以至于 MathJax 无法处理。 命令 latex_extra_preamble 用于构建完整 LaTeX 文档的导言部分,下面将展示如何完成这项工作。 如往常一样,请注意 Python 字符串中需要双反斜杠。

sage: latex.extra_macros('')
sage: latex.extra_preamble('')
sage: from sage.misc.latex import latex_extra_preamble
sage: print(latex_extra_preamble())
\newcommand{\ZZ}{\Bold{Z}}
...
\newcommand{\Bold}[1]{\mathbf{#1}}
sage: latex.add_macro("\\newcommand{\\foo}{bar}")
sage: print(latex_extra_preamble())
\newcommand{\ZZ}{\Bold{Z}}
...
\newcommand{\Bold}[1]{\mathbf{#1}}
\newcommand{\foo}{bar}
>>> from sage.all import *
>>> latex.extra_macros('')
>>> latex.extra_preamble('')
>>> from sage.misc.latex import latex_extra_preamble
>>> print(latex_extra_preamble())
\newcommand{\ZZ}{\Bold{Z}}
...
\newcommand{\Bold}[1]{\mathbf{#1}}
>>> latex.add_macro("\\newcommand{\\foo}{bar}")
>>> print(latex_extra_preamble())
\newcommand{\ZZ}{\Bold{Z}}
...
\newcommand{\Bold}[1]{\mathbf{#1}}
\newcommand{\foo}{bar}

同样,对于更大或更复杂的 LaTeX 表达式,可以将包(或其他任意内容)添加到 LaTeX 文件的导言部分。 任意内容都可以通过 latex.add_to_preamble 命令加入导言部分, 专用命令 latex.add_package_to_preamble_if_available 会首先检查某个包是否实际存在, 然后尝试将其添加到导言部分。

这里我们将几何包添加到导言部分并用它来设置 TeX 将在页面上使用的区域尺寸(有效地设置边距)。 如往常一样,请注意 Python 字符串中需要双反斜杠。

sage: from sage.misc.latex import latex_extra_preamble
sage: latex.extra_macros('')
sage: latex.extra_preamble('')
sage: latex.add_to_preamble('\\usepackage{geometry}')
sage: latex.add_to_preamble('\\geometry{letterpaper,total={8in,10in}}')
sage: latex.extra_preamble()
'\\usepackage{geometry}\\geometry{letterpaper,total={8in,10in}}'
sage: print(latex_extra_preamble())
\usepackage{geometry}\geometry{letterpaper,total={8in,10in}}
\newcommand{\ZZ}{\Bold{Z}}
...
\newcommand{\Bold}[1]{\mathbf{#1}}
>>> from sage.all import *
>>> from sage.misc.latex import latex_extra_preamble
>>> latex.extra_macros('')
>>> latex.extra_preamble('')
>>> latex.add_to_preamble('\\usepackage{geometry}')
>>> latex.add_to_preamble('\\geometry{letterpaper,total={8in,10in}}')
>>> latex.extra_preamble()
'\\usepackage{geometry}\\geometry{letterpaper,total={8in,10in}}'
>>> print(latex_extra_preamble())
\usepackage{geometry}\geometry{letterpaper,total={8in,10in}}
\newcommand{\ZZ}{\Bold{Z}}
...
\newcommand{\Bold}[1]{\mathbf{#1}}

可以通过检查其存在性来添加特定包,以下示例展示了这种情况。作为示例,我们将尝试向导言部分添加一个可能不存在的包。

sage: latex.extra_preamble('')
sage: latex.extra_preamble()
''
sage: latex.add_to_preamble('\\usepackage{foo-bar-unchecked}')
sage: latex.extra_preamble()
'\\usepackage{foo-bar-unchecked}'
sage: latex.add_package_to_preamble_if_available('foo-bar-checked')
sage: latex.extra_preamble()
'\\usepackage{foo-bar-unchecked}'
>>> from sage.all import *
>>> latex.extra_preamble('')
>>> latex.extra_preamble()
''
>>> latex.add_to_preamble('\\usepackage{foo-bar-unchecked}')
>>> latex.extra_preamble()
'\\usepackage{foo-bar-unchecked}'
>>> latex.add_package_to_preamble_if_available('foo-bar-checked')
>>> latex.extra_preamble()
'\\usepackage{foo-bar-unchecked}'

使用哪种 TeX 方言,以及输出和相关查看器的性质,也可以定制。

备注

Sage 几乎包括了构建和使用 Sage 所需的一切,但一个重要的例外是 TeX 本身。 因此,在以下情况下,你需要安装完整的 TeX 系统以及一些相关的转换工具。 许多版本的 Linux 都有基于 TeXLive 的软件包,macOS 有 MacTeX,Windows 有 MiKTeX。

可以使用 latex.engine() 命令控制是否使用系统范围内的 latex, pdflatexxelatex 可执行文件。 当调用 view() 并且引擎设置为 latex 时,会生成一个 dvi 文件,Sage 会使用 dvi 查看器(如 xdvi)来显示结果。 相比之下,当引擎设置为 pdflatex 时,调用 view() 会生成 PDF 文件, 并且 Sage 会调用系统的 PDF 文件查看工具(如 acrobat, okular, evince 等)。

对于使用这些工具的练习,有一些预先打包好的示例。 要使用这些示例,需要导入 sage.misc.latex.latex_examples 对象, 这是 sage.misc.latex.LatexExamples 类的一个实例,如下所示。 目前该类有交换图、组合图、扭结理论和 pstricks 的示例,分别使用以下包:xy,tkz-graph,xypic,pstricks。 导入后,对 latex_examples 使用 tab 补全查看内置示例。 调用每个示例会返回一些关于如何正确呈现该示例的说明。要实际查看示例,需要使用 view(foo) (导言部分、引擎等均设置正确)。

sage: from sage.misc.latex import latex_examples
sage: foo = latex_examples.diagram()
sage: foo
LaTeX example for testing display of a commutative diagram produced
by xypic.

To use, try to view this object -- it will not work.  Now try
'latex.add_to_preamble("\\usepackage[matrix,arrow,curve,cmtip]{xy}")',
and try viewing again. You should get a picture (a part of the diagram arising
from a filtered chain complex).
>>> from sage.all import *
>>> from sage.misc.latex import latex_examples
>>> foo = latex_examples.diagram()
>>> foo
LaTeX example for testing display of a commutative diagram produced
by xypic.
<BLANKLINE>
To use, try to view this object -- it will not work.  Now try
'latex.add_to_preamble("\\usepackage[matrix,arrow,curve,cmtip]{xy}")',
and try viewing again. You should get a picture (a part of the diagram arising
from a filtered chain complex).

为了展示如何处理复杂的 LaTeX 表达式,让我们看一下使用 tkz-graph LaTeX 包的组合图示例。

备注

tkz-graph LaTeX 包建立在 pgf 库的 tikz 前端之上。 渲染组合图需要 pgf 库以及文件 tkz-graph.stytkz-berge.sty。 它们很可能已经是系统范围内 TeX 安装的一部分。即使不是,也应当很容易找到安装指南。

首先,我们通过将相关包添加到 LaTeX 文档的导言部分来确保它们被包含在内。

sage: latex.extra_preamble('\\usepackage{tikz}\n\\usepackage{tkz-graph}\n'
....:                      '\\usepackage{tkz-berge}\n\\usetikzlibrary{arrows,shapes}')
>>> from sage.all import *
>>> latex.extra_preamble('\\usepackage{tikz}\n\\usepackage{tkz-graph}\n'
...                      '\\usepackage{tkz-berge}\n\\usetikzlibrary{arrows,shapes}')

当使用 dvi 文件作为中间格式时,图形无法正确生成,因此最好将 LaTeX 引擎设置为 pdflatex 可执行文件。

sage: latex.engine('pdflatex')
>>> from sage.all import *
>>> latex.engine('pdflatex')

此时,像 view(graphs.CompleteGraph(4)) 这样的命令应该生成一个带有完整图 \(K_4\) 适当图像的 PDF。

实际上,可以省略前面的步骤,因为导言部分会自动正确设置,并且 pdflatex 是 Sage 的默认 LaTeX 引擎。 重新启动 Sage 后再次尝试该命令。

注意,通过 tkz-graph 有多种选项可以影响 LaTeX 中图形的呈现方式,这超出了本节的范围。 请参阅参考手册 LaTeX options for graphs 章节获取指令和详细信息。

SageTeX

SageTeX 是一个可以进一步集成 TeX 和 Sage 的程序。 它是一组 TeX 宏,允许 LaTeX 文档包含指令,让 Sage 计算各种对象并使用 latex() 格式化对象。 更多信息请参见 使用 SageTeX