[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
34.1 Introduction to Rules and Patterns | ||
34.2 Functions and Variables for Rules and Patterns |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
この節ではユーザー定義のパターンマッチングと整理ルールを記述します。
幾分違ったパターンマッチング体系を実装した2つの関数グループがあります。
1つのグループは、tellsimp
, tellsimpafter
, defmatch
,
defrule
, apply1
, applyb1
, apply2
です。
他のグループは、let
, letsimp
です。
どちらの体系も
matchdeclare
が宣言したパターン変数を使ってパターンを定義します。
tellsimp
と tellsimpafter
が定義するパターンマッチングルールは
Maximaの整理器によって自動的に適用されます。
defmatch
, defrule
, let
が定義するルールは
明示的に関数をコールすることで適用されます。
更に、 tellrat
が多項式に適用するルール用メカニズムと、
affine
パッケージの可換/非可換代数用メカニズムがあります。
Categories: Simplification · Rules and patterns
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
rule_1を exprに失敗するまで繰り返し適用して、 それから同じルールを exprの部分式すべてに左から右へ、部分式すべてで rule_1が失敗するまで繰り返し適用します。
この方法で exprを変換した結果を expr_2と呼ぶことにします。 次に rule_2を expr_2の最上部から始めて同じ方法で適用します。 rule_nが最後の部分式上で失敗した時、結果を返します。
maxapplydepth
は apply1
と
apply2
が処理する最も深い部分式の深さです。
applyb1
, apply2
, let
も参照してください。
Categories: Rules and patterns
もし rule_1が与えられた部分式上で失敗したら、 rule_2を繰り返し適用し、などなどと続きます。 すべてのルールが与えられた部分式上で失敗した時だけ、 ルールの全組が次の部分式に繰り返し適用されます。 もしルールの1つが成功したら、 同じ部分式が最初のルールから再処理されます。
maxapplydepth
は
apply1
と apply2
が処理する最も深い部分式の深さです。
Categories: Rules and patterns
失敗するまで繰り返し exprの最も深い部分式に rule_1を適用し、 その後、 rule_1がトップレベルの式で失敗するまで 同じルールを1つ高いレベル(すなわち、より大きな部分式)に適用します。 その後、rule_2を rule_1の結果に同様に適用します。 rule_nがトップレベルの式に適用された後、結果を返します。
applyb1
は
apply1
に似ていますが、トップダウンからの代わりにボトムアップから働きます。
maxapplyheight
は applyb1
があきらめる前に届く最大の高さです
Categories: Rules and patterns
デフォルト値: default_let_rule_package
current_let_rule_package
は、
もし他のルールパッケージが指定されないなら、
(letsimp
など) let
パッケージの関数で使われる
ルールパッケージの名前です。
この変数には
let
コマンドを介して定義された任意の規格パッケージの名前が割り当てられます。
もし letsimp (expr, rule_pkg_name)
のようなコールがされたら、
ルールパッケージ rule_pkg_name
はその関数コールだけのために使われ、
current_let_rule_package
の値は変わりません。
Categories: Rules and patterns
デフォルト値: default_let_rule_package
default_let_rule_package
は、 ユーザーがlet
で明示的に設定したり、
current_let_rule_package
の値を変更することで明示的に設定したりしない時
使われるルールの名前です。
Categories: Rules and patterns
patternにマッチするか見るために exprをテストする関数
progname(expr, x_1, ..., x_n)
を定義します。
(引数として与えられているなら、) patternはパターン引数
x_1, ..., x_nを含む式です。
パターン引数は defmatch
の引数として明示的に与えられます。
一方、 matchdeclare
関数がパターン変数を宣言します。
matchdeclare
のパターン変数か
defmatch
のパターン引数として宣言されていない任意の変数は
それ自身とのみマッチします。
生成関数 prognameの最初の引数はパターンに対してマッチされる式であり、 他の引数はパターンの中のダミー変数 x_1, ..., x_nに対応する実際の引数です。
もしマッチが成功したなら、
prognameは、
左辺がパターン引数やパターン変数で、右辺がパターン引数や変数がマッチした部分式の
等式のリストを返します。
パターン変数はそれらがマッチした部分式に割り当てられますが、
パターン引数には割り当てられません。
もしマッチが失敗したら、 prognameは false
を返します。
リテラルパターン(すなわち、パターン引数もパターン変数も含まないパターン)は、
もしマッチが成功したら true
を返します。
matchdeclare
, defrule
, tellsimp
,
tellsimpafter
も参照してください。
例:
a
と b
は x
を含まず、
a
が非ゼロであるような形式 a*x + b
かどうか見るために
expr
をテストする関数 linearp(expr, x)
を定義します。
パターン引数 x
が defmatch
に与えられているので、
このマッチ関数は任意の変数に関する線形式にマッチします。
(%i1) matchdeclare (a, lambda ([e], e#0 and freeof(x, e)), b, freeof(x)); (%o1) done (%i2) defmatch (linearp, a*x + b, x); (%o2) linearp (%i3) linearp (3*z + (y + 1)*z + y^2, z); 2 (%o3) [b = y , a = y + 4, x = z] (%i4) a; (%o4) y + 4 (%i5) b; 2 (%o5) y (%i6) x; (%o6) x |
a
と b
が x
を含まず、 a
が非ゼロであるような
形式 a*x + b
かどうか見るために expr
をテストする関数
linearp(expr, x)
を定義します。
defmatch
にパターン引数が与えられていないので、
このマッチ関数は他の任意の変数ではなく変数 x
に関する線形式にマッチします。
(%i1) matchdeclare (a, lambda ([e], e#0 and freeof(x, e)), b, freeof(x)); (%o1) done (%i2) defmatch (linearp, a*x + b); (%o2) linearp (%i3) linearp (3*z + (y + 1)*z + y^2); (%o3) false (%i4) linearp (3*x + (y + 1)*x + y^2); 2 (%o4) [b = y , a = y + 4] |
定積分かどうか見るために expr
をテストする関数
checklimits(expr)
を定義します。
(%i1) matchdeclare ([a, f], true); (%o1) done (%i2) constinterval (l, h) := constantp (h - l); (%o2) constinterval(l, h) := constantp(h - l) (%i3) matchdeclare (b, constinterval (a)); (%o3) done (%i4) matchdeclare (x, atom); (%o4) done (%i5) simp : false; (%o5) false (%i6) defmatch (checklimits, 'integrate (f, x, a, b)); (%o6) checklimits (%i7) simp : true; (%o7) true (%i8) 'integrate (sin(t), t, %pi + x, 2*%pi + x); x + 2 %pi / [ (%o8) I sin(t) dt ] / x + %pi (%i9) checklimits (%); (%o9) [b = x + 2 %pi, a = x + %pi, x = t, f = sin(t)] |
Categories: Rules and patterns
与えられたパターンに関する置き換えルールを定義し、名付けます。
もし rulenameと名付けられたルールが
(apply1
, applyb1
, apply2
によって)式に適用されるなら、
パターンにマッチするすべての部分式は replacementで置き換えられます。
パターンマッチが値を割り当てる
replacementの中の変数すべてはその後整理される置き換えの中のそれらの値を割り当てられます。
ルールそれ自身は、パターンマッチと置き換えを演算
1つにして式を変換する関数として扱うことができます。
マッチが失敗したらルール関数は false
を返します。
Categories: Rules and patterns
defrule
, tellsimp
, tellsimpafter
が返すような、または
defmatch
が定義するパターンのような名前
rulename_1, ..., rulename_nを持つルールを表示します。
ルールそれぞれは中間式ラベル (%t
)と一緒に表示されます。
disprule (all)
はルールすべてを表示します。
disprule
は引数をクォートします。
disprule
は表示されたルールに対応する中間式ラベルのリストを返します。
let
が定義したルールを表示する letrules
も参照してください。
例:
(%i1) tellsimpafter (foo (x, y), bar (x) + baz (y)); (%o1) [foorule1, false] (%i2) tellsimpafter (x + y, special_add (x, y)); (%o2) [+rule1, simplus] (%i3) defmatch (quux, mumble (x)); (%o3) quux (%i4) disprule (foorule1, "+rule1", quux); (%t4) foorule1 : foo(x, y) -> baz(y) + bar(x) (%t5) +rule1 : y + x -> special_add(x, y) (%t6) quux : mumble(x) -> [] (%o6) [%t4, %t5, %t6] (%i6) ''%; (%o6) [foorule1 : foo(x, y) -> baz(y) + bar(x), +rule1 : y + x -> special_add(x, y), quux : mumble(x) -> []] |
Categories: Rules and patterns · Display functions
prodは replで置き換えられるような
letsimp
のための代入ルールを定義します。
prodは以下の項の正または負のべきの積です:
letsimp
をコールする以前に
matchdeclare
関数が述語論理をアトムと関連づけるために使われないなら、
letsimp
が文字通りに検索するアトム。
この場合、 letsimp
はアトムを述語論理を満たす積の任意の項にマッチさせます。
sin(x)
, n!
, f(x,y)
などのようなカーネル。
上のアトムと同様に、述語論理をカーネルの引数に関連づけるために
matchdeclare
が使われないなら
letsimp
は文字通りのマッチを検索します。
正のべきの項は少なくともそのべきを持つ項だけにマッチするでしょう。
一方、負のべきの項は少なくとも負としてのべきをもつ項だけにマッチするでしょう。
prodの中の負のべきの場合、
スイッチ letrat
を true
に設定しなければいけません。
letrat
も参照してください。
もし述語論理が引数のリストが続く let
関数に含まれるなら、
arg_i'が arg_iにマッチした値である場合、
predname (arg_1', ..., arg_n')
が
true
に評価される時だけ試験的なマッチ
(すなわち、述語論理が省略されたなら受け入れられるもの)が受け入れられます。
arg_iは任意のアトム名や
prodの中に現れる任意の核の引数を取り得ます。
replは任意の有理式を取り得ます。
もし任意のアトムや prodからの引数が
replの中に現れるなら、適切な代入が行われます。
グローバルフラグ letrat
は letsimp
による商の整理を制御します。
letrat
が false
の時、
letsimp
はexprの分子と分母をそれぞれ整理し、商を整理はしません。
n!/n
のような代入は (n-1)!
に進み失敗します。
letrat
が true
の時、分子、分母、商がその順番で整理されます。
これらの代入関数は、同時にいくつかのルールパッケージを使うことを許します。
ルールパッケージそれぞれは任意の数の
let
ルールを含むことができ、ユーザー定義名で参照されます。
コマンド let ([prod, repl, predname, arg_1,
..., arg_n], package_name)
は、
ルール prednameをルールパッケージ package_nameに加えます。
コマンド letsimp (expr, package_name)
は、
package_nameの中でルールを適用します。
letsimp (expr, package_name1, package_name2, ...)
は、
letsimp (%, package_name2)
, …が続く
letsimp (expr, package_name1)
と同値です。
current_let_rule_package
は現在使われているルールパッケージの名前です。
この変数は
let
コマンドを介して定義された任意のルールパッケージの名前に割れ当てられます。
let
パッケージを構成する関数のいずれかがパッケージ名なしでコールされた時はいつでも
current_let_rule_package
が指定したパッケージが使われます。
もし letsimp (expr, rule_pkg_name)
のようなコールがされたら、
ルールパッケージ rule_pkg_nameはその letsimp
コマンドだけで使われ、
current_let_rule_package
は変わりません。
もし他に指定されないなら、
current_let_rule_package
は
default_let_rule_package
をデフォルト値とします。
(%i1) matchdeclare ([a, a1, a2], true)$ (%i2) oneless (x, y) := is (x = y-1)$ (%i3) let (a1*a2!, a1!, oneless, a2, a1); (%o3) a1 a2! --> a1! where oneless(a2, a1) (%i4) letrat: true$ (%i5) let (a1!/a1, (a1-1)!); a1! (%o5) --- --> (a1 - 1)! a1 (%i6) letsimp (n*m!*(n-1)!/m); (%o6) (m - 1)! n! (%i7) let (sin(a)^2, 1 - cos(a)^2); 2 2 (%o7) sin (a) --> 1 - cos (a) (%i8) letsimp (sin(x)^4); 4 2 (%o8) cos (x) - 2 cos (x) + 1 |
Categories: Rules and patterns
デフォルト値: false
letrat
が false
の時、
letsimp
は比の分子と分母それぞれを整理し、商を整理しません。
letrat
が true
の時、
分子、分母、商はその順番に整理されます。
(%i1) matchdeclare (n, true)$ (%i2) let (n!/n, (n-1)!); n! (%o2) -- --> (n - 1)! n (%i3) letrat: false$ (%i4) letsimp (a!/a); a! (%o4) -- a (%i5) letrat: true$ (%i6) letsimp (a!/a); (%o6) (a - 1)! |
Categories: Rules and patterns
ルールパッケージのルールを表示します。
letrules ()
は現在のルールパッケージのルールを表示します。
letrules (package_name)
は package_nameのルールを表示します。
現在のルールパッケージは current_let_rule_package
によって指名されます。
もし他に指定されないなら、
current_let_rule_package
は
default_let_rule_package
がデフォルト値になります。
disprule
も参照してください
それは tellsimp
と tellsimpafter
が定義するルールを表示します。
Categories: Rules and patterns
exprに変化がなくなるまで繰り返し let
が定義する代入ルールを適用します。
letsimp (expr)
は
current_let_rule_package
のルールを使います。
letsimp (expr, package_name)
は
current_let_rule_package
を変えずに
package_nameのルールを使います。
letsimp (expr, package_name_1, ..., package_name_n)
は、
letsimp (%, package_name_2)
などが続く
letsimp (expr, package_name_1
と同値です。
Categories: Rules and patterns
デフォルト値: [default_let_rule_package]
let_rule_packages
はデフォルトパッケージ
default_let_rule_package
に加えるユーザー定義の
letルールパッケージすべてのリストです。
Categories: Rules and patterns
述語論理 pred_kを変数 a_kの変数やリストに関連づけます。
なので a_kは述語論理が false
以外の何かを返す式にマッチします。
述語論理は関数の名前、ラムダ式、関数コール、最後の引数のないラムダコール、
true
または all
です。
任意の式が true
や all
にマッチします。
もし述語論理が関数コールかラムダコールとして指定されるなら、
テストされる式が引数のリストに追加されます;
マッチが評価される時引数が評価されます。
そうでないなら、述語論理は関数名またはラムダ式として指定され、
テストされる式が唯一の引数です。
matchdeclare
がコールされた時、述語論理関数は定義されている必要はありません;
述語論理はマッチが試みられるまで評価されません。
述語論理は、
true
か false
はもちろん、ブーリアン式を返すかもしれません。
ブーリアン式は、構成されたルール関数内で is
によって評価されるので、
述語論理内部で is
をコールする必要はありません。
もし式がマッチ述語論理を満たすなら、
マッチ変数が式に割り当てられます。
例外は足し算 +
や掛け算 *
のオペランドのマッチ変数です。
足し算と掛け算だけは特別に扱われます;
他のn項演算子(組み込みもユーザー定義も)は通常の関数のように扱われます。
足し算と掛け算の場合、 マッチ変数はマッチ述語論理を満たす唯一の式か、 そんな式の(それぞれ)和または積に割り当てられます。 そんな多項マッチングはどん欲 (greedy)です: 述語論理群はそれらの関連変数がマッチパターンの中で現れる順に評価され、 複数の述語論理を満たす項は、それが満たす最初の述語論理によってマッチされます。 述語論理それぞれは、 次の述語論理が評価される前に 和や積のオペランドすべてに対してテストされます。 加えて、 もし(それぞれ) 0か 1がマッチ述語論理を満たし、かつ、 述語論理を満たす他の項がないなら、 0か1が述語論理の関連マッチ変数に割り当てられます。
足し算と掛け算パターンを処理するアルゴリズムは、 (例えば、「任意のものにマッチする」変数が現れるパターンのように) マッチパターンの中やマッチされる式の中の項の順序付けに依存したいくつかのマッチ結果をもたらします。 しかしながら、もしマッチ述語論理すべてが相互に排他的なら、 1つのマッチ述語論理はべつのものがマッチした項を受け入れられないので、 マッチ結果は順序付けに影響されません。
変数 aを引数として matchdeclare
をコールすると、
もし既に宣言されているなら、
aに関する matchdeclare
プロパティが変わります:
ルールが定義された時、直近の matchdeclare
だけが効果を持ちます。
(matchdeclare
か remove
を介した)
matchdeclare
プロパティへの後の変更は、存在するルールに影響しません。
propvars (matchdeclare)
は
matchdeclare
プロパティを持つ変数すべてのリストを返します。
printprops (a, matchdeclare)
は、
変数 a
に関する述語論理を返します。
printprops (all, matchdeclare)
は、
すべての matchdeclare
変数に関する述語論理のリストを返します。
remove (a, matchdeclare)
は、
aから matchdeclare
プロパティを削除します。
関数 defmatch
, defrule
, tellsimp
, tellsimpafter
,
let
はパターンに対して式をテストするルールを構成します。
matchdeclare
は引数をクォートします。
matchdeclare
はいつも done
を返します。
例:
述語論理は、関数名か、ラムダ式か、最後の引数がない関数コールかラムダコールか、
true
か all
です。
(%i1) matchdeclare (aa, integerp); (%o1) done (%i2) matchdeclare (bb, lambda ([x], x > 0)); (%o2) done (%i3) matchdeclare (cc, freeof (%e, %pi, %i)); (%o3) done (%i4) matchdeclare (dd, lambda ([x, y], gcd (x, y) = 1) (1728)); (%o4) done (%i5) matchdeclare (ee, true); (%o5) done (%i6) matchdeclare (ff, all); (%o6) done |
もし式がマッチ述語論理を満たすなら、 マッチ変数は式に割り当てられます。
(%i1) matchdeclare (aa, integerp, bb, atom); (%o1) done (%i2) defrule (r1, bb^aa, ["integer" = aa, "atom" = bb]); aa (%o2) r1 : bb -> [integer = aa, atom = bb] (%i3) r1 (%pi^8); (%o3) [integer = 8, atom = %pi] |
足し算と掛け算の場合、 マッチ変数は、マッチ述語論理を満たす1つの式か、 そんな式の(それぞれ)和か積に割り当てられるかもしれません。
(%i1) matchdeclare (aa, atom, bb, lambda ([x], not atom(x))); (%o1) done (%i2) defrule (r1, aa + bb, ["all atoms" = aa, "all nonatoms" = bb]); bb + aa partitions `sum' (%o2) r1 : bb + aa -> [all atoms = aa, all nonatoms = bb] (%i3) r1 (8 + a*b + sin(x)); (%o3) [all atoms = 8, all nonatoms = sin(x) + a b] (%i4) defrule (r2, aa * bb, ["all atoms" = aa, "all nonatoms" = bb]); bb aa partitions `product' (%o4) r2 : aa bb -> [all atoms = aa, all nonatoms = bb] (%i5) r2 (8 * (a + b) * sin(x)); (%o5) [all atoms = 8, all nonatoms = (b + a) sin(x)] |
+
と *
の引数をマッチする時、
もしマッチ述語論理すべてが相互に排他的なら、
1つのマッチ述語論理は別のものがマッチした項を受け入れられないので、
マッチ結果は順序付けに影響されません。
(%i1) matchdeclare (aa, atom, bb, lambda ([x], not atom(x))); (%o1) done (%i2) defrule (r1, aa + bb, ["all atoms" = aa, "all nonatoms" = bb]); bb + aa partitions `sum' (%o2) r1 : bb + aa -> [all atoms = aa, all nonatoms = bb] (%i3) r1 (8 + a*b + %pi + sin(x) - c + 2^n); n (%o3) [all atoms = %pi + 8, all nonatoms = sin(x) + 2 - c + a b] (%i4) defrule (r2, aa * bb, ["all atoms" = aa, "all nonatoms" = bb]); bb aa partitions `product' (%o4) r2 : aa bb -> [all atoms = aa, all nonatoms = bb] (%i5) r2 (8 * (a + b) * %pi * sin(x) / c * 2^n); n (b + a) 2 sin(x) (%o5) [all atoms = 8 %pi, all nonatoms = -----------------] c |
関数 propvars
と printprops
はマッチ変数についての情報を返します。
(%i1) matchdeclare ([aa, bb, cc], atom, [dd, ee], integerp); (%o1) done (%i2) matchdeclare (ff, floatnump, gg, lambda ([x], x > 100)); (%o2) done (%i3) propvars (matchdeclare); (%o3) [aa, bb, cc, dd, ee, ff, gg] (%i4) printprops (ee, matchdeclare); (%o4) [integerp(ee)] (%i5) printprops (gg, matchdeclare); (%o5) [lambda([x], x > 100, gg)] (%i6) printprops (all, matchdeclare); (%o6) [lambda([x], x > 100, gg), floatnump(ff), integerp(ee), integerp(dd), atom(cc), atom(bb), atom(aa)] |
Categories: Rules and patterns · Declarations and inferences
デフォルト値: 10000
maxapplydepth
は apply1
と apply2
が探索する最大の深さです。
Categories: Function application
デフォルト値: 10000
maxapplyheight
は applyb1
があきらめる前に到達する最大の高さです。
Categories: Function application
let
関数で直近に定義された代入ルール prod -> replを削除します。
名前を渡すとルールをルールパッケージ名から削除します。
remlet()
やremlet(all)
は
現在のルールパッケージから代入ルールすべてを削除します。
例えばremlet (all, name)
のようにルールパッケージ名を渡すと、
ルールパッケージ nameも削除します。
もし同じ積の代入を変えようと思ったら、
remlet
をコールする必要はなく、
let
関数と新しい置き換えおよび述語論理名を使って
文字通りに同じ積を使って代入を再定義するだけです。
そこで remlet (prod)
をコールすると、元の代入ルールが生き返ります。
remrule
も参照してください。
tellsimp
や tellsimpafter
で定義されたルールを削除します。
Categories: Rules and patterns
tellsimp
や tellsimpafter
で定義されたルールを削除します。
remrule (op, rulename)
は、演算子 opから名前
rulenameを持つルールを削除します。
opが組み込みか
(infix
, prefix
, などで定義されたような)ユーザー定義演算子の時、
opと rulenameはダブルクォートマークでくくられないといけません。
remrule (op, all)
は演算子 opに関するルールすべてを削除します。
remlet
も参照してください。
let
で定義されたルールを削除します。
例:
(%i1) tellsimp (foo (aa, bb), bb - aa); (%o1) [foorule1, false] (%i2) tellsimpafter (aa + bb, special_add (aa, bb)); (%o2) [+rule1, simplus] (%i3) infix ("@@"); (%o3) @@ (%i4) tellsimp (aa @@ bb, bb/aa); (%o4) [@@rule1, false] (%i5) tellsimpafter (quux (%pi, %e), %pi - %e); (%o5) [quuxrule1, false] (%i6) tellsimpafter (quux (%e, %pi), %pi + %e); (%o6) [quuxrule2, quuxrule1, false] (%i7) [foo (aa, bb), aa + bb, aa @@ bb, quux (%pi, %e), quux (%e, %pi)]; bb (%o7) [bb - aa, special_add(aa, bb), --, %pi - %e, %pi + %e] aa (%i8) remrule (foo, foorule1); (%o8) foo (%i9) remrule ("+", ?\+rule1); (%o9) + (%i10) remrule ("@@", ?\@\@rule1); (%o10) @@ (%i11) remrule (quux, all); (%o11) quux (%i12) [foo (aa, bb), aa + bb, aa @@ bb, quux (%pi, %e), quux (%e, %pi)]; (%o12) [foo(aa, bb), bb + aa, aa @@ bb, quux(%pi, %e), quux(%e, %pi)] |
Categories: Rules and patterns
tellsimpafter
に似ていますが、
古いものの前に新しい情報を置くので組み込み整理ルールの前に適用されます。
整理器が働く前に式を変更することが重要な時、
例えば整理器が式について何か「知っている」がそれが返すものが好みでないなら、
tellsimp
を使います。
もし整理器が式の主演算子について何かを「知っている」が単に十分でないなら、
たぶん tellsimpafter
を使いたいでしょう。
パターンは、和や積、変数1つ、数は取れません。
システム変数 rules
は
defrule
, defmatch
, tellsimp
,
tellsimpafter
で定義されたルールのリストです。
例:
(%i1) matchdeclare (x, freeof (%i)); (%o1) done (%i2) %iargs: false$ (%i3) tellsimp (sin(%i*x), %i*sinh(x)); (%o3) [sinrule1, simp-%sin] (%i4) trigexpand (sin (%i*y + x)); (%o4) sin(x) cos(%i y) + %i cos(x) sinh(y) (%i5) %iargs:true$ (%i6) errcatch(0^0); 0 0 has been generated (%o6) [] (%i7) ev (tellsimp (0^0, 1), simp: false); (%o7) [^rule1, simpexpt] (%i8) 0^0; (%o8) 1 (%i9) remrule ("^", %th(2)[1]); (%o9) ^ (%i10) tellsimp (sin(x)^2, 1 - cos(x)^2); (%o10) [^rule2, simpexpt] (%i11) (1 + sin(x))^2; 2 (%o11) (sin(x) + 1) (%i12) expand (%); 2 (%o12) 2 sin(x) - cos (x) + 2 (%i13) sin(x)^2; 2 (%o13) 1 - cos (x) (%i14) kill (rules); (%o14) done (%i15) matchdeclare (a, true); (%o15) done (%i16) tellsimp (sin(a)^2, 1 - cos(a)^2); (%o16) [^rule3, simpexpt] (%i17) sin(y)^2; 2 (%o17) 1 - cos (y) |
Categories: Rules and patterns
組み込み整理ルールの後、 Maxima整理器が適用する整理ルールを定義します。
patternは、
(matchdeclare
で宣言された)パターン変数や他のアトムや演算子
―パターンマッチング用とみなされるリテラル―からなる式です。
replacementが patternにマッチする実際の式に代入されます; replacementの中のパターン変数には実際の式の中でマッチした値が割り当てられます。
patternは主演算子がパターン変数でない任意の非アトム式を取り得ます;
整理ルールは主演算子に関連付けられます。
(以下で記述する1つの例外がありますが、)関数、リスト、配列の名前が、
(パターン変数でなく)ただリテラルとして、
主演算子として patternの中で現れることができます;
これは、パターンとして
もし aa
や bb
がパターン変数なら
aa(x)
や bb[y]
のような式を除外します。
パターン変数である関数、リスト、配列の名前は
patternの中で主演算子以外の演算子として現れることがあります。
上の関数名に関するルールに1つ例外があります。
aa[x](y)
のような式の中の添字付き関数の名前は、
主演算子が aa
でなく Lispアトム mqapply
だからパターン変数にできます。
これは添字付き関数を含む式の表現の結果です。
(もしクォートやフラグ noeval
を通して抑制されないなら)
整理ルールは、評価の後、適用されます。
tellsimpafter
で確立されたルールは、
組み込みルールの後、それらが定義された順に適用されます。
ルールはボトムアップに適用されます。
すなわち、式全体への適用の前に、最初、部分式に適用されます。
ルールすべてが適用されることを保証するために、
(例えば、クォートクォート演算子 ''
やフラグ infeval
を介して)
結果を繰り返し整理する必要があるかもしれません。
パターン変数は、整理ルールの中でローカル変数として扱われます。
一旦ルールが定義されると、パターン変数の値はルールに影響せず、ルールによって影響されません。
成功したルールマッチの結果となるパターン変数への割り当ては、
パターン変数の現在の割り当て(またはその欠落)に影響しません。
しかしながら、 Maximaの中のアトムすべてで、
(put
や関連関数で定義された)パターン変数のプロパティはグローバルです。
tellsimpafter
が構成するルールは
patternの主演算子の名前を取って名付けられます。
組み込み演算子や
infix
, prefix
, postfix
, matchfix
,
nofix
で定義されたユーザー定義演算子に関するルールは、
Lisp識別子である名前を持ちます。
他の関数に関するルールは Maxima識別子である名前を持ちます。
名詞と動詞形の扱いは少し混乱しています。 もしルールが名詞(または動詞)形に関して定義されて、 対応する動詞(または名詞)形に関するルールが既に存在しているなら、 新しく定義されたルールは両方の形式(名詞と動詞)に適用されます。 もし対応する動詞(名詞)形に関するルールが存在しないなら、 新しく定義されたルールは名詞(または動詞)形にだけ適用されます。
tellsimpafter
で構成されたルールは通常の Lisp関数です。
もしルール名が $foorule1
なら、
構成子 :lisp (trace $foorule1)
は関数をトレースし、
:lisp (symbol-function '$foorule1)
は定義を表示します。
tellsimpafter
は引数をクォートします。
tellsimpafter
は patternの主演算子に関するルールのリストを返します。
このリストは新しく確立されたルールを含みます。
matchdeclare
, defmatch
, defrule
, tellsimp
,
let
, kill
, remrule
, clear_rules
も参照してください。
例:
patternは主演算子がパターン変数でない任意の非アトム式を取り得ます。
(%i1) matchdeclare (aa, atom, [ll, mm], listp, xx, true)$ (%i2) tellsimpafter (sin (ll), map (sin, ll)); (%o2) [sinrule1, simp-%sin] (%i3) sin ([1/6, 1/4, 1/3, 1/2, 1]*%pi); 1 sqrt(2) sqrt(3) (%o3) [-, -------, -------, 1, 0] 2 2 2 (%i4) tellsimpafter (ll^mm, map ("^", ll, mm)); (%o4) [^rule1, simpexpt] (%i5) [a, b, c]^[1, 2, 3]; 2 3 (%o5) [a, b , c ] (%i6) tellsimpafter (foo (aa (xx)), aa (foo (xx))); (%o6) [foorule1, false] (%i7) foo (bar (u - v)); (%o7) bar(foo(u - v)) |
ルールはそれらが定義された順に適用されます。 もし2つのルールが式にマッチできるなら最初に定義されたルールが適用されます。
(%i1) matchdeclare (aa, integerp); (%o1) done (%i2) tellsimpafter (foo (aa), bar_1 (aa)); (%o2) [foorule1, false] (%i3) tellsimpafter (foo (aa), bar_2 (aa)); (%o3) [foorule2, foorule1, false] (%i4) foo (42); (%o4) bar_1(42) |
整理ルールの中でパターン変数はローカル変数として扱われます。
(defmatch
と比較してください。パターン変数をグローバル変数として扱います。)
(%i1) matchdeclare (aa, integerp, bb, atom); (%o1) done (%i2) tellsimpafter (foo(aa, bb), bar('aa=aa, 'bb=bb)); (%o2) [foorule1, false] (%i3) bb: 12345; (%o3) 12345 (%i4) foo (42, %e); (%o4) bar(aa = 42, bb = %e) (%i5) bb; (%o5) 12345 |
アトムすべてと同様に、
たとえ値がローカルでもパターン変数のプロパティはグローバルです。
この例では、割り当てプロパティは define_variable
を介して宣言されます。
Maximaの至る所でこれはアトム bb
のプロパティです。
(%i1) matchdeclare (aa, integerp, bb, atom); (%o1) done (%i2) tellsimpafter (foo(aa, bb), bar('aa=aa, 'bb=bb)); (%o2) [foorule1, false] (%i3) foo (42, %e); (%o3) bar(aa = 42, bb = %e) (%i4) define_variable (bb, true, boolean); (%o4) true (%i5) foo (42, %e); Error: bb was declared mode boolean, has value: %e -- an error. Quitting. To debug this try debugmode(true); |
ルールは主演算子の名前を取って名付けられます。 組み込みやユーザー定義の演算子に関するルール名は Lisp識別子で、 一方、他の関数に関する名前は Maxima識別子です。
(%i1) tellsimpafter (foo (%pi + %e), 3*%pi); (%o1) [foorule1, false] (%i2) tellsimpafter (foo (%pi * %e), 17*%e); (%o2) [foorule2, foorule1, false] (%i3) tellsimpafter (foo (%i ^ %e), -42*%i); (%o3) [foorule3, foorule2, foorule1, false] (%i4) tellsimpafter (foo (9) + foo (13), quux (22)); (%o4) [+rule1, simplus] (%i5) tellsimpafter (foo (9) * foo (13), blurf (22)); (%o5) [*rule1, simptimes] (%i6) tellsimpafter (foo (9) ^ foo (13), mumble (22)); (%o6) [^rule1, simpexpt] (%i7) rules; (%o7) [foorule1, foorule2, foorule3, +rule1, *rule1, ^rule1] (%i8) foorule_name: first (%o1); (%o8) foorule1 (%i9) plusrule_name: first (%o4); (%o9) +rule1 (%i10) remrule (foo, foorule1); (%o10) foo (%i11) remrule ("^", ?\^rule1); (%o11) ^ (%i12) rules; (%o12) [foorule2, foorule3, +rule1, *rule1] |
加工された (worked)例: 反可換乗算。
(%i1) gt (i, j) := integerp(j) and i < j; (%o1) gt(i, j) := integerp(j) and i < j (%i2) matchdeclare (i, integerp, j, gt(i)); (%o2) done (%i3) tellsimpafter (s[i]^^2, 1); (%o3) [^^rule1, simpncexpt] (%i4) tellsimpafter (s[i] . s[j], -s[j] . s[i]); (%o4) [.rule1, simpnct] (%i5) s[1] . (s[1] + s[2]); (%o5) s . (s + s ) 1 2 1 (%i6) expand (%); (%o6) 1 - s . s 2 1 (%i7) factor (expand (sum (s[i], i, 0, 9)^^5)); (%o7) 100 (s + s + s + s + s + s + s + s + s + s ) 9 8 7 6 5 4 3 2 1 0 |
Categories: Rules and patterns
kill (rules)
を実行し、足し算
+
, 掛け算 *
, べき ^
に関して次のルール番号を 1に再設定します。
Categories: Rules and patterns
[ << ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This document was generated by 市川雄二 on June, 21 2016 using texi2html 1.76.