查看“Minimal Maxima”的源代码
来自Ubuntu中文
←
Minimal Maxima
跳到导航
跳到搜索
因为以下原因,您没有权限编辑该页面:
您请求的操作仅限属于该用户组的用户执行:
用户
您可以查看和复制此页面的源代码。
本文作者:Robert Dodier 翻译:dbzhang800 适用版本: 文章状态:整理中... == Maxima 是什么?== Maxima 是一个处理数学表达式的系统,例如x + y, sin(a + bπ)以及u · v − v · u Maxima 并不太关心表达式的含义,一个表达式是否有意义由使用者来判断。 有时你想给未知数赋值并且要计算表达式的值。Maxima 很善长做这件事。但是Maxima 也很 善长推迟赋值;你可以先对表达式做一番处理,然后才给(也许永远不给)未知数赋值。 我们先看几个例子: '''1.我想计算球的体积。''' (%i1) V: 4/3 * %pi * r^3; 3 4 %pi r (%o1) -------- 3 '''2.半径是10。''' (%i2) r: 10; (%o2) 10 '''3.V的值和前面一样;在我们下令以前,Maxima不会改变V的值。''' (%i3) V; 3 4 %pi r (%o3) -------- 3 '''4.Maxima,重新计算一下V。''' (%i4) ’’V; 4000 %pi (%o4) -------- 3 '''5.我想看到一个具体的数值而不是一个表达式。''' (%i5) ’’V, numer; (%o5) 4188.79020478639 == 表达式 == Maxima 中所有的东西都是表达式,包括数学表达式、对象、程序结构等。表达式要么是原子,要么是操作符与它的自变量。 原子是一个符号(名字),一个用引号括起来的字符串,或者是一个数(整数或浮点数)。 所有非原子表达式都表示为op(a1 , . . . , an ),其中op是操作符的名字,a1 , . . . , an 是自变。(表达式的显示形式可能不太一致,但内部表示都是一样的。)表达式中的自变量可以是原子或非原子表达式。 数学表达式中含有一个操作符,比如+ − ∗/ < = > 或者一个函数,比如'''sin'''(x),'''bessel_j'''(n, x)。在这种情况下操作符就是函数。 对象在Maxima 中是表达式。列表[a1 , . . . , an ]就是表达式'''list'''(a1 , . . . , an )。矩阵就是表达式 matrix(list(a1,1 , . . . , a1,n ), . . . ,list(am,1 , . . . , am,n )) 程 序 构 造 是 表 达 式 。 一 个 代 码 块'''block'''(a1 , . . . , an )是 操 作 符 为'''block'''自 变 量 为a1 , . . . , an 的表 达 式 。 条 件 语 句'''if''' a '''then''' b '''elseif''' c '''then''' d是 表 达 式'''if'''(a, b, c, d)。 循 环'''for''' a '''in''' L '''do''' S是 类 似于'''do'''(a, L, S)的表达式。 Maxima 函数'''op'''返回一个非原子表达式的操作符。函数args返回非原子表达式的自变量。函数'''atom'''判断一个表达式是不是原子。 让我们看几个例子。 '''1. 符号、字符串和数字都是原子。为了一次能看到它们,我把几个例子凑到时了一个列表里面。''' (%i2) [a, foo, foo_bar, "Hello, world!", 42, 17.29]; (%o2) [a, foo, foo_bar, Hello, world!, 42, 17.29] '''2. 数学表达式。''' (%i1) [a + b + c, a * b * c, foo = bar, a*b < c*d]; (%o1) [c + b + a, a b c, foo = bar, a b < c d] '''3. 列表和矩阵。列表和矩阵的元可以是任何表达式,甚至是其它列表或矩阵。''' (%i1) L: [a, b, c, %pi, %e, 1729, 1/(a*d - b*c)]; 1 (%o1) [a, b, c, %pi, %e, 1729, ---------] a d - b c (%i2) L2: [a, b, [c, %pi, [%e, 1729], 1/(a*d - b*c)]]; 1 (%o2) [a, b, [c, %pi, [%e, 1729], ---------]] a d - b c (%i3) L [7]; 1 (%o3) --------- a d - b c (%i4) L2 [3]; 1 (%o4) [c, %pi, [%e, 1729], ---------] a d - b c (%i5) M: matrix ([%pi, 17], [29, %e]); [ %pi 17 ] (%o5) [ ] [ 29 %e ] (%i6) M2: matrix([[%pi,17],a*d - b*c],[matrix([1,a],[b,7]),%e]); [ [%pi, 17] a d - b c ] [ ] (%o6) [ [ 1 a ] ] [ [ ] %e ] [ [ b 7 ] ] (%i7) M [2][1]; (%o7) 29 (%i8) M2 [2][1]; [ 1 a ] (%o8) [ ] [ b 7 ] '''4. 程序构造是表达式。x : y表示把y赋给x;这个赋值表达式的值是y。block把几个表达式组合为一个块,然后依次求各个表达式的值;最后一个表达式的值即是块的值。''' (%o1) 25 (%i2) [a, b]; (%o2) [42, 17] (%i3) block ([a], a: 42, a^2 - 1600) + block ([b], b: 5, %pi^b); 5 (%o3) %pi + 164 (%i4) (if a > 1 then %pi else %e) + (if b < 0 then 1/2 else 1/7); 1 (%o4) %pi + - 7 '''5. op返回操作符,args返回自变量,atom判断一个表达式是不是原子。''' (%i1) op (p + q); (%o1) + (%i2) op (p + q > p*q); (%o2) > (%i3) op (sin (p + q)); (%o3) sin (%i4) op (foo (p, q)); (%o4) foo (%i5) op (foo (p, q) := p - q); (%o5) := (%i6) args (p + q); (%o6) [q, p] (%i7) args (p + q > p*q); (%o7) [q + p, p q] (%i8) args (sin (p + q)); (%o8) [q + p] (%i9) args (foo (p, q)); (%o9) [p, - q] (%i10) args (foo (p, q) := p - q); (%o10) [foo(p, q), p - q] (%i11) atom (p); (%o11) true (%i12) atom (p + q); (%o12) false (%i13) atom (sin (p + q)); (%o13) false '''6. 程序构造的操作符和自变量。单引号告诉Maxima构造表达式,但不求值。这点我们后面会涉及。''' (%o0) done (%i1) op ('(block ([a], a: 42, a^2 - 1600))); (%o1) block (%i2) op (' (if p > q then p else q)); (%o2) if (%i3) op ('(for x in L do print (x))); (%o3) mdoin (%i4) args (' (block ([a], a: 42, a^2 -1600))); 2 (%o4) [[a], a : 42, a - 1600] (%i5) args (' (if p > q then p else q)); (%o5) [p > q, p, true, q] (%i6) args (' (for x in L do print (x))); (%o6) [x, L, false, false, false, false, print(x)] ==求值== 一个符号的值是跟这个符号相关联的一个表达式。每个符号都有一个值如果没有被赋值,一个符号的值就是它自己。(例如,如果没有给x赋过值,那么它的值就是x。)数字和字符串的值就是它们本身。 一个非原子表达式基本上按下面方式求值。 # 对表达式中操作符的每一个自变量求值。 # 如果一个操作符是一个可以调用的函数,那么就调用这个函数,而表达式的值就是该函数 的返回值。 在几种情况下,上述求值过程会发生变化。其中一些变化将导致较少的求值运算: # 有一些函数并不对它们一部分或者全部自变量进行求值,或者相反修改了它们自变量的值。 # 一个单引号 会阻止求值。 ## 'a的求值结果为a。a的任何其它值都被忽略掉。 ## 对 f (a1, ..., an )的求值得到时f (ev(a1), ..., ev(an))。也就是说,自变量都被求值了,而f 却没有被调用。 ## '(...)将阻止(...)中任何表达式的求值。 另外一些变化会导致更多的求值运算。 # 两个单引号 a使得在对表达式a作语法分析的时候就额外求值一次。 # '''ev(a)'''使得每次对'''ev'''(a)求值的时候都额外对a求值。 # '''apply'''(f, [a1, ..., an ])将会对自变量(a1, ..., an )求值,即使f 只是一般地引用它们。 # '''define'''像:= 一样构造一个函数定义,但是'''define'''会对函数体求值而:=则仅仅引用函数体。 下面看一些表达式是怎样被求值的。 '''1. 如果没有被赋值,那么符号的求值结果就是它们自身。''' (%i1) block (a: 1, b: 2, e: 5); (%o1) 5 (%i2) [a, b, c, d, e]; (%o2) [1, 2, c, d, 5] '''2. 操作符的自变量一般求值(除非以某种方法阻止求值)。''' (%i1) block (x: %pi, y: %e); (%o1) %e (%i2) sin (x + y); (%o2) - sin(%e) (%i3) x > y; (%o3) %pi > %e (%i4) x!; (%o4) %pi! '''3. 如果操作符对应于一个可调用函数,那么调用这个函数(除非被阻止)。否则,求值会得到具有同一个操作符的另一个表达式。''' (%i1) foo (p, q) := p - q; (%o1) foo(p, q) := p - q (%i2) p: %phi; (%o2) %phi (%i3) foo (p, q); (%o3) %phi - q (%i4) bar (p, q); (%o4) bar(%phi, q) '''4. 一些函数引用它们的自变量。例如:save , :=, kill''' (%i1) block (a: 1, b: %pi, c: x + y); (%o1) y+x (%i2) [a, b, c]; (%o2) [1, %pi, y + x] (%i3) save ("tmp.save", a, b, c); (%o3) tmp.save (%i4) f (a) := a^b; (%o4) b (%o4) f(a) := a (%i5) f (7); %pi (%o5) 7 (%i6) kill (a, b, c); (%o6) done (%i7) [a, b, c]; (%o7) [a, b, c] '''5. 一个单引号会阻止求值。''' (%i1) foo (x, y) := y - x; (%o1) foo(x, y) := y - x (%i2) block (a: %e, b: 17); (%o2) 17 (%i3) foo (a, b); (%o3) 17 - %e (%i4) foo (’a, ’b); (%o4) b-a (%i5) ’foo (a, b); (%o5) foo(%e, 17) (%i6) ’(foo (a, b)); (%o6) foo(a, b) '''6. 两个单引号使得在对表达式作语法分析的时候就额外求值一次。''' (%i1) diff (sin (x), x); (%o1) cos(x) (%i2) foo (x) := diff (sin (x), x); (%o2) foo(x) := diff(sin(x), x) (%i3) foo (x) := ’’(diff (sin (x), x)); (%o3) foo(x) := cos(x) '''7. ev使得每当它求值的时候才有一次额外的求值。请对比它与两个单引号的不同效果。''' (%i1) block (xx: yy, yy: zz); (%o1) zz (%i2) [xx, yy]; (%o2) [yy, zz] (%i3) foo (x) := ’’x; (%o3) foo(x) := x (%i4) foo (xx); (%o4) yy (%i5) bar (x) := ev (x); (%o5) bar(x) := ev(x) (%i6) bar (xx); (%o6) zz '''8. apply导致对自变量求值,即便通常情况下仅仅对它们引用。''' (%i1) block (a: aa, b: bb, c: cc); (%o1) cc (%i2) block (aa: 11, bb: 22, cc: 33); (%o2) 33 (%i3) [a, b, c, aa, bb, cc]; (%o3) [aa, bb, cc, 11, 22, 33] (%i4) apply (kill, [a, b, c]); (%o4) done (%i5) [a, b, c, aa, bb, cc]; (%o5) [aa, bb, cc, aa, bb, cc] (%i6) kill (a, b, c); (%o6) done (%i7) [a, b, c, aa, bb, cc]; (%o7) [a, b, c, aa, bb, cc] '''9. define对函数定义求值。''' (%i1) integrate (sin (a*x), x, 0, %pi); 1 cos(%pi a) (%o1) - - ---------- a a (%i2) foo (x) := integrate (sin (a*x), x, 0, %pi); (%o2) foo(x) := integrate(sin(a x), x, 0, %pi) (%i3) define (foo (x), integrate (sin (a*x), x, 0, %pi)); 1 cos(%pi a) (%o3) foo(x) := - - ---------- a a ==化简== 对一个表达式求值之后,Maxima试图寻找一个“更简单”的等价的表达式。Maxima会应用几个规则,包括人们对简单的约定。例如,1 + 1化简为2,x + x化简为2x,以及'''sin'''(%'''pi''')化简为0。 然而,许多大家熟知的恒等式并不会被自动应用。例如,三角函数中的倍角公式,或者对分式的整理如a/b + c/b → (a + c)/b。有几个函数能够应用这些恒等式。 除非明确禁止,化简总是被执行。即使不对表达式求值也会执行化简。 '''tellsimpafter'''用来建立用户定义的化简规则。 我们来看几个化简的例子。 '''1. 单引号阻止求值,但不阻止化简。当全局标志simp是false的时候,阻止化简但不阻止求值。''' '''2. 一些恒等式不能自动应用。expand, ratsimp, trigexpand, edmoivre是能够应用恒等式的一些函数。''' ==apply,map和lambda== '''1. apply构造一个表达式并求值。表达式中的自变量总是被求值(即便在其它情况下不会)。''' '''2. map对自变量列表中的每一项构造一个表达式并求值。表达式中的自变量总是被求值(即便在其它情况下不会)。''' '''3. lambda构造一个lambda表达式(也就是说,一个无名函数)。lambda可以像一个命名函数一样用于一些环境中。lambda不对函数体求值。''' ==内置对象类型== 对象表示为一个表达式。像其它表达式一样,对象也由操作符和自变量组成。 最重要的内建类型列表、矩阵、集合。 ===列表=== # 象这样来表示一个列表:[a, b, c]。 # 如果L是一个列表,则L[i]是它的第i个元素。L[1]是第一个元素。 # '''map'''(f, L)应用f 到L的每一个元素上。 # '''apply'''(“ + “, L)对L的所有元素求和。 # '''for''' x '''in''' L '''do''' expr对L中的每一个元素,求值expr。 # '''length'''(L)是L中元素的个数。 ===矩阵=== # 矩阵象这样定义:'''matrix'''(L1 , . . . , Ln ),其中(L1 , . . . , Ln )是矩阵中每行矩阵元的列表。 # 如果M 是一个矩阵,M [i, j]或者M [i][j]就是它的第(i, j)个矩阵元。M [1, 1]是左上角矩阵元。 # 运算符 . 代表不可交换的乘法。M.L, L.M 和M.N 是不对易乘法,其中L是一个列表,M 和N 是矩阵。 # '''transpose'''(M )是M 的转置。 # '''eigenvalues'''(M )返回M 的本征值。 # '''eigenvectors'''(M )返回M 的本征向量。 # '''length'''(M )返回M 行数。 # '''length'''('''transpose'''(M ))返回M 的列数。 ===集合=== # Maxima 理解显式定义的有限集合。集合跟列表不同如果要把一种变为另一种,需要显式的转换。 # 集合中元素是a, b, c, . . .时,我们这样指定集合:'''set'''(a, b, c, . . .) # '''union'''(A, B)是A和B的并集。 # '''intersection'''(A, B)是A和B的交集。 # '''cardinality'''(A)是集合A中元素的个数。 ==如何. . .== ===定义函数=== '''1. 运算符:=定义一个函数,引用函数体。''' 在下面的例子中, 每当调用函数时 ,'''diff'''都要重新求值。 自变量被代入到x, 然后求值最后的表达式。 当变量不 是一个符号时, 将发生错误 : 对于'''foo'''(1) Maxima试图对'''diff'''('''sin'''(1)2 , 1)求值。 '''2. define定义一个函数并对函数体求值。''' 在这个例子中,只对'''diff'''求值一次(当函数被定义的时候)。'''foo'''(1)现在是有效的。 ===解方程=== ===积分和微分=== '''integrate'''计算积分和不定积分。 '''diff'''计算导数。 ===作图=== '''plot2d'''画2维图。 参考 '''plot3d。''' ===保存和载入文件=== '''save'''把表达式写入一个文件。 '''load'''从文件中读入表达式。 参考'''stringout'''的'''batch'''。 ==Maxima 编程== Maxima有一个包含了全部Maxima符号的命名空间。没有办法建立其它命名空间。 所有变量都是全局的,除非它们出现在局部变量的声明中。函数、lambda表达式、以及块中可以有局部变量。 一个变量的值总是最近一次赋值给它的那个,要么通过显式赋值,要么是通过对块、函数、或者lambda表达式中的局部变量赋值。这个策略称为动态域。 如果一个变量是函数、lambda表达式、或者块中的局部变量,它的值是局部的,但它的其它属性(象由'''declare'''建立的)是全局的。函数'''local'''把一个变量的全部属性变为局部的。 一个函数定义默认是全局的,即便它出现在函数、lambda表达式、或者块中。local(f),f(x):=...产生一个局部函数定义。 '''trace'''(foo)会让Maxima在进入和退出函数foo时打印一条消息。 下面看一些Maxima编程的例子。 '''1. 所有变量都是全局的,除非它们出现在局部变量的声明中。函数、lambda表达式、以及块中可以有局部变量。''' (%i1) (x: 42, y:1729, z:foo*bar); (%o1) bar foo (%i2) f(x, y) := x * y * z; (%o2) f(x, y) := x y z (%i3) f(aa, bb); (%o3) aa bar bb foo (%i4) lambda([x, z], (x - z)/y); x - z (%o4) lambda([x, z], -----) y (%i5) apply(%, [uu, vv]); uu - vv (%o5) ------- 1729 (%i6) block([y, z], y: 65536, [x, y, z]); (%o6) [42, 65536, z] (%i7) '''2. 一个变量的值总是最近一次赋给它的那个,要么通过显式赋值,要么是通过对块、函数、或者lambda表达式中的局部变量赋值。''' (%i1) foo(y) := x - y; (%o1) foo(y) := x - y (%i2) x: 1729; (%o2) 1729 (%i3) foo(%pi); (%o3) 1729 - %pi (%i4) bar(x) := foo(%e); (%o4) bar(x) := foo(%e) (%i5) bar(42); (%o5) 42 - %e (%i6) ==Lisp 和Maxima== 构造 ''':lisp''' expr告诉Lisp解释器去计算expr。这个构造可以在命令提示符中被识别,也可以 在'''batch'''而不是'''load'''处理的文件中被识别。 Maxima的符号'''foo'''对应于Lisp中的符号$foo,Lisp中的符号foo对应于Maxima中的符号?'''foo''' 。 ''':lisp''' ('''defun''' $foo(a)(. . .)定义了一个计算它的参数的Lisp函数。在Maxima中,这个函数通过'''foo'''(a)被调用。 ''':lisp''' ('''defmspec''' $foo(e)(. . .)定义了一个引用它的参数的Lisp函数。在Maxima中,这个函数通过'''foo'''(a)被调用。$foo的参数是('''cdr''' e),而且('''caar''' e)总是$foo自身。 在Lisp中,构造('''mfuncall''' ’$foo a1 . . . an ) 调用Maxima中定义的foo函数。 下面让我们从Maxima进入Lisp,或者反过来说。 '''1. 构造:lisp expr告诉Lisp解释器去计算expr。''' (%i1) (aa + bb)^2; 2 (%o1) (bb + aa) (%i2) :lisp $% ((MEXPT SIMP) ((MPLUS SIMP) $AA $BB) 2) '''2. :lisp (defun $foo(a)(. . .)定义了一个计算它的参数的Lisp函数foo。''' (%i1) :lisp (defun $foo (a b) ‘((mplus) ((mtimes) ,a ,b) $%pi)) $FOO (%i1) (p: x + y, q: x - y); (%o1) x - y (%i2) foo (p, q); (%o2) (x - y) (y + x) + %pi '''3. :lisp (defmspec $foo(e)(. . .)定义了一个引用它的参数的Lisp函数foo。''' (%i1) :lisp(defmspec $bar(e)(let((a(cdr e)))‘((mplus)((mtimes),@a) #<CLOSURE LAMBDA(E)(LET((A(CDR E)))‘((MPLUS)((MTIMES),@A)$%PI))> (%i1) bar (p, q); (%o1) p q + %pi (%i2) bar (’’p, ’’q); (%o2) p q + %pi '''4. 在Lisp中,构造(mfuncall ’$foo a1 . . . an ) 调用Maxima中定义的foo函数。''' (%i1) blurf (x) := x^2; 2 (%o1) blurf(x) := x (%i2) :lisp (displa (mfuncall '$blurf' ((mplus) $grotz $mumble))) 2 (mumble + grotz) NIL
返回
Minimal Maxima
。
导航菜单
页面操作
页面
讨论
阅读
查看源代码
历史
页面操作
页面
讨论
更多
工具
个人工具
登录
导航
首页
最近更改
随机页面
页面分类
帮助
搜索
编辑
编辑指南
沙盒
新闻动态
字词处理
工具
链入页面
相关更改
特殊页面
页面信息