接口

Sage的一个核心方面是,它支持使用通用接口和干净的编程语言在多个不同的计算机代数系统中“在一个屋檐下”进行对象计算。

接口的控制台方法和交互方法做的事情非常不同。例如,以GAP为例:

  1. gap.console() :这会打开GAP控制台-它会将控制权转移到GAP。在这里,Sage只不过是一个方便的程序启动器,类似于Linux bashShell。

  2. gap.interact() :这是与可能“充满”Sage对象的运行Gap实例进行交互的一种便捷方式。您可以将Sage对象导入到此GAP会话中(甚至从交互界面),等等。

GP/Pari

PARI是一个紧凑、非常成熟、高度优化的C程序,其主要关注点是数论。您可以在Sage中使用两个截然不同的界面:

  • gp --“ G O P Ari“口译员,以及

  • pari -Pari C库。

例如,下面是做同一件事的两种方式。它们看起来一模一样,但输出实际上是不同的,幕后发生的事情也截然不同。

sage: gp('znprimroot(10007)')
Mod(5, 10007)
sage: pari('znprimroot(10007)')
Mod(5, 10007)

在第一种情况下,GP解释器的单独副本作为服务器启动,字符串 'znprimroot(10007)' 被发送给它,由GP计算,结果被赋值给GP中的一个变量(这会在子GP进程中占用不会被释放的内存空间)。然后显示该变量的值。在第二种情况下,不会启动单独的程序,并且字符串 'znprimroot(10007)' 是由某个Pari C库函数计算的。结果存储在Python堆上的一块内存中,当不再引用变量时将释放该内存。这些对象具有不同的类型:

sage: type(gp('znprimroot(10007)'))
<class 'sage.interfaces.gp.GpElement'>
sage: type(pari('znprimroot(10007)'))
<class 'cypari2.gen.Gen'>

那么你应该使用哪一种呢?这取决于你在做什么。Gp接口完全可以做您在通常的gp/pari命令行程序中可以做的任何事情,因为它正在运行该程序。特别是,您可以加载复杂的Pari程序并运行它们。相比之下,Pari接口(通过C库)要严格得多。首先,并不是所有的成员函数都实现了。其次,很多代码,例如涉及数值积分的代码,不能通过Pari接口工作。也就是说,与GP接口相比,Pari接口的速度和健壮性要高得多。

(如果GP接口耗尽了计算给定输入行的内存,它将自动将堆栈大小增加一倍,并重试该输入行。因此,如果您没有正确预测所需的内存量,您的计算就不会崩溃。这是通常的GP解释器似乎没有提供的一个很好的技巧。对于Pari C库接口,它会立即将创建的每个对象从Pari堆栈复制出来,因此堆栈永远不会增长。但是,每个对象的大小不得超过100MB,否则在创建对象时堆栈将溢出。这种额外的复制确实会造成轻微的性能损失。)

总而言之,Sage使用Pari C库提供与GP/Pari解释器类似的功能,只是使用了不同的复杂内存管理和Python编程语言。

首先,我们从一个Python列表创建一个Pari列表。

sage: v = pari([1,2,3,4,5])
sage: v
[1, 2, 3, 4, 5]
sage: type(v)
<class 'cypari2.gen.Gen'>

每个Pari对象都是类型 Gen 。基础对象的pari类型可以使用 type 成员函数。

sage: v.type()
't_VEC'

在Pari中,为了创建一条椭圆曲线,我们输入 ellinit([1,2,3,4,5]) 。Sage是相似的,除了 ellinit 是可以在任何Pari对象上调用的方法,例如,我们的 t_VEC v

sage: e = v.ellinit()
sage: e.type()
't_VEC'
sage: pari(e)[:13]
[1, 2, 3, 4, 5, 9, 11, 29, 35, -183, -3429, -10351, 6128487/10351]

现在我们有了一个椭圆曲线对象,我们可以计算一些关于它的东西。

sage: e.elltors()
[1, [], []]
sage: e.ellglobalred()
[10351, [1, -1, 0, -1], 1, [11, 1; 941, 1], [[1, 5, 0, 1], [1, 5, 0, 1]]]
sage: f = e.ellchangecurve([1,-1,0,-1])
sage: f[:5]
[1, -1, 0, 4, 3]

GAP

SAGE伴随着计算离散数学,尤其是群论的发展。

下面是GAP的一个例子 IdGroup 功能。

sage: G = gap('Group((1,2,3)(4,5), (3,4))')
sage: G
Group( [ (1,2,3)(4,5), (3,4) ] )
sage: G.Center()
Group( () )
sage: G.IdGroup()
[ 120, 34 ]
sage: G.Order()
120

我们可以在Sage中执行相同的计算,而无需显式调用Gap接口,如下所示:

sage: G = PermutationGroup([[(1,2,3),(4,5)],[(3,4)]])
sage: G.center()
Subgroup generated by [()] of (Permutation Group with generators [(3,4), (1,2,3)(4,5)])
sage: G.group_id()
[120, 34]
sage: n = G.order(); n
120

对于某些GAP功能,您应该安装可选的Sage包。这可以使用命令::

sage -i gap_packages

单数

Singular为Gröbner基、多元多项式GCDS、平面曲线的Riemann-Roch空间的基和因式分解等提供了一个庞大而成熟的库。我们演示了使用Sage接口将多元多项式因式分解为Single(不要键入 ....: ):

sage: R1 = singular.ring(0, '(x,y)', 'dp')
sage: R1
polynomial ring, over a field, global ordering
//   coefficients: QQ
//   number of vars : 2
//        block   1 : ordering dp
//                  : names    x y
//        block   2 : ordering C
sage: f = singular('9*y^8 - 9*x^2*y^7 - 18*x^3*y^6 - 18*x^5*y^6 +'
....:     '9*x^6*y^4 + 18*x^7*y^5 + 36*x^8*y^4 + 9*x^10*y^4 - 18*x^11*y^2 -'
....:     '9*x^12*y^3 - 18*x^13*y^2 + 9*x^16')

现在我们已经定义了 \(f\) ,我们将其打印出来,并将其考虑在内。

sage: f
9*x^16-18*x^13*y^2-9*x^12*y^3+9*x^10*y^4-18*x^11*y^2+36*x^8*y^4+18*x^7*y^5-18*x^5*y^6+9*x^6*y^4-18*x^3*y^6-9*x^2*y^7+9*y^8
sage: f.parent()
Singular
sage: F = f.factorize(); F
[1]:
   _[1]=9
   _[2]=x^6-2*x^3*y^2-x^2*y^3+y^4
   _[3]=-x^5+y^2
[2]:
   1,1,2
sage: F[1][2]
x^6-2*x^3*y^2-x^2*y^3+y^4

与中的GAP示例一样 GAP ,我们可以在不显式使用奇异接口的情况下计算上述因式分解(然而,在幕后,Sage使用奇异接口进行实际计算)。请勿键入 ....:

sage: x, y = QQ['x, y'].gens()
sage: f = (9*y^8 - 9*x^2*y^7 - 18*x^3*y^6 - 18*x^5*y^6 + 9*x^6*y^4
....:     + 18*x^7*y^5 + 36*x^8*y^4 + 9*x^10*y^4 - 18*x^11*y^2 - 9*x^12*y^3
....:     - 18*x^13*y^2 + 9*x^16)
sage: factor(f)
(9) * (-x^5 + y^2)^2 * (x^6 - 2*x^3*y^2 - x^2*y^3 + y^4)

最大值

MAXIMA包含在Sage中,还提供了一个Lisp实现。Gnplot包(Maxima默认使用它进行绘图)是作为Sage可选包分发的。除了其他事情,马克西马还进行符号操作。极大值可以对函数进行符号积分和微分,可以求解一阶常微分方程组、大多数线性二阶常微分方程组,并实现了任意阶线性常微分方程组的拉普拉斯变换法。Maxima还了解广泛的特殊函数,具有通过gnplot绘制图形的功能,并具有求解和操作矩阵(如行缩减、特征值和特征向量)和多项式方程的方法。

我们通过构造矩阵来说明Sage/Maxima接口 \(i,j\) 条目为 \(i/j\) ,用于 \(i,j=1,\ldots,4\)

sage: f = maxima.eval('ij_entry[i,j] := i/j')
sage: A = maxima('genmatrix(ij_entry,4,4)'); A
matrix([1,1/2,1/3,1/4],[2,1,2/3,1/2],[3,3/2,1,3/4],[4,2,4/3,1])
sage: A.determinant()
0
sage: A.echelon()
matrix([1,1/2,1/3,1/4],[0,0,0,0],[0,0,0,0],[0,0,0,0])
sage: A.eigenvalues()
[[0,4],[3,1]]
sage: A.eigenvectors().sage()
[[[0, 4], [3, 1]], [[[1, 0, 0, -4], [0, 1, 0, -2], [0, 0, 1, -4/3]], [[1, 2, 3, 4]]]]

下面是另一个例子:

sage: A = maxima("matrix ([1, 0, 0], [1, -1, 0], [1, 3, -2])")
sage: eigA = A.eigenvectors()
sage: V = VectorSpace(QQ,3)
sage: eigA
[[[-2,-1,1],[1,1,1]],[[[0,0,1]],[[0,1,3]],[[1,1/2,5/6]]]]
sage: v1 = V(sage_eval(repr(eigA[1][0][0]))); lambda1 = eigA[0][0][0]
sage: v2 = V(sage_eval(repr(eigA[1][1][0]))); lambda2 = eigA[0][0][1]
sage: v3 = V(sage_eval(repr(eigA[1][2][0]))); lambda3 = eigA[0][0][2]

sage: M = MatrixSpace(QQ,3,3)
sage: AA = M([[1,0,0],[1, - 1,0],[1,3, - 2]])
sage: b1 = v1.base_ring()
sage: AA*v1 == b1(lambda1)*v1
True
sage: b2 = v2.base_ring()
sage: AA*v2 == b2(lambda2)*v2
True
sage: b3 = v3.base_ring()
sage: AA*v3 == b3(lambda3)*v3
True

最后,我们给出了一个使用Sage进行绘图的例子 openmath 。其中许多是从Maxima参考手册修改而来的。

多个函数的2D图(请勿键入 ....: ):

sage: maxima.plot2d('[cos(7*x),cos(23*x)^4,sin(13*x)^3]','[x,0,1]',  # not tested
....:     '[plot_format,openmath]')

可以用鼠标移动的“实时”3D绘图(不要键入 ....: ):

sage: maxima.plot3d ("2^(-u^2 + v^2)", "[u, -3, 3]", "[v, -2, 2]",  # not tested
....:     '[plot_format, openmath]')
sage: maxima.plot3d("atan(-x^2 + y^3/4)", "[x, -4, 4]", "[y, -4, 4]",  # not tested
....:     "[grid, 50, 50]",'[plot_format, openmath]')

下一个情节是著名的莫比乌斯地带(不要键入 ....: ):

sage: maxima.plot3d("[cos(x)*(3 + y*cos(x/2)), sin(x)*(3 + y*cos(x/2)), y*sin(x/2)]",  # not tested
....:     "[x, -4, 4]", "[y, -4, 4]", '[plot_format, openmath]')

下一个情节是著名的克莱因瓶子(不要输入 ....: ):

sage: maxima("expr_1: 5*cos(x)*(cos(x/2)*cos(y) + sin(x/2)*sin(2*y)+ 3.0) - 10.0")
5*cos(x)*(sin(x/2)*sin(2*y)+cos(x/2)*cos(y)+3.0)-10.0
sage: maxima("expr_2: -5*sin(x)*(cos(x/2)*cos(y) + sin(x/2)*sin(2*y)+ 3.0)").sage()
-5*(cos(1/2*x)*cos(y) + sin(1/2*x)*sin(2*y) + 3.0)*sin(x)
sage: maxima("expr_3: 5*(-sin(x/2)*cos(y) + cos(x/2)*sin(2*y))")
5*(cos(x/2)*sin(2*y)-sin(x/2)*cos(y))
sage: maxima.plot3d ("[expr_1, expr_2, expr_3]", "[x, -%pi, %pi]",  # not tested
....:     "[y, -%pi, %pi]", "['grid, 40, 40]", '[plot_format, openmath]')