MuPAD
计算机代数系统 (CAS) 是一种为数学表达式的符号操作而设计的软件包。一个 CAS 应该能够:
执行数值运算,其精度仅受计算机硬件的限制
执行基本微积分:偏微分和全微分;符号和数值积分
求解微分方程(偏微分和全微分方程)
操作幂级数
简化代数表达式
理解标准函数:指数函数、三角函数、双曲函数;特别是它们的导数和反导数,以及它们的幂级数展开
了解一些其他函数:超几何函数、贝塞尔函数
操作矩阵和向量;基本运算、特征系统、行列式、矩阵分解
创建二维和三维图形
以各种形式生成输出:TeX/LaTeX、Fortran、C、HTML、PostScript
与其他软件交互;CAS 应该能够整合用其他语言编写的程序
可扩展:CAS 应该内置某种编程语言,以便用户可以添加更多功能
数论函数:素性测试、模运算、原根查找
正交函数:勒让德函数、切比雪夫函数、拉盖尔函数
图形序列的动画
递推关系求解
MuPAD 是在帕德博恩大学由 Benno Fuchssteiner 领导的团队开发的 CAS。尽管它可能没有其更知名的竞争对手 Maple 和 Mathematica 那样的范围和魅力,但它在深度上与它们相当,在某些方面甚至超越了它们。它的名字是“MultiProcessing Algebra Data Tool”(多处理代数数据工具)的缩写,正如我们将看到的,是对它相当好的描述。
与主要的商业 CAS 相比,MuPAD 被设计成一个开放系统——任何人都可以扩展和添加到它。当前版本是 1.4,于 1998 年 3 月发布。
假设您已在系统上安装了 MuPAD。(稍后我将讨论安装。)现在怎么办?
您可以通过两种方式启动 MuPAD:在控制台中,使用命令
mupad
或者,如果您正在运行 X,则使用命令
xmupad将提供图形界面。如果您已正确安装 MuPAD,那么这两个命令实际上都是 shell 脚本,它们定义了某些环境变量,然后调用实际的可执行文件。
假设您选择了后者。您将获得一个类似于图 1 所示的窗口。
请注意 OpenWindows 的外观和感觉。到目前为止,MuPAD 团队尚未发布使用 Athena 或 Motif 小部件的 Linux 二进制文件,尽管正在准备中。MuPAD 被设计为与 OpenWindows 小部件集一起工作,因此,如果您使用 OpenLook 窗口管理器,它的表现最佳。它的许多附属窗口没有自己的关闭或退出按钮,而是依赖于窗口管理器来实现这一点。对于本文中的所有图形和屏幕截图,我使用了 olvwm:Open Look 虚拟窗口管理器。
您还会注意到菜单相当稀疏;事实上,图形界面提供的功能并不比智能控制台多多少。不要灰心——这里面蕴藏着比表面看起来更多的东西!
为了节省显示过多屏幕截图,我们将回到控制台模式。所有 MuPAD 表达式都以冒号或分号结尾(冒号抑制输出显示),并且语法类似于 Maple 的语法。
当 MuPAD 启动时,会加载一个内核(用 C++ 编写);这定义了许多基本命令、函数和常量。其他命令在专门的库中可用,这些库是用 MuPAD 自己的语言编写的。这些命令必须显式加载:可以单独加载,也可以加载整个库。
我们将从对 MuPAD 的数学经典研究开始
>> 2+2; 4
出色地通过了!现在让我们尝试一些超出普通手持计算器能力范围的问题。
>> 3^(4^5); 37339184874102004353295975418486658822540977678373400775063693172207904061 72652512299936889388039772204687650654314751581087270545921608585813513369 82809187314191748594262580938807019951956404285571818041046681288797402925 51766801234061729839657473161915238672304623512593489605859058828465479354 05059362023765478074427305821445270589887562514528177934133521419207446230 27518729185432862375737063985485319476416926263819972887006907013899256524 297198527698749274196276811060702333710356481如您所见,MuPAD 对处理非常大的整数毫不畏惧。
>> DIGITS:=1000:float(PI); 3.141592653589793238462643383279502884197169399375105820974944592307816406 28620899862803482534211706798214808651328230664709384460955058223172535940 81284811174502841027019385211055596446229489549303819644288109756659334461 28475648233786783165271201909145648566923460348610454326648213393607260249 14127372458700660631558817488152092096282925409171536436789259036001133053 05488204665213841469519415116094330572703657595919530921861173819326117931 05118548074462379962749567351885752724891227938183011949129833673362440656 64308602139494639522473719070217986094370277053921717629317675238467481846 76694051320005681271452635608277857713427577896091736371787214684409012249 53430146549585371050792279689258923542019956112129021960864034418159813629 77477130996051870721134999999837297804995105973173281609631859502445945534 69083026425223082533446850352619311881710100031378387528865875332083814206 17177669147303598253490428755468731159562863882353787593751957781857780532 171226806613001927876611195909216420199DIGITS 值给出了处理浮点值时的有效位数。其默认值为 10,可以设置为 1 到 2^31 - 1 之间的任何值。
>> DIGITS:=100:float(1/997); 0.001003009027081243731193580742226680040120361083249749247743229689067201 604814443329989969909729187562 >> 43^(1/5); 2.121747460841897852639905031079416833442447899377300135845506404964677379 294415637755003497680157377
通用命令 solve 可用于求解所有类型的方程:代数方程、微分方程、递推方程。
>> solve(x^2-4*x+3=0,x); {1, 3} >> sols:=solve(a*x^3+b*x^2+c*x+d=0,x):
我们将抑制输出,因为它相当长,但让我们看看我们可以用它做什么
>> op(sols,1); / 3 / 2 3 3 2 2 \1/2 \ | b c d b | d b c d c b d b c | | | ---- - --- - ----- + | ---- - ----- + ----- + ----- - ------ | |^(1/3) | 2 2 a 3 | 2 3 3 4 4 | | \ 6 a 27 a \ 4 a 6 a 27 a 27 a 108 a / / / 3 / 2 3 3 2 2 \ b | b c d b | d b c d c b d b c | - --- + | ---- - --- - ----- - | ---- - ----- + ----- + ----- - ------ | 3 a | 2 2 a 3 | 2 3 3 4 4 | \ 6 a 27 a \ 4 a 6 a 27 a 27 a 108 a / 1/2 \ | |^(1/3) | /op 命令挑选出子表达式;在本例中,由于结果是一个三元素集合,我们选择了它的第一个元素。
>> generate::TeX(%); "- \\frac{b}{3 a} + \\sqrt[3]{- \\frac{d}{2 a} + \\frac{b c}{6 a^2} - \\fr\ ac{b^3}{27 a^3} + \\sqrt{- \\frac{b c d}{6 a^3} + \\frac{d^2}{4 a^2} + \\f\ rac{c^3}{27 a^3} + \\frac{b^3 d}{27 a^4} - \\frac{b^2 c^2}{108 a^4}}} + \\\ sqrt[3]{- \\frac{d}{2 a} + \\frac{b c}{6 a^2} - \\frac{b^3}{27 a^3} - \\sq\ rt{- \\frac{b c d}{6 a^3} + \\frac{d^2}{4 a^2} + \\frac{c^3}{27 a^3} + \\f\ rac{b^3 d}{27 a^4} - \\frac{b^2 c^2}{108 a^4}}}"TeX 命令是在 MuPAD 启动时不会自动加载的命令之一。要访问它,我们必须给出它在 MuPAD 库中的完整地址。
这里 % 指的是上一个命令的输出。此结果现在可以保存到文件中
>> fprint("solution.tex",%);
MuPAD 还可以求解代数方程组。
>> solve({x+2*y+a*z=-1,a*x-3*y+z=3,2*x-a*y-5*z=2},{x,y,z}); { { 2 2 2 } } { { a - a 3 a - 5 a - 19 11 a - 2 a + 19 } } { { z = --------------, x = ---------------, y = ---------------- } } { { 3 3 3 } } { { a - 17 a - 19 a - 17 a - 19 a - 17 a - 19 } }上述系统是线性的,也可以使用 linsolve 命令同样好地求解。
内核中有一些基本的数论函数;其他函数包含在 numlib 库中。
>> isprime(997); TRUE >> Factor(2^67-1); 193707721 761838257287 >> nextprime(1000000); 1000003 >> powermod(9382471,322973,1298377); 880825 >> phi(nextprime(2^20)-1); 498400
这里 phi 是欧拉总计函数,返回小于且与参数互质的整数的数量。这些函数允许我们执行简单的 RSA 加密和解密。假设我们选择两个素数并计算它们的乘积
>> p:=nextprime(5678); 5683 >> q:=nextprime(6789); 6791 >> N:=p*q; 38593253现在我们必须选择一个与 (p-1)*(q-1) 互质的整数 e;较小的素数就可以;例如 e:=17。
>> e:=17:值 e 和 N 是我们的“公钥”。现在我们找到 d,e 模 (p-1)*(q-1) 的逆。这很容易通过方便的倒数函数重载来完成
>> d:=1/e mod (p-1)*(q-1); 6808373假设有人希望向我们发送消息 M < N;例如
>> M:=24367139;他们可以使用我们的公钥值对其进行加密
>> M1:=powermod(M,e,N); 18476508我们现在可以使用值 d(和 N)对其进行解密
>> powermod(M1,d,N); 24367139这确实是原始消息的值。
我们在上面的方程求解中看到了 MuPAD 符号能力的惊鸿一瞥。但 MuPAD 可以做的远不止这些:各种代数简化;以不同形式重写;部分分式等等。
>> expand((x+2*y-3*z)^4); 4 4 4 3 3 3 3 3 x + 16 y + 81 z + 32 x y + 8 x y - 108 x z - 12 x z - 216 y z - 3 2 2 2 2 2 2 2 96 y z + 216 x y z - 144 x y z - 72 x y z + 24 x y + 54 x z + 2 2 216 y z >> Factor(%); 4 (x + 2 y - 3 z) >> sum(1/(k*(k+2)*(k+4)),k=1..n); 2 3 4 310 n + 337 n + 110 n + 11 n ---------------------------------------- 2 3 4 4800 n + 3360 n + 960 n + 96 n + 2304 >> partfrac(%); 1 1 1 1 --------- - --------- - --------- + --------- + 11/96 8 (n + 3) 8 (n + 1) 8 (n + 2) 8 (n + 4) >> normal(%); 2 3 4 310 n + 337 n + 110 n + 11 n ---------------------------------------- 2 3 4 4800 n + 3360 n + 960 n + 96 n + 2304 >> Factor(%); 2 n (n + 5) (55 n + 11 n + 62) ---------------------------------- 96 (n + 1) (n + 2) (n + 3) (n + 4) >> sum(sin(k*x),k=1..n); (I exp(-I x) - I exp(I x) + I exp(-I n x) - I exp(I n x) - I exp(- I x - I n x) + I exp(I x + I n x)) / 4 - 2 exp(-I x) - 2 exp(I x) >> rewrite(%,sincos); (2 sin(x) + 2 sin(n x) + I cos(x + n x) - 2 sin(x + n x) - I cos(- x - n x) ) / 4 - 4 cos(x)
MuPAD 的微积分技能非常出色。它实现了非常强大的微分、积分和极限算法。
>> diff(x^3,x); 2 3 x >> diff(exp(exp(x)),x$4); 2 3 exp(x) exp(exp(x)) + 7 exp(x) exp(exp(x)) + 6 exp(x) exp(exp(x)) + 4 exp(x) exp(exp(x))
美元运算符 $ 是 MuPAD 的序列运算符。与大多数运算符一样,它是重载的;在导数的上下文中,它被解释为多重导数。我们当然也可以执行偏微分。
>> int(sec(x),x); ln(2 sin(x) + 2) ln(2 - 2 sin(x)) ---------------- - ---------------- 2 2 >> int(cos(x)^3, x=-PI/4..PI/3); 1/2 1/2 5 2 3 3 ------ + ------ 12 8 >> int(E^(-x^2),x=0..0.5); / 1 \ int| --------, x = 0..0.5 | | 2 | | x | \ exp(1) / >> float(%); 0.461281006412792448755702936740453103083759088964291146680472565934983884\ 2952938567126622486999424745如果我们只需要数值结果,那么我们不希望强制 MuPAD 首先尝试符号或精确解。在这种情况下,我们可以使用 hold 命令,该命令返回未评估的输入,但“保持”它以供稍后评估。因此,我们可以输入
>> hold(int(exp(-x^2),x=0..0.5));然后是 float 命令。
幂级数的默认阶数为 6。这可以通过更改 ORDER 的值(类似于上面的 DIGITS),或通过在 series 命令中包含阶数来更改。最后一个包含是可选的。
>> tx:=series(tan(x),x,12); 3 5 7 9 11 x 2 x 17 x 62 x 1382 x 12 x + -- + ---- + ----- + ----- + -------- + O(x ) 3 15 315 2835 155925 >> cx:=series(cos(x),x,12); 2 4 6 8 10 x x x x x 12 1 - -- + -- - --- + ----- - ------- + O(x ) 2 24 720 40320 3628800 >> tx*cx; 3 5 7 9 11 x x x x x 12 x - -- + --- - ---- + ------ - -------- + O(x ) 6 120 5040 362880 39916800
这当然 看起来 像 sin(x) 的级数,但让我们看看 MuPAD 是否将其识别为这样。
>> sx:=series(sin(x),x,12): >> is(tx*cx=sx); TRUE >> type(tx*cx); Puiseux这意味着级数乘积的结果被 MuPAD 识别为“Puiseux”类型的对象;也就是说,一个可能包含分数幂的级数。
MuPAD 也可以处理多项式。
>> p1:=x^8-3*x^5+11*x^4-x^2+17; 4 2 5 8 11 x - x - 3 x + x + 17 >> p2:=x^3-23*x^2-4*x+11; 3 2 x - 4 x - 23 x + 11 >> divide(p1,p2); 2 3 4 5 285641 x + 12337 x + 533 x + 23 x + x + 6613228, 2 23310861 x + 153111100 x - 72745491
最后一个命令的结果由两项组成:商和余数。MuPAD 还有用于从多项式中提取系数、使用霍纳算法评估多项式以及更多功能的命令。
我们首先创建一个矩阵域
>> M:=Dom::Matrix(); Dom::Matrix(Dom::ExpressionField(id, iszero))
此处返回的结果表明 MuPAD 期望矩阵的元素将是某个域的成员,该域不执行规范化(函数 id 只是按给定的方式返回元素),并且 0 被识别为零值。
现在我们将使库 linalg 中的所有命令对我们可用
>> export(linalg);
现在我们将创建一些矩阵并使用它们。首先,是一个具有给定元素的矩阵。
>> A:=M([[1,2,3],[-1,3,-2],[4,-5,2]]); +- -+ | 1, 2, 3 | | | | -1, 3, -2 | | | | 4, -5, 2 | +- -+我们已将矩阵元素作为列表的列表输入(在 MuPAD 中,列表以方括号分隔)。
接下来,是一个元素随机选择在 -9 和 9 之间的矩阵。我们通过将 random 返回的函数应用于每个元素来做到这一点。
>> B:=M(3,3,func(random(-9..9)(),i,j)); +- -+ | -7, -5, 8 | | | | 3, -1, 7 | | | | 3, -5, 6 | +- -+
显然,这种方法可以用于生成任何矩阵,其元素是其行和列值的函数。linalg 库中有一个 randomMatrix 命令,但它要求元素是系数环的成员。对于我们的目的来说,自己编写一个同样容易。
>> A*B; +- -+ | 8, -22, 40 | | | | 10, 12, 1 | | | | -37, -25, 9 | +- -+ >> det(A); -37 >> 1/A; +- -+ | 4/37, 19/37, 13/37 | | | | 6/37, 10/37, 1/37 | | | | 7/37, -13/37, -5/37 | +- -+正如我们在上面看到的,MuPAD 支持运算符重载,这意味着由于 A 是矩阵,1/A 被解释为 A 的逆。
>> A^10; +- -+ | 19897010, -20429930, 22281963 | | | | -42711893, 43857348, -47862790 | | | | 64993856, -66730117, 72852811 | +- -+ >> b:=M(3,1,[7,9,-21]); +- -+ | 7 | | | | 9 | | | | -21 | +- -+这里前两个(可选)值给出了矩阵的行数和列数,然后矩阵元素在单个列表中给出。如果列表不够长,则其余值将默认为零。
>> linearSolve(A,b); +- -+ | -2 | | | | 3 | | | | 1 | +- -+ >> AM:=A.b; +- -+ | 1, 2, 3, 7 | | | | -1, 3, -2, 9 | | | | 4, -5, 2, -21 | +- -+. 运算符是连接。同样,这是一个重载运算符,因为它也适用于其他数据类型。
>> gaussJordan(AM); +- -+ | 1, 0, 0, -2 | | | | 0, 1, 0, 3 | | | | 0, 0, 1, 1 | +- -+linalg 库功能非常齐全,包含大量用于操作矩阵和向量的命令:行和列运算;矩阵分解和分解;用于处理矩阵多项式和特征系统的命令;等等。
我们首先通过将微分方程定义为 ode 域中的方程来定义它。
>> de:=ode(y'(x)+4*y(x)=exp(3*x),y(x)); ode(4 y(x) + diff(y(x), x) = exp(3 x), y(x))
请注意,MuPAD 支持导数的破折号表示法。
>> solve(de); { 3 } { exp(x) } { ------- + C1 exp(-4 x) } { 7 }当然,我们可以求解具有初始条件的方程
>> de2:=ode({y''(x)-2*y'(x)+3*y(x)=0,y(0)=1,y'(0)=2},y(x)); ode({D(y)(0) = 2, y(0) = 1, 3 y(x) - 2 diff(y(x), x) + diff(y(x), x, x) = 0 }, y(x)) >> solve(de2); { 1/2 1/2 } { 1/2 exp(x) 2 sin(x 2 ) } { exp(x) cos(x 2 ) + ----------------------- } { 2 }MuPAD 可以轻松求解线性微分方程,还可以求解一大类非线性微分方程。
递推关系的求解方式类似;通过将方程定义为 rec 类型,并应用命令 solve。
>> rr:=rec(a(n)=a(n-1)+3*a(n-2),a(n)); rec(a(n) = a(n - 1) + 3 a(n - 2), a(n)) >> solve(rr); { / 1/2 \n / 1/2 \n } { | 13 | | 13 | } { a1 | ----- + 1/2 | + a2 | 1/2 - ----- | } { \ 2 / \ 2 / }
如果我们包含初始条件,MuPAD 将返回精确解。
>> rr2:=rec(a(n)=a(n-1)+3*a(n-2),a(n),{a(0)=1,a(1)=3}); rec(a(n) = a(n - 1) + 3 a(n - 2), a(n), {a(0) = 1, a(1) = 3}) >> solve(rr2); { / 1/2 \ / 1/2 \n / 1/2 \ / 1/2 \n } { | 5 13 | | 13 | | 5 13 | | 13 | } { | 1/2 - ------- | | 1/2 - ----- | + | ------- + 1/2 | | ----- + 1/2 | } { \ 26 / \ 2 / \ 26 / \ 2 / }对于非齐次方程,MuPAD 返回特解。
>> rr3:=rec(a(n) = a(n - 1) + 3*a(n - 2)+n^2, a(n)); 2 rec(a(n) = a(n - 1) + 3 a(n - 2) + n , a(n)) >> solve(rr3); { 2 } { 14 n n } { - ---- - -- - 59/27 } { 9 3 }
MuPAD 中的图形显示是通过一个名为 VCam 的单独程序生成的,该程序可以完全独立于 MuPAD 使用。但假设我们正处于 MuPAD 会话(使用 xmupad 启动)的中间,并且我们希望绘制一些函数。命令 plotfunc 将允许我们绘制 y=f(x) 形式的函数,或者在三维中,绘制 z=f(x,y) 形式的函数。
>> plotfunc(1/(1+x^2),x=-4..4); >> plotfunc(x^3-3*x*y^2,x=-2..2,y=-2..2);
这些命令将打开一个 VCam 窗口,其中显示了函数,以及另一个窗口,您可以在其中更改各种绘图选项。第二个命令的输出如图 2 所示,以及 VCams 的各种窗口。
更通用的绘图命令是 plot2d 和 plot3d,通过它们可以按如下方式生成上述绘图
>> plot2d(Mode = Curve, [u, 1/(1+u^2)], u = [-4, 4]]); >> plot3d([Mode = Surface, [u, v, exp(-sqrt(u^2+v^2))], u = [-4, 4], v = [-4, 4]]);
我们看到这些命令使用函数的参数化表示。这允许轻松绘制大量不同的函数。有大量的绘图选项,包括绘图和背景的颜色、曲线或表面的样式、轴的位置和样式、标签和标题。所有这些都可以在 VCam 中交互更改,或作为选项提供给 plot 命令。
对于更复杂的示例,让我们绘制一个环面,半径为 3 和 1。这可以使用以下命令绘制
>> plot3d([Mode = Surface, [(3+cos(u))*cos(v), (3+cos(u))*sin(v), sin(u)], u = [0, 2*PI], v = [0, 2*PI]]);
这将给出一个带有三个编号轴的线框环面——这不是一个特别优雅的结果。我们可以向这个基本命令添加更多选项,以给我们一个漂亮的填充环面,带有隐藏线,在一个没有数字的框中
>> plot3d(Title = "A torus", Axes = Box, Labels = ["","",""], Ticks = 0, [Mode = Surface, [(3+cos(u))*cos(v), (3+cos(u))*sin(v), sin(u)], u = [0, 2*PI], v = [0, 2*PI] Style = [ColorPatches, AndMesh]]);所有这些选项现在都可以再次使用 VCam 更改。我们还可以更改视角;放大和缩小;修改配色方案;以及许多其他事情。我们可以一次绘制多个表面,方法是在一个 plot3d 命令中放置多个表面定义。例如
>> plot3d(Title = "Two tori", Axes = Box, Labels = ["","",""], Ticks = 0, [Mode = Surface, [(5+cos(u))*cos(v), (5+cos(u))*sin(v), sin(u)], u = [0, 2*PI], v = [0, 2*PI], Style = [ColorPatches, AndMesh] ], [Mode = Surface, [sin(u), 5+(5+cos(u))*cos(v), (5+cos(u))*sin(v)], u = [0, 2*PI], v = [0, 2*PI], Style = [ColorPatches, AndMesh] ] );结果如图 3 所示。
在处理如此长的表达式时,最好首先使用您喜欢的编辑器创建一个小文件,例如“tori.mu”,以包含上述命令,然后将其读入 MuPAD
>> read("tori.mu");
这避免了使用 MuPAD 自己的文本编辑功能,这些功能非常基本。
我们已经粗略地讨论了术语“域”。现在我们将更详细地(但不是很多)研究这一点。域是 MuPAD 工作方式的基础,我们需要对其有基本的了解才能有效地使用 MuPAD。
MuPAD 中的域可以是代数结构(例如有限域或置换群)或数据类型(例如矩阵、多项式或分数),对于这些域,在域上定义的重载运算符或函数始终返回域中的结果(或者在不存在结果时返回 FAIL 结果)。
举一些例子,假设我们研究模 29 的整数上的矩阵。由于 29 是素数,这些整数形成一个伽罗瓦域,因此矩阵应该响应所有标准算术运算。
首先是定义
>> M29:=Dom::Matrix(Dom::IntegerMod(29)); Dom::Matrix(Dom::IntegerMod(29))
这里使用了两个域:Dom::Matrix,它创建一个矩阵域,以及 Dom::IntegerMod(29),它创建模 29 的整数域。
>> A:=M29([[100,200,-30],[47,-97,130],[13,33,-1001]]); +- -+ | 13 mod 29, 26 mod 29, 28 mod 29 | | | | 18 mod 29, 19 mod 29, 14 mod 29 | | | | 13 mod 29, 4 mod 29, 14 mod 29 | +- -+请注意,MuPAD 返回的结果会自动规范化,以便矩阵元素位于所需的域中。如果我们输入无法规范化的值(例如,十进制分数),MuPAD 将返回错误消息。
>> 1/A; +- -+ | 3 mod 29, 8 mod 29, 15 mod 29 | | | | 28 mod 29, 9 mod 29, 22 mod 29 | | | | 12 mod 29, 19 mod 29, 13 mod 29 | +- -+这里,逆运算符返回合适的结果。让我们检查一下。
>> %*A; +- -+ | 1 mod 29, 0 mod 29, 0 mod 29 | | | | 0 mod 29, 1 mod 29, 0 mod 29 | | | | 0 mod 29, 0 mod 29, 1 mod 29 | +- -+这是我们特定矩阵环的单位元。现在我们可以尝试一些其他矩阵运算。
>> linalg::det(A); 12 mod 29 >> linalg::gaussElim(A); +- -+ | 13 mod 29, 26 mod 29, 28 mod 29 | | | | 0 mod 29, 12 mod 29, 2 mod 29 | | | | 0 mod 29, 0 mod 29, 9 mod 29 | +- -+ >> linalg::gaussJordan(A); +- -+ | 1 mod 29, 0 mod 29, 0 mod 29 | | | | 0 mod 29, 1 mod 29, 0 mod 29 | | | | 0 mod 29, 0 mod 29, 1 mod 29 | +- -+ >> A^10; +- -+ | 22 mod 29, 10 mod 29, 3 mod 29 | | | | 3 mod 29, 21 mod 29, 16 mod 29 | | | | 4 mod 29, 18 mod 29, 5 mod 29 | +- -+ >> exp(A); FAIL矩阵指数 exp(X) 定义为 1 + X + (X^2)/2 + (X^3)/6 + (X^4)/24 + ... + (X^n)/n! + ... 正如您可能预期的那样,这对于我们域上的矩阵未定义。对于另一个示例,请考虑模 2 的整数上的多项式。定义类似于上面的矩阵定义。
>> PK:=Dom::Polynomial(Dom::IntegerMod(2)); Dom::Polynomial(Dom::IntegerMod(2))现在我们将在此域中创建一个多项式。
>> p1:=PK(x^17+1); 17 x + 1为了保险起见,我们将创建第二个多项式,它看起来相同,但不在我们的域中。
>> p2:=x^17+1; 17 x + 1即使它们在屏幕上看起来相同,MuPAD 也了解它们;type 命令会告诉我们。
>> type(p1); Dom::Polynomial(Dom::IntegerMod(2)) >> type(p2); "_plus"(最后一个命令的结果是 p2 是通过将事物加在一起形成的对象。)
>> Factor(p1); 3 4 5 8 2 4 6 7 8 1 (x + 1) (x + x + x + x + 1) (x + x + x + x + x + x + 1) >> Factor(p2); 2 3 4 5 6 7 8 9 10 11 12 13 (x + 1) (x - x - x + x - x + x - x + x - x + x - x + x - x 14 15 16 + x - x + x + 1)domains 包是 MuPAD 的一部分,它处于不断修订和增强的状态。例如,目前,不可能在多项式域中执行多项式除法。
MuPAD 配备了功能非常齐全的编程语言。如此之多,以至于我会说这是 MuPAD 最强大的优势之一。与其他 CAS 相比,MuPAD 允许:
过程式编程
函数式编程
面向对象编程
并行处理
即使是像这样的入门介绍也无法触及 MuPAD 编程能力的皮毛,因此我们将只看几个简单的示例。有关更复杂的示例,请尝试 expose 命令,或查看 $MuPAD/share/examples 目录中的一些文件。
对于过程式编程,MuPAD 提供了所有标准编程要求:各种循环、分支和递归。例如,这是一个旨在实现 Hofstadter 混沌函数的简单过程,行号如下所示
1 q:=proc(n) option remember; 2 begin 3 if n<=2 then 4 1 5 else 6 q(n-q(n-1))+q(n-q(n-2)) 7 end_if; 8 end_proc;
假设我们创建一个名为 Hofstadter.mu 的小文件,其中包含这些行,我们使用以下命令将其读入 MuPAD
>> read("Hofstadter.mu");这将使函数 q(n) 对我们可用。然后我们可以列出前 20 个值
>> q(i)$i=1..20; 1, 1, 2, 3, 3, 4, 5, 5, 6, 6, 6, 8, 8, 8, 10, 9, 10, 11, 11, 12或者我们可以绘制前一万个值的图表
>> plot2d([Mode = List,[point(u,q(u)) $ u=1..10000]]);关于这个简单过程的几点说明:第 1 行中的 option remember 表示由函数生成的值会自动存储在需要时可以检索的位置。由于所有嵌套递归,在不使用先前值的情况下评估函数值将非常慢。语法非常标准,并且与 Maple 的语法非常相似。
我们可以使用“箭头”定义非常容易地定义简单函数
>> f:=x->x^2+1;
奇怪的是,我在手册中找不到任何关于此的参考。
对于一个稍微复杂一点的示例,假设我们尝试编写一个程序来生成真值表。也就是说,这样
>> tt(p and q);
将产生
p, q, p and q T, T, T T, F, F F, T, F F, F, F为了使事情对我们自己来说更容易,我们将在函数调用中包含布尔表达式的变量,以便省去解析表达式以获得其变量的麻烦。这是一个这样的程序
1 tt:=proc() 2 local i,j,n,l,ft,f,r,rf; 3 begin 4 if args(0) <= 1 then error("Must include all variables"); 5 end_if; 6 7 ft:=[FALSE,TRUE]; 8 n:=args(0)-1; 9 print(Unquoted,args(j)$j=2..args(0),expr2text(args(1))); 10 11 for j from 2^n-1 downto 0 do 12 f:=args(1); 13 14 for i from 1 to n do 15 l[i]:=floor(j/(2^(n-i))) mod 2; 16 end_for; 17 18 for i from 1 to n do 19 f:=subs(f,args(i+1)=ft[l[i]+1]); 20 end_for; 21 22 for i from 1 to n do 23 r[i]:=_if(l[i]=0,"F","T"); 24 end_for; 25 26 rf:=_if(simplify(f,logic),"T","F"); 27 28 print(Unquoted,r[i]$hold(i)=1..n,rf); 29 end_for; 30 end_proc:这里的一些要点:第 4 行和第 8 行中的值 args(0) 给出了参数的数量;第 9 行中的 expr2text 函数只是返回给定表达式的字符串版本;第 4 行中的 error 语句立即退出过程;_if 命令(第 23 行和第 26 行)是标准 if 语句的函数形式。程序的其余部分只是列出变量的所有可能的真值(这在第 14 行到第 20 行中完成),并将它们打印出来,以及将这些真值代入函数时获得的值。
这个程序可能只被认为是框架;例如,它不进行类型检查。
目前有一些 MuPAD 书籍可用,但我还没有见过。在线文档非常出色。它以两种形式存在:纯 ASCII(用于在终端模式下使用 MuPAD);以及带有超链接的 dvi,当在 X 下使用 MuPAD 时。
对于 ASCII,帮助命令通过问号获得
>> ?<command>
将提供有关 <command> 的一些屏幕信息。请注意,这是唯一不需要终止冒号或分号的 MuPAD 命令。文档量各不相同;但通常包括基本描述、一些示例以及相关命令的列表。有些帮助文件确实非常大;有些则非常小。例如
>> ?stats::median很短;它基本上只是告诉您此命令返回值的列表的中位数。然而
>> ?Dom::Matrix非常长,详细讨论了矩阵的创建以及为矩阵定义的操作。
有关 MuPAD 库的信息可以使用 info 命令获得;例如
>> info(numlib);
提供了 numlib 库中所有命令的列表。您也可以使用
>> ?numlib以获得对 numlib 所有命令的简要描述。
您可以使用 expose 查看定义函数的 MuPAD 程序。同样,程序的长度差异很大。例如
>> expose(length);
返回一个由六行程序定义的简短函数,但
>> expose(D)返回一个 164 行的程序。您也可以使用 op 获取信息;同样,给出的量也各不相同;
>> op(Dom::Matrix);返回定义矩阵的 MuPAD 程序的所有 1482 行。
xmupad 的文档以手册的 dvi 文件形式提供,其中包含大量超链接。实际上可以使用 hypage 命令独立于 MuPAD 读取手册。与启动 MuPAD 的命令一样,这是对 shell 脚本的调用。但是,hypage 会与 xmupad 一起自动启动。
所有相关文档均以 hyTeX dvi 文件形式提供;即带有嵌入式超链接的 dvi 文件。如果您习惯于 TeX 和 dvi 查看器,这种方法看起来非常明智:数学排版非常出色,正如您所期望的那样,并且包含大量图形。起初使用书籍(具有所有装饰:目录、章节、索引)作为在线文档的范例似乎有点奇怪,但实际上效果非常好。毕竟,每个人都熟悉书籍的结构,因此无需学习一些新的奇怪帮助系统的特殊性和怪癖。
信息量非常丰富。除了对所有命令和函数的讨论外,还有关于图形、编程和调试的广泛章节,以及两个出色的演示。此外,除了手册外,还有涵盖所有 MuPAD 库的 hytex dvi 文件,以及方便的快速参考。
一旦 xmupad 和 hypage 启动并运行,帮助命令
>> ?<command>
将在相关页面打开手册。进入手册后,您可以使用超链接浏览其他类似命令。我发现 hypage 非常容易使用。如果您已安装 MuPAD,您应该会发现本文是多余的,因为手册中更深入地介绍了本文中的所有内容。
图 4 显示了 hypage 的屏幕截图。
但是,我对 hypage 有一些不满。主要的一个是无法更改字体大小或页面布局。例如,如果您减小 hypage 窗口的大小,则文本不会重新格式化以适应可用的窗口大小,因此您必须使用不方便的滚动条来查看文本。这使得 hypage 在 640x480 VGA 屏幕(例如在我的笔记本电脑上)上几乎无法使用。此外,所有文本都是相同的颜色(超链接由下划线给出),我发现这有点沉闷。似乎也没有太多的击键移动。我找到了三个(手册中未列出):p 代表上一页;f 代表前进,r 代表返回(到链接页面)。
另一方面,使用更高分辨率的屏幕,hypage 是一种乐趣。
规范的 MuPAD 站点是
但大多数信息都在
您可以从 MuPAD 站点定向到该站点。在这里,您会找到一些常见问题解答、一些 MuPAD 在不同数学领域的示例以及与其他 CAS 的一些比较。不幸的是,这些比较相当旧,并且在撰写本文时,它们尚未升级到最新版本的 MuPAD。还有一些 MuPAD 团队成员编写的技术文章,讨论了 MuPAD 内部工作原理的各个方面。如果您想掌握 MuPAD,应该阅读这些文章。
您还会找到一些 MathPAD 期刊。这些期刊由 MuPAD 团队出版,涵盖 CAS 及其一般用途。其中只有少数是专门针对 MuPAD 的,而这少数是值得一读的,因为它们让人们对 MuPAD 的发展以及各种设计考虑因素有了深刻的了解。
到目前为止,除了已出版的手册外,还没有关于 MuPAD 的书籍,并且在公开文献中也很少有文章。上面的两个站点和在线文档几乎涵盖了所有内容。
再简单不过了!您需要下载两个文件:一个包含二进制文件(mupad、xmupad、vcam、hypage 等);另一个是“共享”材料:文档和 MuPAD 库。解压缩它们,并将它们解压缩到合适的目录(/usr/local/MuPAD 是一个好位置,但任何位置都可以),并将 /usr/local/MuPAD/share/bin(或其他任何内容)添加到您的路径中。正如我之前提到的,此 bin 目录仅包含 shell 脚本,这些脚本在调用二进制文件之前设置所有必要的环境变量。因此,无需进行任何额外的调整。
要使用 MuPAD 的图形功能,您还需要在系统上安装 xview 库。
您会发现,这样安装的 MuPAD 具有一定的内存限制:您将无法处理需要大量内存使用的命令。要克服此问题,您需要注册您的 MuPAD 副本。这将为您提供许可证密钥,您可以使用该密钥来解锁 MuPAD 的内存使用。
在 sci.math.symbolic 新闻组中最常被问到的问题之一是:“……之间有什么区别?” 我目前见过的最好的答案是:“它们的拼写不同!” 本着这种精神,我无意详细分析 MuPAD 和其他 CAS 之间的差异,而是要提出一些一般性观点。
首先,MuPAD 在价格上是无与伦比的:它是免费的!严格来说,这不是真的;在某些情况下,您必须付费才能使用 MuPAD。但对于单用户 Linux 用户(我们当中有谁不是呢?),它是免费的。
与 Maple 和 Mathematica 可爱的工作表界面相比,该界面相当笨拙。MS Windows 95/NT 下 MuPAD 的界面要精致得多,但您必须付费才能获得。仅凭这一点,我就会说 MuPAD 不如其竞争对手那样适合基础教学。很高兴看到不同颜色的输入和输出,以及正确排版的数学输出。我也喜欢将图形输出作为工作表的一部分。目前,这些在 MuPAD 中都不可能实现。
同样,MuPAD 没有其竞争对手那样的数学广度。一个例子将说明我的观点:尝试求解 Riccati 微分方程 dy 2 2 -- = x + y , y(0) = 1。 dx Maple 可以轻松解决这个问题;解决方案是一个涉及贝塞尔函数的复杂表达式。但是,MuPAD 无法解决这个问题;它对贝塞尔函数的了解不足以识别它们可能应用的所有位置。此外,其应用于微分方程的 solve 命令没有 Maple 的 dsolve 命令强大。但是,MuPAD 是一种年轻得多的产品,而 Maple 和 Mathematica 都是由拥有令人羡慕的资源的大公司生产的,MuPAD 却是由一个规模小且长期资金不足的研究团队生产的。
另一方面,MuPAD 与其竞争对手一样具有可扩展性。它的编程能力与 Maple 和 Mathematica 相当。更重要的是,它提供了不同的编程范例,并且不会强迫您采用任何特定的风格。同样,它提供完整的并行编程,并附带出色的图形调试器。要公正地讨论这些主题,至少需要另一篇与本文大小相同的文章,所以请获取 MuPAD 并阅读其文档!
在 MuPAD 中使用域意味着可以探索数学的深层方面,并编写非常通用的例程。因此,即使 MuPAD 在广度上有所不足,但它也具有与其竞争对手相当或更高的深度。
那么为什么要使用 MuPAD 呢?如果您想要一个 CAS 作为“黑匣子”来快速生成方程的解;那么 MuPAD 不如其竞争对手那样合适(至少目前还不是)。但是,如果您正在探索数学关系和结构,那么 MuPAD 似乎是首选工具。
我对 MuPAD 印象非常深刻;如此出色的免费软件确实很少见。MuPAD 值得 Linux 社区的全力支持,如果您以任何方式使用数学,那么 MuPAD 应该在您的系统中找到一席之地。
