[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

34. Rules and Patterns


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

34.1 Introduction to Rules and Patterns

この節ではユーザー定義のパターンマッチングと整理ルールを記述します。 幾分違ったパターンマッチング体系を実装した2つの関数グループがあります。 1つのグループは、tellsimp, tellsimpafter, defmatch, defrule, apply1, applyb1, apply2です。 他のグループは、let, letsimpです。 どちらの体系も matchdeclareが宣言したパターン変数を使ってパターンを定義します。

tellsimptellsimpafterが定義するパターンマッチングルールは Maximaの整理器によって自動的に適用されます。 defmatch, defrule, letが定義するルールは 明示的に関数をコールすることで適用されます。

更に、 tellratが多項式に適用するルール用メカニズムと、 affineパッケージの可換/非可換代数用メカニズムがあります。

Categories:  Simplification · Rules and patterns


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

34.2 Functions and Variables for Rules and Patterns

関数: apply1 (expr, rule_1, ..., rule_n)

rule_1exprに失敗するまで繰り返し適用して、 それから同じルールを exprの部分式すべてに左から右へ、部分式すべてで rule_1が失敗するまで繰り返し適用します。

この方法で exprを変換した結果を expr_2と呼ぶことにします。 次に rule_2expr_2の最上部から始めて同じ方法で適用します。 rule_nが最後の部分式上で失敗した時、結果を返します。

maxapplydepthapply1apply2が処理する最も深い部分式の深さです。

applyb1, apply2, letも参照してください。

Categories:  Rules and patterns

関数: apply2 (expr, rule_1, ..., rule_n)

もし rule_1が与えられた部分式上で失敗したら、 rule_2を繰り返し適用し、などなどと続きます。 すべてのルールが与えられた部分式上で失敗した時だけ、 ルールの全組が次の部分式に繰り返し適用されます。 もしルールの1つが成功したら、 同じ部分式が最初のルールから再処理されます。

maxapplydepthapply1apply2が処理する最も深い部分式の深さです。

apply1letも参照してください。

Categories:  Rules and patterns

関数: applyb1 (expr, rule_1, ..., rule_n)

失敗するまで繰り返し exprの最も深い部分式に rule_1を適用し、 その後、 rule_1がトップレベルの式で失敗するまで 同じルールを1つ高いレベル(すなわち、より大きな部分式)に適用します。 その後、rule_2rule_1の結果に同様に適用します。 rule_nがトップレベルの式に適用された後、結果を返します。

applyb1apply1に似ていますが、トップダウンからの代わりにボトムアップから働きます。

maxapplyheightapplyb1があきらめる前に届く最大の高さです

apply1, apply2, letも参照してください。

Categories:  Rules and patterns

オプション変数: current_let_rule_package

デフォルト値: 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

default_let_rule_packageは、 ユーザーがletで明示的に設定したり、 current_let_rule_packageの値を変更することで明示的に設定したりしない時 使われるルールの名前です。

Categories:  Rules and patterns

関数: defmatch  
    defmatch (progname, pattern, x_1, …, x_n)  
    defmatch (progname, pattern)

patternにマッチするか見るために exprをテストする関数 progname(expr, x_1, ..., x_n)を定義します。

(引数として与えられているなら、) patternはパターン引数 x_1, ..., x_nを含む式です。 パターン引数は defmatchの引数として明示的に与えられます。 一方、 matchdeclare関数がパターン変数を宣言します。 matchdeclareのパターン変数か defmatchのパターン引数として宣言されていない任意の変数は それ自身とのみマッチします。

生成関数 prognameの最初の引数はパターンに対してマッチされる式であり、 他の引数はパターンの中のダミー変数 x_1, ..., x_nに対応する実際の引数です。

もしマッチが成功したなら、 prognameは、 左辺がパターン引数やパターン変数で、右辺がパターン引数や変数がマッチした部分式の 等式のリストを返します。 パターン変数はそれらがマッチした部分式に割り当てられますが、 パターン引数には割り当てられません。 もしマッチが失敗したら、 prognamefalseを返します。

リテラルパターン(すなわち、パターン引数もパターン変数も含まないパターン)は、 もしマッチが成功したら trueを返します。

matchdeclare, defrule, tellsimp, tellsimpafterも参照してください。

例:

abxを含まず、 aが非ゼロであるような形式 a*x + bかどうか見るために exprをテストする関数 linearp(expr, x)を定義します。 パターン引数 xdefmatchに与えられているので、 このマッチ関数は任意の変数に関する線形式にマッチします。

 
(%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

abxを含まず、 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

関数: defrule (rulename, pattern, replacement)

与えられたパターンに関する置き換えルールを定義し、名付けます。 もし rulenameと名付けられたルールが (apply1, applyb1, apply2によって)式に適用されるなら、 パターンにマッチするすべての部分式は replacementで置き換えられます。 パターンマッチが値を割り当てる replacementの中の変数すべてはその後整理される置き換えの中のそれらの値を割り当てられます。

ルールそれ自身は、パターンマッチと置き換えを演算 1つにして式を変換する関数として扱うことができます。 マッチが失敗したらルール関数は falseを返します。

Categories:  Rules and patterns

関数: disprule  
    disprule (rulename_1, …, rulename_2)  
    disprule (all)

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) ev(%);
(%o6) [foorule1 : foo(x, y) -> baz(y) + bar(x),
     +rule1 : y + x -> special_add(x, y), quux : mumble(x) -> []]

関数: let  
    let (prod, repl, predname, arg_1, …, arg_n)  
    let ([prod, repl, predname, arg_1, …, arg_n], package_name)

prodreplで置き換えられるような letsimpのための代入ルールを定義します。 prodは以下の項の正または負のべきの積です:

正のべきの項は少なくともそのべきを持つ項だけにマッチするでしょう。 一方、負のべきの項は少なくとも負としてのべきをもつ項だけにマッチするでしょう。 prodの中の負のべきの場合、 スイッチ letrattrueに設定しなければいけません。 letratも参照してください。

もし述語論理が引数のリストが続く let関数に含まれるなら、 arg_i'arg_iにマッチした値である場合、 predname (arg_1', ..., arg_n')trueに評価される時だけ試験的なマッチ (すなわち、述語論理が省略されたなら受け入れられるもの)が受け入れられます。 arg_iは任意のアトム名や prodの中に現れる任意の核の引数を取り得ます。 replは任意の有理式を取り得ます。 もし任意のアトムや prodからの引数が replの中に現れるなら、適切な代入が行われます。

グローバルフラグ letratletsimpによる商の整理を制御します。 letratfalseの時、 letsimpexprの分子と分母をそれぞれ整理し、商を整理はしません。 n!/nのような代入は (n-1)!に進み失敗します。 letrattrueの時、分子、分母、商がその順番で整理されます。

これらの代入関数は、同時にいくつかのルールパッケージを使うことを許します。 ルールパッケージそれぞれは任意の数の 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_packagedefault_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

オプション変数: letrat

デフォルト値: false

letratfalseの時、 letsimpは比の分子と分母それぞれを整理し、商を整理しません。

letrattrueの時、 分子、分母、商はその順番に整理されます。

 
(%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 ()  
    letrules (package_name)

ルールパッケージのルールを表示します。 letrules ()は現在のルールパッケージのルールを表示します。 letrules (package_name)package_nameのルールを表示します。

現在のルールパッケージは current_let_rule_packageによって指名されます。 もし他に指定されないなら、 current_let_rule_packagedefault_let_rule_packageがデフォルト値になります。

dispruleも参照してください それは tellsimptellsimpafterが定義するルールを表示します。

Categories:  Rules and patterns

関数: letsimp  
    letsimp (expr)  
    letsimp (expr, package_name)  
    letsimp (expr, package_name_1, …, package_name_n)

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

オプション変数: let_rule_packages

デフォルト値: [default_let_rule_package]

let_rule_packagesはデフォルトパッケージ default_let_rule_packageに加えるユーザー定義の letルールパッケージすべてのリストです。

Categories:  Rules and patterns

関数: matchdeclare (a_1, pred_1, ..., a_n, pred_n)

述語論理 pred_kを変数 a_kの変数やリストに関連づけます。 なので a_kは述語論理が false以外の何かを返す式にマッチします。

述語論理は関数の名前、ラムダ式、関数コール、最後の引数のないラムダコール、 trueまたは allです。 任意の式が trueallにマッチします。 もし述語論理が関数コールかラムダコールとして指定されるなら、 テストされる式が引数のリストに追加されます; マッチが評価される時引数が評価されます。 そうでないなら、述語論理は関数名またはラムダ式として指定され、 テストされる式が唯一の引数です。 matchdeclareがコールされた時、述語論理関数は定義されている必要はありません; 述語論理はマッチが試みられるまで評価されません。

述語論理は、 truefalseはもちろん、ブーリアン式を返すかもしれません。 ブーリアン式は、構成されたルール関数内で isによって評価されるので、 述語論理内部で isをコールする必要はありません。

もし式がマッチ述語論理を満たすなら、 マッチ変数が式に割り当てられます。 例外は足し算 +や掛け算 *のオペランドのマッチ変数です。 足し算と掛け算だけは特別に扱われます; 他のn項演算子(組み込みもユーザー定義も)は通常の関数のように扱われます。

足し算と掛け算の場合、 マッチ変数はマッチ述語論理を満たす唯一の式か、 そんな式の(それぞれ)和または積に割り当てられます。 そんな多項マッチングはどん欲 (greedy)です: 述語論理群はそれらの関連変数がマッチパターンの中で現れる順に評価され、 複数の述語論理を満たす項は、それが満たす最初の述語論理によってマッチされます。 述語論理それぞれは、 次の述語論理が評価される前に 和や積のオペランドすべてに対してテストされます。 加えて、 もし(それぞれ) 0か 1がマッチ述語論理を満たし、かつ、 述語論理を満たす他の項がないなら、 0か1が述語論理の関連マッチ変数に割り当てられます。

足し算と掛け算パターンを処理するアルゴリズムは、 (例えば、「任意のものにマッチする」変数が現れるパターンのように) マッチパターンの中やマッチされる式の中の項の順序付けに依存したいくつかのマッチ結果をもたらします。 しかしながら、もしマッチ述語論理すべてが相互に排他的なら、 1つのマッチ述語論理はべつのものがマッチした項を受け入れられないので、 マッチ結果は順序付けに影響されません。

変数 aを引数として matchdeclareをコールすると、 もし既に宣言されているなら、 aに関する matchdeclareプロパティが変わります: ルールが定義された時、直近の matchdeclareだけが効果を持ちます。 (matchdeclareremoveを介した) 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を返します。

例:

述語論理は、関数名か、ラムダ式か、最後の引数がない関数コールかラムダコールか、 trueallです。

 
(%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

関数 propvarsprintpropsはマッチ変数についての情報を返します。

 
(%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)]

オプション変数: maxapplydepth

デフォルト値: 10000

maxapplydepthapply1apply2が探索する最大の深さです。

Categories:  Function application

オプション変数: maxapplyheight

デフォルト値: 10000

maxapplyheightapplyb1があきらめる前に到達する最大の高さです。

Categories:  Function application

関数: remlet  
    remlet (prod, name)  
    remlet ()  
    remlet (all)  
    remlet (all, name)

let関数で直近に定義された代入ルール prod -> replを削除します。 名前を渡すとルールをルールパッケージ名から削除します。

remlet()remlet(all)は 現在のルールパッケージから代入ルールすべてを削除します。 例えばremlet (all, name)のようにルールパッケージ名を渡すと、 ルールパッケージ nameも削除します。

もし同じ積の代入を変えようと思ったら、 remletをコールする必要はなく、 let関数と新しい置き換えおよび述語論理名を使って 文字通りに同じ積を使って代入を再定義するだけです。 そこで remlet (prod)をコールすると、元の代入ルールが生き返ります。

remruleも参照してください。 tellsimptellsimpafterで定義されたルールを削除します。

Categories:  Rules and patterns

関数: remrule  
    remrule (op, rulename)  
    remrule (op, all)

tellsimptellsimpafterで定義されたルールを削除します。

remrule (op, rulename)は、演算子 opから名前 rulenameを持つルールを削除します。 opが組み込みか (infix, prefix, などで定義されたような)ユーザー定義演算子の時、 oprulenameはダブルクォートマークでくくられないといけません。

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

関数: tellsimp (pattern, replacement)

tellsimpafterに似ていますが、 古いものの前に新しい情報を置くので組み込み整理ルールの前に適用されます。

整理器が働く前に式を変更することが重要な時、 例えば整理器が式について何か「知っている」がそれが返すものが好みでないなら、 tellsimpを使います。 もし整理器が式の主演算子について何かを「知っている」が単に十分でないなら、 たぶん tellsimpafterを使いたいでしょう。

パターンは、和や積、変数1つ、数は取れません。

システム変数 rulesdefrule, 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

関数: tellsimpafter (pattern, replacement)

組み込み整理ルールの後、 Maxima整理器が適用する整理ルールを定義します。 patternは、 (matchdeclareで宣言された)パターン変数や他のアトムや演算子 ―パターンマッチング用とみなされるリテラル―からなる式です。

replacementpatternにマッチする実際の式に代入されます; replacementの中のパターン変数には実際の式の中でマッチした値が割り当てられます。

patternは主演算子がパターン変数でない任意の非アトム式を取り得ます; 整理ルールは主演算子に関連付けられます。 (以下で記述する1つの例外がありますが、)関数、リスト、配列の名前が、 (パターン変数でなく)ただリテラルとして、 主演算子として patternの中で現れることができます; これは、パターンとして もし aabbがパターン変数なら 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は引数をクォートします。 tellsimpafterpatternの主演算子に関するルールのリストを返します。 このリストは新しく確立されたルールを含みます。

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

関数: clear_rules ()

kill (rules)を実行し、足し算 +, 掛け算 *, べき ^に関して次のルール番号を 1に再設定します。

Categories:  Rules and patterns


[ << ] [ >> ]           [Top] [Contents] [Index] [ ? ]

This document was generated by 市川雄二 on June, 5 2017 using texi2html 1.76.