交互式 Shell

在本教程的大部分内容中,我们假定你使用 sage 命令启动 Sage 解释器。 这将启动一个定制版的 IPython Shell,并导入许多函数和类,使它们可以直接从命令提示符使用。 可以通过编辑 $SAGE_ROOT/ipythonrc 文件进行进一步的自定义。 启动 Sage 后,会输出以下类似内容:

┌────────────────────────────────────────────────────────────────────┐
│ SageMath version 9.7, Release Date: 2022-01-10                     │
│ Using Python 3.10.4. Type "help()" for help.                       │
└────────────────────────────────────────────────────────────────────┘


sage:

要退出 Sage 只需按 Ctrl-D 或输入 quitexit

sage: quit
Exiting Sage (CPU time 0m0.00s, Wall time 0m0.89s)
>>> from sage.all import *
>>> quit
Exiting Sage (CPU time 0m0.00s, Wall time 0m0.89s)

Wall time 指的是墙上的挂钟走过的时间。因为 CPU 时间不会跟踪子进程(如 GAP 或 Singular)消耗的时间。

(请避免在终端中使用 kill -9 杀死 Sage 进程, 因为 Sage 可能无法终止子进程,例如 Maple 进程,或清理 $HOME/.sage/tmp 中的临时文件。)

Sage 会话

会话是从 Sage 启动到退出期间的输入输出序列。Sage 通过IPython 记录所有 Sage 输入。 实际上,如果你使用的是交互式 Shell(而不是 notebook 界面), 你可以随时输入 %history (或 %hist)来列出迄今为止输入的所有命令行。 在 Sage 提示符下输入 ? 可以了解有关 IPython 的更多信息,例如, “IPython 提供带编号的提示符...并缓存输入和输出。所有输入都会保存, 并且可以作为变量检索(除了常用的箭头键召回外)。以下全局变量始终存在(所以不要覆盖它们!)”:

_:  上一次输入 (交互式 SHell 和 notebook 均适用)
__: 上两次输入 (仅交互式 Shell 适用)
_oh : 所有输入的列表 (仅交互式 Shell 适用)

例如:

sage: factor(100)
 _1 = 2^2 * 5^2
sage: kronecker_symbol(3,5)
 _2 = -1
sage: %hist   # This only works from the interactive shell, not the notebook.
1: factor(100)
2: kronecker_symbol(3,5)
3: %hist
sage: _oh
 _4 = {1: 2^2 * 5^2, 2: -1}
sage: _i1
 _5 = 'factor(ZZ(100))\n'
sage: eval(_i1)
 _6 = 2^2 * 5^2
sage: %hist
1: factor(100)
2: kronecker_symbol(3,5)
3: %hist
4: _oh
5: _i1
6: eval(_i1)
7: %hist
>>> from sage.all import *
>>> factor(Integer(100))
 _1 = 2^2 * 5^2
>>> kronecker_symbol(Integer(3),Integer(5))
 _2 = -1
>>> %hist   # This only works from the interactive shell, not the notebook.
1: factor(100)
2: kronecker_symbol(3,5)
3: %hist
>>> _oh
 _4 = {1: 2^2 * 5^2, 2: -1}
>>> _i1
 _5 = 'factor(ZZ(100))\n'
>>> eval(_i1)
 _6 = 2^2 * 5^2
>>> %hist
1: factor(100)
2: kronecker_symbol(3,5)
3: %hist
4: _oh
5: _i1
6: eval(_i1)
7: %hist

我们在本教程和其他 Sage 文档中均省略了输出编号。

你还可以在会话中将输入列表储存在宏中。

sage: E = EllipticCurve([1,2,3,4,5])
sage: M = ModularSymbols(37)
sage: %hist
1: E = EllipticCurve([1,2,3,4,5])
2: M = ModularSymbols(37)
3: %hist
sage: %macro em 1-2
Macro `em` created. To execute, type its name (without quotes).
>>> from sage.all import *
>>> E = EllipticCurve([Integer(1),Integer(2),Integer(3),Integer(4),Integer(5)])
>>> M = ModularSymbols(Integer(37))
>>> %hist
1: E = EllipticCurve([1,2,3,4,5])
2: M = ModularSymbols(37)
3: %hist
>>> %macro em Integer(1)-Integer(2)
Macro `em` created. To execute, type its name (without quotes).
sage: E
Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 over
Rational Field
sage: E = 5
sage: M = None
sage: em
Executing Macro...
sage: E
Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 over
Rational Field
>>> from sage.all import *
>>> E
Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 over
Rational Field
>>> E = Integer(5)
>>> M = None
>>> em
Executing Macro...
>>> E
Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 over
Rational Field

在使用交互式 Shell 时,任何 UNIX Shell 命令都可以通过在 Sage 前面加上感叹号 ! 来执行。例如:

sage: !ls
auto  example.sage glossary.tex  t  tmp  tut.log  tut.tex
>>> from sage.all import *
>>> !ls
auto  example.sage glossary.tex  t  tmp  tut.log  tut.tex

返回当前目录的列表。

PATH 变量将 Sage 的 bin 目录放在最前端, 因此如果运行 gp, gap, singular, maxima 等等,你会得到随 Sage 附带的版本。

sage: !gp
Reading GPRC: /etc/gprc ...Done.

                           GP/PARI CALCULATOR Version 2.2.11 (alpha)
                  i686 running linux (ix86/GMP-4.1.4 kernel) 32-bit version
...
sage: !singular
                     SINGULAR                             /  Development
 A Computer Algebra System for Polynomial Computations   /   version 3-0-1
                                                       0<
     by: G.-M. Greuel, G. Pfister, H. Schoenemann        \   October 2005
FB Mathematik der Universitaet, D-67653 Kaiserslautern    \
>>> from sage.all import *
>>> !gp
Reading GPRC: /etc/gprc ...Done.

                           GP/PARI CALCULATOR Version 2.2.11 (alpha)
                  i686 running linux (ix86/GMP-4.1.4 kernel) 32-bit version
...
>>> !singular
                     SINGULAR                             /  Development
 A Computer Algebra System for Polynomial Computations   /   version 3-0-1
                                                       0<
     by: G.-M. Greuel, G. Pfister, H. Schoenemann        \   October 2005
FB Mathematik der Universitaet, D-67653 Kaiserslautern    \

记录输入和输出

记录 Sage 会话不同于保存会话(参见 保存和加载完整会话)。 要记录输入(和可选输出),请使用 logstart 命令。输入 logstart? 了解更多详情。 你可以使用这个命令记录你输入的所有内容、所有输出,甚至可以在未来的会话中重现输入(通过重新加载日志文件)。

was@form:~$ sage
┌────────────────────────────────────────────────────────────────────┐
│ SageMath version 9.7, Release Date: 2022-01-10                     │
│ Using Python 3.10.4. Type "help()" for help.                       │
└────────────────────────────────────────────────────────────────────┘

sage: logstart setup
Activating auto-logging. Current session state plus future input saved.
Filename       : setup
Mode           : backup
Output logging : False
Timestamping   : False
State          : active
sage: E = EllipticCurve([1,2,3,4,5]).minimal_model()
sage: F = QQ^3
sage: x,y = QQ['x,y'].gens()
sage: G = E.gens()
sage:
Exiting Sage (CPU time 0m0.61s, Wall time 0m50.39s).
was@form:~$ sage
┌────────────────────────────────────────────────────────────────────┐
│ SageMath version 9.7, Release Date: 2022-01-10                     │
│ Using Python 3.10.4. Type "help()" for help.                       │
└────────────────────────────────────────────────────────────────────┘

sage: load("setup")
Loading log file <setup> one line at a time...
Finished replaying log file <setup>
sage: E
Elliptic Curve defined by y^2 + x*y  = x^3 - x^2 + 4*x + 3 over Rational
Field
sage: x*y
x*y
sage: G
[(2 : 3 : 1)]

如果你在 Linux KDE 终端 konsole 中使用 Sage,那么可以按照以下步骤保存会话: 在 konsole 中启动 Sage 后,选择“设置”,然后“历史记录...”,然后“设置为无限制”。 当你准备保存会话时,选择“编辑”,然后“保存历史记录为...”,并输入一个名称将会话的文本保存到你的计算机。 保存这个文件后,你可以将其加载到编辑器(例如 xemacs)并打印出来。

粘贴忽略提示符

假设你正在阅读 Sage 或 Python 计算的会话,并希望将它们复制到 Sage 中。 但是有 >>>sage: 提示符很烦人。实际上,你可以将包含提示符的示例复制并粘贴到 Sage 中。 换句话说,默认情况下,Sage 解析器在传递给 Python 之前会删除任何前导 >>>sage: 提示符。例如:

sage: 2^10
1024
sage: sage: sage: 2^10
1024
sage: >>> 2^10
1024
>>> from sage.all import *
>>> Integer(2)**Integer(10)
1024
>>> sage: sage: Integer(2)**Integer(10)
1024
>>> >>> Integer(2)**Integer(10)
1024

命令计时

如果你在输入的开头放置 %time 命令,那么命令执行的时间将显示在输出后。 例如,我们可以比较几种幂运算的运行时间。 这些计时在你电脑上可能会有很大不同,甚至在不同版本的 Sage 之间也会有所不同。 首先是原生 Python:

sage: %time a = int(1938)^int(99484)
CPU times: user 0.66 s, sys: 0.00 s, total: 0.66 s
Wall time: 0.66
>>> from sage.all import *
>>> %time a = int(Integer(1938))**int(Integer(99484))
CPU times: user 0.66 s, sys: 0.00 s, total: 0.66 s
Wall time: 0.66

这意味着总共耗时 0.66 秒,"Wall time" 即墙上挂钟的时间为 0.66 秒。 如果你的计算机负载较重,wall time 可能比 CPU 时间长很多。

还可以使用 timeit 函数来尝试在大量迭代命令下获取时间。 这提供了稍微不同的信息,并且需要输入命令字符串来计时。

sage: timeit("int(1938)^int(99484)")
5 loops, best of 3: 44.8 ms per loop
>>> from sage.all import *
>>> timeit("int(1938)^int(99484)")
5 loops, best of 3: 44.8 ms per loop

接下来我们使用原生 Sage Integer 类型,它是用 Cython 调用 GMP 库实现的:

sage: %time a = 1938^99484
CPU times: user 0.04 s, sys: 0.00 s, total: 0.04 s
Wall time: 0.04
>>> from sage.all import *
>>> %time a = Integer(1938)**Integer(99484)
CPU times: user 0.04 s, sys: 0.00 s, total: 0.04 s
Wall time: 0.04

使用 PARI 的 C 语言接口:

sage: %time a = pari(1938)^pari(99484)
CPU times: user 0.05 s, sys: 0.00 s, total: 0.05 s
Wall time: 0.05
>>> from sage.all import *
>>> %time a = pari(Integer(1938))**pari(Integer(99484))
CPU times: user 0.05 s, sys: 0.00 s, total: 0.05 s
Wall time: 0.05

GMP 表现稍好(预料之中,因为为 Sage 构建的 PARI 版本使用 GMP 进行整数运算)。

还可以使用 cputime 命令计时一组命令块,如下所示:

sage: t = cputime()
sage: a = int(1938)^int(99484)
sage: b = 1938^99484
sage: c = pari(1938)^pari(99484)
sage: cputime(t)                       # somewhat random output
0.64
>>> from sage.all import *
>>> t = cputime()
>>> a = int(Integer(1938))**int(Integer(99484))
>>> b = Integer(1938)**Integer(99484)
>>> c = pari(Integer(1938))**pari(Integer(99484))
>>> cputime(t)                       # somewhat random output
0.64
sage: cputime?
...
    Return the time in CPU second since Sage started, or with optional
    argument t, return the time since time t.
    INPUT:
        t -- (optional) float, time in CPU seconds
    OUTPUT:
        float -- time in CPU seconds
>>> from sage.all import *
>>> cputime?
...
    Return the time in CPU second since Sage started, or with optional
    argument t, return the time since time t.
    INPUT:
        t -- (optional) float, time in CPU seconds
    OUTPUT:
        float -- time in CPU seconds

walltime 命令的行为与 cputime 命令类似,只是它计算的是挂钟时间。

我们也可以用 Sage 包含的计算机代数系统计算上面的幂。以下每种情况下,我们执行一个简单命令以启动该程序的服务器。 最相关的时间是挂钟时间。然而,如果挂钟时间和 CPU 时间之间存在显著差异,则可能表明存在值得优化的性能问题。

sage: time 1938^99484;
CPU times: user 0.01 s, sys: 0.00 s, total: 0.01 s
Wall time: 0.01
sage: gp(0)
0
sage: time g = gp('1938^99484')
CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
Wall time: 0.04
sage: maxima(0)
0
sage: time g = maxima('1938^99484')
CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
Wall time: 0.30
sage: kash(0)
0
sage: time g = kash('1938^99484')
CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
Wall time: 0.04
sage: mathematica(0)
        0
sage: time g = mathematica('1938^99484')
CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
Wall time: 0.03
sage: maple(0)
0
sage: time g = maple('1938^99484')
CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
Wall time: 0.11
sage: libgap(0)
0
sage: time g = libgap.eval('1938^99484;')
CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
Wall time: 1.02
>>> from sage.all import *
>>> time Integer(1938)**Integer(99484);
CPU times: user 0.01 s, sys: 0.00 s, total: 0.01 s
Wall time: 0.01
>>> gp(Integer(0))
0
>>> time g = gp('1938^99484')
CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
Wall time: 0.04
>>> maxima(Integer(0))
0
>>> time g = maxima('1938^99484')
CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
Wall time: 0.30
>>> kash(Integer(0))
0
>>> time g = kash('1938^99484')
CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
Wall time: 0.04
>>> mathematica(Integer(0))
        0
>>> time g = mathematica('1938^99484')
CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
Wall time: 0.03
>>> maple(Integer(0))
0
>>> time g = maple('1938^99484')
CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
Wall time: 0.11
>>> libgap(Integer(0))
0
>>> time g = libgap.eval('1938^99484;')
CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
Wall time: 1.02

注意,在这项测试中 GAP 和 Maxima 最慢(运行在 sage.math.washington.edu 机器上)。 由于 pexpect 接口的开销,将它们与最快的 Sage 相比可能不太公平。

其他 IPython 技巧

如上文所述,Sage 使用 IPython 作为前端,因此你可以使用任何 IPython 的命令和功能。 你可以阅读 完整的 IPython 文档 。 下面是一些有趣的技巧 -- 在 IPython 中,这些被称为 "Magic 命令":

  • 如果你想输入一些复杂代码,可以使用 %edit (或 %eded)打开一个编辑器。 在启动 Sage 之前,请确保 EDITOR 环境变量设置为你喜欢的编辑器 (通过在适当位置如 .profile 文件中放置 export EDITOR=/usr/bin/emacsexport EDITOR=/usr/bin/vim 等)。在 Sage 提示符下执行 %edit 会打开指定的编辑器。 然后在编辑器中你可以定义一个函数:

    def some_function(n):
        return n**2 + 3*n + 2
    

    保存并退出编辑器。在剩下的 Sage 会话期间,你可以使用 some_function。 如果你想修改它,可以在 Sage 提示符下输入 %edit some_function

  • 如果你有一个计算,并且想修改其输出以便用于其他用途,可执行计算并输入 %rep: 这会将上一个命令的输出放置到 Sage 提示符,供你编辑。:

    sage: f(x) = cos(x)
    sage: f(x).derivative(x)
    -sin(x)
    
    >>> from sage.all import *
    >>> __tmp__=var("x"); f = symbolic_expression(cos(x)).function(x)
    >>> f(x).derivative(x)
    -sin(x)
    

    此时如果你在 Sage 提示符下输入 %rep, 你会得到一个新的 Sage 提示符,后面跟着 -sin(x), 光标在行尾。

要了解更多信息,请输入 %quickref 以获得 IPython 快速参考指南。 截止本文撰写时间(2011 年 4 月),Sage 使用的 IPython 版本为 0.9.1, Magic 命令文档 可以在线访问。各种较为高级的 Magic 命令系统的内容记载在 这里

错误与异常

出现问题时,通常会看到 Python “异常”。Python 甚至会尝试给出引发异常的原因。 通常可以看到异常的名称,例如:NameErrorValueError (详细异常列表请参见 Python 库参考 [PyLR] )。例如:

sage: 3_2
------------------------------------------------------------
   File "<console>", line 1
     ZZ(3)_2
           ^
SyntaxError: invalid ...

sage: EllipticCurve([0,infinity])
------------------------------------------------------------
Traceback (most recent call last):
...
TypeError: Unable to coerce Infinity (<class 'sage...Infinity'>) to Rational
>>> from sage.all import *
>>> Integer(3_2)
------------------------------------------------------------
   File "<console>", line 1
     ZZ(3)_2
           ^
SyntaxError: invalid ...

>>> EllipticCurve([Integer(0),infinity])
------------------------------------------------------------
Traceback (most recent call last):
...
TypeError: Unable to coerce Infinity (<class 'sage...Infinity'>) to Rational

有时交互式调试器对理解问题很有用。可以使用 %pdb 切换它(默认是关闭的)。 如果打开调试器,出现异常时会出现提示符 ipdb>。在调试器中,可以打印任意局部变量的状态, 并在执行栈中上下移动。例如:

sage: %pdb
Automatic pdb calling has been turned ON
sage: EllipticCurve([1,infinity])
---------------------------------------------------------------------------
<class 'exceptions.TypeError'>             Traceback (most recent call last)
...

ipdb>
>>> from sage.all import *
>>> %pdb
Automatic pdb calling has been turned ON
>>> EllipticCurve([Integer(1),infinity])
---------------------------------------------------------------------------
<class 'exceptions.TypeError'>             Traceback (most recent call last)
...

ipdb>

ipdb> 提示符下输入 ? 以获取调试器命令列表:

ipdb> ?

Documented commands (type help <topic>):
========================================
EOF    break  commands   debug    h       l     pdef   quit    tbreak
a      bt     condition  disable  help    list  pdoc   r       u
alias  c      cont       down     ignore  n     pinfo  return  unalias
args   cl     continue   enable   j       next  pp     s       up
b      clear  d          exit     jump    p     q      step    w
whatis where

Miscellaneous help topics:
==========================
exec  pdb

Undocumented commands:
======================
retval  rv

输入 Ctrl-D 或 quit 返回 Sage。

反向搜索与 Tab 补全

反向搜索: 输入命令的开头,然后按 Ctrl-p (或直接按上箭头键)查看以前输入的以该命令开头的命令行。 即使你完全退出 Sage 并稍后重新启动,这些功能仍然可以使用。也可以使用 Ctrl-r 通过历史记录进行反向搜索。 所有这些功能均使用 readline 软件包,可在大多数 Linux 版本中使用。

为了演示 Tab 补全,首先创建三维向量空间 \(V=\QQ^3\) 如下:

sage: V = VectorSpace(QQ,3)
sage: V
Vector space of dimension 3 over Rational Field
>>> from sage.all import *
>>> V = VectorSpace(QQ,Integer(3))
>>> V
Vector space of dimension 3 over Rational Field

也可以使用如下更简洁的表示法:

sage: V = QQ^3
>>> from sage.all import *
>>> V = QQ**Integer(3)

然后可以很容易地使用 Tab 补全列出 \(V\) 的所有成员函数。只需输入 V., 然后按键盘上的 Tab 键:

sage: V.[tab key]
V._VectorSpace_generic__base_field
...
V.ambient_space
V.base_field
V.base_ring
V.basis
V.coordinates
...
V.zero_vector
>>> from sage.all import *
>>> V.[tab key]
V._VectorSpace_generic__base_field
...
V.ambient_space
V.base_field
V.base_ring
V.basis
V.coordinates
...
V.zero_vector

如果输入函数的前几个字母,然后按 Tab 键,只会显示以这些字母开头的函数。

sage: V.i[tab key]
V.is_ambient  V.is_dense    V.is_full     V.is_sparse
>>> from sage.all import *
>>> V.i[tab key]
V.is_ambient  V.is_dense    V.is_full     V.is_sparse

如果想知道某函数的作用,例如 coordinates 函数, 输入 V.coordinates? 来获取帮助或 V.coordinates?? 查看源码,如下一节所述。

集成帮助系统

Sage 拥有集成帮助系统。输入函数名后跟 ? 可以查看该函数的文档。

sage: V = QQ^3
sage: V.coordinates?
Type:           instancemethod
Base Class:     <class 'instancemethod'>
String Form:    <bound method FreeModule_ambient_field.coordinates of Vector
space of dimension 3 over Rational Field>
Namespace:      Interactive
File:           /home/was/s/local/lib/python2.4/site-packages/sage/modules/f
ree_module.py
Definition:     V.coordinates(self, v)
Docstring:
    Write v in terms of the basis for self.

    Returns a list c such that if B is the basis for self, then

            sum c_i B_i = v.

    If v is not in self, raises an ArithmeticError exception.

    EXAMPLES:
        sage: M = FreeModule(IntegerRing(), 2); M0,M1=M.gens()
        sage: W = M.submodule([M0 + M1, M0 - 2*M1])
        sage: W.coordinates(2*M0-M1)
        [2, -1]
>>> from sage.all import *
>>> V = QQ**Integer(3)
>>> V.coordinates?
Type:           instancemethod
Base Class:     <class 'instancemethod'>
String Form:    <bound method FreeModule_ambient_field.coordinates of Vector
space of dimension 3 over Rational Field>
Namespace:      Interactive
File:           /home/was/s/local/lib/python2.4/site-packages/sage/modules/f
ree_module.py
Definition:     V.coordinates(self, v)
Docstring:
    Write v in terms of the basis for self.

    Returns a list c such that if B is the basis for self, then

            sum c_i B_i = v.

    If v is not in self, raises an ArithmeticError exception.

    EXAMPLES:
>>> M = FreeModule(IntegerRing(), Integer(2)); M0,M1=M.gens()
>>> W = M.submodule([M0 + M1, M0 - Integer(2)*M1])
>>> W.coordinates(Integer(2)*M0-M1)
        [2, -1]

如上所示,输出告诉你对象的类型,定义它的文件,以及有用的函数描述及示例, 可以将这些示例粘贴到当前会话中。几乎所有这些示例都会定期自动测试,以确保它们正常工作并完全按照描述运行。

另一个非常符合 Sage 开源精神的功能是,如果 f 是一个 Python 函数, 那么输入 f?? 会显示定义 f 的源代码。例如:

sage: V = QQ^3
sage: V.coordinates??
Type:           instancemethod
...
Source:
def coordinates(self, v):
        """
        Write $v$ in terms of the basis for self.
        ...
        """
        return self.coordinate_vector(v).list()
>>> from sage.all import *
>>> V = QQ**Integer(3)
>>> V.coordinates??
Type:           instancemethod
...
Source:
def coordinates(self, v):
        """
        Write $v$ in terms of the basis for self.
        ...
        """
        return self.coordinate_vector(v).list()

这告诉我们 coordinates 函数所做的就是调用 coordinate_vector 函数并将结果转换为列表。 coordinate_vector 函数做什么?

sage: V = QQ^3
sage: V.coordinate_vector??
...
def coordinate_vector(self, v):
        ...
        return self.ambient_vector_space()(v)
>>> from sage.all import *
>>> V = QQ**Integer(3)
>>> V.coordinate_vector??
...
def coordinate_vector(self, v):
        ...
        return self.ambient_vector_space()(v)

coordinate_vector 函数将其输入强制转化环绕空间, 其效果是以 \(V\) 的形式计算 \(v\) 的系数向量。 空间 \(V\) 已经是环绕空间,因为它就是 \(\QQ^3\)。 子空间也有 coordinate_vector 函数,它是不同的。我们创建一个子空间并看到:

sage: V = QQ^3; W = V.span_of_basis([V.0, V.1])
sage: W.coordinate_vector??
...
def coordinate_vector(self, v):
        """
         ...
        """
        # First find the coordinates of v wrt echelon basis.
        w = self.echelon_coordinate_vector(v)
        # Next use transformation matrix from echelon basis to
        # user basis.
        T = self.echelon_to_user_matrix()
        return T.linear_combination_of_rows(w)
>>> from sage.all import *
>>> V = QQ**Integer(3); W = V.span_of_basis([V.gen(0), V.gen(1)])
>>> W.coordinate_vector??
...
def coordinate_vector(self, v):
        """
         ...
        """
        # First find the coordinates of v wrt echelon basis.
        w = self.echelon_coordinate_vector(v)
        # Next use transformation matrix from echelon basis to
        # user basis.
        T = self.echelon_to_user_matrix()
        return T.linear_combination_of_rows(w)

(如果你认为实现效率低下,请注册以帮助优化线性代数。)

你也可以输入 help(command_name)help(class) 来获取给定类的帮助文档(类似 manpage )。

sage: help(VectorSpace)
Help on function VectorSpace in module sage.modules.free_module:

VectorSpace(K, dimension_or_basis_keys=None, sparse=False, inner_product_matrix=None, *,
            with_basis='standard', dimension=None, basis_keys=None, **args)
EXAMPLES:

The base can be complicated, as long as it is a field.

::

    sage: V = VectorSpace(FractionField(PolynomialRing(ZZ,'x')),3)
    sage: V
    Vector space of dimension 3 over Fraction Field of Univariate Polynomial Ring in x
     over Integer Ring
    sage: V.basis()
    [
    (1, 0, 0),
    (0, 1, 0),
--More--
>>> from sage.all import *
>>> help(VectorSpace)
Help on function VectorSpace in module sage.modules.free_module:

VectorSpace(K, dimension_or_basis_keys=None, sparse=False, inner_product_matrix=None, *,
            with_basis='standard', dimension=None, basis_keys=None, **args)
EXAMPLES:

The base can be complicated, as long as it is a field.

::

>>> V = VectorSpace(FractionField(PolynomialRing(ZZ,'x')),Integer(3))
>>> V
    Vector space of dimension 3 over Fraction Field of Univariate Polynomial Ring in x
     over Integer Ring
>>> V.basis()
    [
    (1, 0, 0),
    (0, 1, 0),
--More--

当你输入 q 退出帮助系统时,你的会话内容将保持不变。 帮助列表不会使你的会话变得杂乱,而 function_name? 的输出有时会造成这种情况。 输入 help(module_name) 特别有用。例如,向量空间在 sage.modules.free_module 中定义, 输入 help(sage.modules.free_module) 即可获得有关整个模块的文档。 使用帮助查看文档时,可以通过输入 / 进行搜索,也可以通过输入 ? 反向搜索。

保存和加载单个对象

假设你计算出一个矩阵或更复杂的模符号空间,并希望将其保存以供日后使用。你要怎么办呢? 计算机代数系统采用多种方法来保存单个对象。

  1. 保存游戏: 仅支持保存和加载完整会话(如 GAP、Magma)。

  2. 统一输入输出: 使每个对象都以可读的方式打印(GP/PARI)。

  3. Eval: 轻松在解释器中计算任意代码(如 Singular、PARI)。

由于 Sage 使用 Python,因此采用不同的方法,即每个对象都可以序列化, 转化为一个可以从中恢复该对象的字符串。这与 PARI 的统一输入输出方法精神相似, 只不过对象打印到屏幕的方式不会过于复杂。此外,保存和加载在大多数情况下是完全自动的, 不需要额外编程;这是 Python 的设计特性。

几乎所有 Sage 对象 x 都可以以压缩形式保存到磁盘, 使用 save(x, filename) (或在许多情况下 x.save(filename))。 要加载对象,使用 load(filename)

sage: A = MatrixSpace(QQ,3)(range(9))^2
sage: A
[ 15  18  21]
[ 42  54  66]
[ 69  90 111]
sage: save(A, 'A')
>>> from sage.all import *
>>> A = MatrixSpace(QQ,Integer(3))(range(Integer(9)))**Integer(2)
>>> A
[ 15  18  21]
[ 42  54  66]
[ 69  90 111]
>>> save(A, 'A')

现在你应该退出 Sage 并重新启动。然后便可以恢复 A

sage: A = load('A')
sage: A
[ 15  18  21]
[ 42  54  66]
[ 69  90 111]
>>> from sage.all import *
>>> A = load('A')
>>> A
[ 15  18  21]
[ 42  54  66]
[ 69  90 111]

可以使用同样的方法处理更复杂的对象,如椭圆曲线。缓存对象的所有数据都与对象一同保存。例如:

sage: E = EllipticCurve('11a')
sage: v = E.anlist(100000)              # takes a while
sage: save(E, 'E')
sage: quit
>>> from sage.all import *
>>> E = EllipticCurve('11a')
>>> v = E.anlist(Integer(100000))              # takes a while
>>> save(E, 'E')
>>> quit

E 的存储版占 153K 字节,因为它储存了前 100000 个 \(a_n\).

~/tmp$ ls -l E.sobj
-rw-r--r--  1 was was 153500 2006-01-28 19:23 E.sobj
~/tmp$ sage [...]
sage: E = load('E')
sage: v = E.anlist(100000)              # instant!

(在 Python 中,保存和加载使用 cPickle 模块实现。 具体来说,Sage 对象 x 可以通过 cPickle.dumps(x, 2) 保存。注意 2!)

Sage 无法保存和加载某些其它计算机代数系统(例如 GAP、Singular、Maxima)创建的单个对象。 它们重新加载时状态显示为“无效 (invalid)”。在 GAP 中,虽然许多对象的打印方式可以重新构建, 但很多对象却不行,因此特意不允许从其打印表示进行重建。

sage: a = libgap(2)
sage: a.save('a')
sage: load('a')
Traceback (most recent call last):
...
ValueError: The session in which this object was defined is no longer
running.
>>> from sage.all import *
>>> a = libgap(Integer(2))
>>> a.save('a')
>>> load('a')
Traceback (most recent call last):
...
ValueError: The session in which this object was defined is no longer
running.

GP/PARI 对象可以保存和加载,因为它们的打印表示足以重构它们。

sage: a = gp(2)
sage: a.save('a')
sage: load('a')
2
>>> from sage.all import *
>>> a = gp(Integer(2))
>>> a.save('a')
>>> load('a')
2

保存的对象稍后可以在不同架构或操作系统的计算机上重新加载, 例如,你可以在 32 位 OS X 上保存一个大矩阵,然后在 64 位 Linux 上重新加载它, 计算阶梯形式,然后再保存回去。此外,在许多情况下,即使在不同版本的 Sage 中也能加载对象, 只要该对象的代码没有太大差异。对象的所有属性,以及定义对象的类(但不包括源代码)都会被保存。 如果该类在新版本的 Sage 中不再存在,那么该对象就无法在新版本中重新加载。 但你可以在老版本中加载它,获取其对象字典(使用 x.__dict__),保存该字典,并将其加载到新版本中。

保存为文本

你还可以将对象的 ASCII 文本表示保存到纯文本文件中, 只需以写入模式打开文件并写入对象的字符串表示即可(你也可以通过这种方式写入许多对象)。 写完对象后,关闭文件。

sage: R.<x,y> = PolynomialRing(QQ,2)
sage: f = (x+y)^7
sage: o = open('file.txt','w')
sage: o.write(str(f))
sage: o.close()
>>> from sage.all import *
>>> R = PolynomialRing(QQ,Integer(2), names=('x', 'y',)); (x, y,) = R._first_ngens(2)
>>> f = (x+y)**Integer(7)
>>> o = open('file.txt','w')
>>> o.write(str(f))
>>> o.close()

保存和加载完整会话

Sage 对于保存和加载完整会话有非常灵活的支持。

save_session(sessionname) 命令将所有在当前会话中定义的变量保存为给定 sessionname 的字典。 (在少数情况下,如果某个变量不支持保存,则不会保存到字典。)生成的文件为 .sobj 文件, 可以像保存的其它对象一样加载。加载会话保存的对象时,会得到一个字典,字典的键为变量名,值为对象。

可以使用 load_session(sessionname) 命令将 sessionname 中定义的变量加载到当前会话。 注意,这不会清除当前会话中已经定义的变量;而是合并两个会话。

首先启动 Sage 并定义一些变量。

sage: E = EllipticCurve('11a')
sage: M = ModularSymbols(37)
sage: a = 389
sage: t = M.T(2003).matrix(); t.charpoly().factor()
 _4 = (x - 2004) * (x - 12)^2 * (x + 54)^2
>>> from sage.all import *
>>> E = EllipticCurve('11a')
>>> M = ModularSymbols(Integer(37))
>>> a = Integer(389)
>>> t = M.T(Integer(2003)).matrix(); t.charpoly().factor()
 _4 = (x - 2004) * (x - 12)^2 * (x + 54)^2

接下来保存会话,将上面定义的每个变量保存至文件。然后查看文件,大小约为 3K。

sage: save_session('misc')
Saving a
Saving M
Saving t
Saving E
sage: quit
was@form:~/tmp$ ls -l misc.sobj
-rw-r--r--  1 was was 2979 2006-01-28 19:47 misc.sobj
>>> from sage.all import *
>>> save_session('misc')
Saving a
Saving M
Saving t
Saving E
>>> quit
was@form:~/tmp$ ls -l misc.sobj
-rw-r--r--  1 was was 2979 2006-01-28 19:47 misc.sobj

最后重新启动 Sage,定义一个额外的变量,并加载保存的会话。

sage: b = 19
sage: load_session('misc')
Loading a
Loading M
Loading E
Loading t
>>> from sage.all import *
>>> b = Integer(19)
>>> load_session('misc')
Loading a
Loading M
Loading E
Loading t

每个保存的变量再次可用。此外,变量 b 没有被覆盖。

sage: M
Full Modular Symbols space for Gamma_0(37) of weight 2 with sign 0
and dimension 5 over Rational Field
sage: E
Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational
Field
sage: b
19
sage: a
389
>>> from sage.all import *
>>> M
Full Modular Symbols space for Gamma_0(37) of weight 2 with sign 0
and dimension 5 over Rational Field
>>> E
Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational
Field
>>> b
19
>>> a
389