Next: , Previous:   [Contents][Index]

37 Program Flow


37.1 Lisp and Maxima

MaximaはLispで書かれており、 Lisp関数や変数をMaximaからアクセスしたり、その逆が簡単にできます。 LispとMaximaのシンボルは命名の慣例で区別されます。 ドル記号$で始まるLispシンボルは、ドル記号なしのMaximaシンボルに対応します。 クエスチョンマーク?で始まるMaximaシンボルは、クエスチョンマークなしのLispシンボルに対応します。 例えば、MaximaシンボルfooはLispシンボル$FOOに対応し、 Maximaシンボル?fooはLispシンボルFOOに対応します。 ?fooは、?fooの間にスペースを入れずに書くことに注意してください。でないと、それはdescribe ("foo")に間違えられます。

Lispシンボルの中に、ハイフン-やアスタリスク*、他の特殊文字があれば、 Maximaのコードの中では、バックスラッシュ\でエスケープしないといけません。 例えば、Lispの識別子 *foo-bar*は、Maximaでは、?\*foo\-bar\*と書きます。

Maximaセッションの中で、Lispコードを実行できます。 特殊コマンド:lispを使って、 (1つか複数のフォームを含む)Lispの一行を実行できます。例えば、

(%i1) :lisp (foo $x $y)

は、Lisp関数fooをMaxima変数x, yを引数としてコールします。 :lisp構成子は 対話プロンプトやbatchdemoによって処理されるファイルの中で使えますが、 load, batchload, translate_file, compile_fileが 処理するファイルの中では使えません。

関数to_lisp()を実行すると、対話的なLispセッションが始まります。 (to-maxima)を入力すると、Lispセッションを終了してMaximaに戻ります。

Lispの関数や変数を、Maximaで通常の関数名、変数名(特殊な句読点のない名前)に見せるには、 Lispの名前をドル記号$で始めなければなりません。

Maximaでは、識別子の中の大文字、小文字が区別されます。 LispとMaximaの間の名前変換を決めるルールがあります。

  1. 縦棒で囲まれていないLisp識別子は、Maximaの小文字の識別子に対応します。 Lisp識別子が大文字でも小文字でも混ざっていても無視されます。 例えば、Lispの$foo$FOO$Fooはすべて Maximaのfooに対応します。 でも、これはデフォルトで、 Lispリーダが$foo, $FOO, $Fooを Lispシンボル$FOOに変換するからです。
  2. すべて大文字かすべて小文字で、縦棒で囲まれたLisp識別子は、大文字小文字を逆にしたMaximaの識別子に対応します。 例えば、Lispの|$FOO|, |$foo|はそれぞれ、Maximaのfoo, FOOに対応します。
  3. 大文字小文字が混ざっていて、縦棒で囲まれたLisp識別子は、そのままMaximaの識別子に対応します。 例えば、Lispの|$Foo|はMaximaのFooに対応します。

#$Lispマクロを使うと、Maximaの式をLispコードの中で使うことができます。 #$expr$はMaximaの式exprと同値なLispの式に展開されます。

(msetq $foo #$[x, y]$)

これは以下のように入力するのと同じ効果です。

(%i1) foo: [x, y];

Lisp関数displaは、Maximaフォーマットで式を表示します。

(%i1) :lisp #$[x, y, z]$ 
((MLIST SIMP) $X $Y $Z)
(%i1) :lisp (displa '((MLIST SIMP) $X $Y $Z))
[x, y, z]
NIL

Maximaで定義された関数は、通常のLisp関数ではありません。 Lisp関数mfuncallは、Maxima関数をコールします。 例えば:

(%i1) foo(x,y) := x*y$
(%i2) :lisp (mfuncall '$foo 'a 'b)
((MTIMES SIMP) A B)

以下のLisp関数は、Maximaパッケージの中でシャドウされています。

   complement     continue      //
   float          functionp     array
   exp            listen        signum
   atan           asin          acos
   asinh          acosh         atanh
   tanh           cosh          sinh
   tan            break         gcd

37.2 Garbage Collection

数式処理は膨大なゴミ(最終的には使われない一時的な、もしくは中間の結果)を生む傾向があり、 ゴミの効率的な取り扱いは、プログラムをうまく完了させるために非常に重要な場合があります。

(SunOS 4.0やBSDの幾つかを含む)mprotectシステムコールが利用可能なUNIXシステム 上でのGCLでは、階層化(stratified)ガーベッジコレクションが利用可能です。 これは、ガーベッジコレクションを最近書き込まれたページに限定します。 GCLドキュメントのALLOCATEやGBCを参照してください。 Lispレベルで(setq si::*notify-gbc* t)を実行すると、どの領域がより多くの空間を必要としているか決めるのに役立つでしょう。

Maximaを走らせる他のLispについては、 そのLispのGCの制御の仕方に関するドキュメントを調べてください。


37.3 Introduction to Program Flow

Maximaは、 goのようなもっとプリミティブな構成子はもちろん、 繰り返しのためにdoループを提供します。


37.4 Functions and Variables for Program Flow

関数: backtrace ()
関数: backtrace (n)

コールスタック、すなわち、 現在アクティブな関数をコールした関数のリスト、を印字します。

backtrace()はコールスタック全体を印字します。

backtrace (n)は、 現在アクティブな関数を含めて、n個の直近の関数を印字します。

backtraceは、 (デバッグの文脈でだけでなく、) スクリプト、関数、対話プロンプトからコールすることができます。

例:

  • backtrace()はコールスタック全体を印字します。
    (%i1) h(x) := g(x/7)$
    (%i2) g(x) := f(x-11)$
    (%i3) f(x) := e(x^2)$
    (%i4) e(x) := (backtrace(), 2*x + 13)$
    (%i5) h(10);
    #0: e(x=4489/49)
    #1: f(x=-67/7)
    #2: g(x=10/7)
    #3: h(x=10)
                                  9615
    (%o5)                         ----
                                   49
    
  • backtrace (n)は、 現在アクティブな関数を含めて、n個の直近の関数を印字します。
    (%i1) h(x) := (backtrace(1), g(x/7))$
    (%i2) g(x) := (backtrace(1), f(x-11))$
    (%i3) f(x) := (backtrace(1), e(x^2))$
    (%i4) e(x) := (backtrace(1), 2*x + 13)$
    (%i5) h(10);
    #0: h(x=10)
    #0: g(x=10/7)
    #0: f(x=-67/7)
    #0: e(x=4489/49)
                                  9615
    (%o5)                         ----
                                   49
    
特殊演算子: do

do文は繰り返しを実行するために使われます。 その強力な一般性のために、 do文は2編で記述されます。 最初、通常の形式が (Fortran, Algol, PL/I, など)いくつかの他のプログラミング言語の中で使われるそれ との類似で与えられます; それから、他の特長が言及されます。

この形式の、終了条件に関してだけ違う3つの別形があります。 それらは:

  • for variable: initial_value step increment thru limit do body
  • for variable: initial_value step increment while condition do body
  • for variable: initial_value step increment unless condition do body

(代わりに、stepは終了条件や範囲の後与えられるかもしれません。)

initial_value, increment, limit, bodyは、 任意の式を取り得ます。 もし増分が1なら、 "step 1"は省略できます。

do文の実行は、最初 initial_valuevariable (今後、制御変数と呼びます) に割り当てることによって処理されます。 そして: (1) もし制御変数が thru指定の範囲を越えたら、もしくは、 unlessの条件が trueなら、 もしくは、 whileの条件が falseなら、 doは終了します。 (2) bodyが評価されます。 (3) 増分が制御変数に足されます。 終了条件が満たされるまで、 いずれかが満たされる時 doが終了する複数の終了条件を与えることもできます。

一般的に、 thruテストは、 もし incrementが非負なら、制御変数が limitよりも大きい時、 または、もし incrementが負なら、制御変数が limitよりも小さい時、 満たされます。 incrementlimitは、この不等式が決定できる限り、数値でない式も取り得ます。 しかしながら、 do文が入力された時 incrementが構文法的に負(例えば負の数)でない限り、 Maximaは、 doが実行される時、正と仮定します。 もし正でないなら、 doは適切に終了しないかもしれません。

limit, increment, 終了条件は、ループを通して毎回評価されることに注意してください。 もしこれらのいずれかがおおくの計算を含み、 bodyの実行中すべてで変わらない結果をもたらすなら、 doに先立って変数をそれらの値に設定し、その変数を do形式の中で使うことはもっと効率的です。

do文が通常返す値は、アトム doneです。 しかしながら、 早い時点で doから抜けて任意の望みの値を与えるために、 関数 returnbodyの中で使うことができます。 しかしながら、 blockの中で起こる doの中の returnは、 doだけから抜けて、 blockからは抜けないことに注意してください。 doから囲んでいる blockに抜けるために、 go関数は使えないことにも注意してください。

制御変数はいつも doにローカルです。

従って、 doの外側の同じ名前を持つ変数の値に影響することなく、任意の変数が使えます。 制御変数は、 doが終了した後、バインドされていません。

(%i1) for a:-3 thru 26 step 7 do display(a)$
                             a = - 3

                              a = 4

                             a = 11

                             a = 18

                             a = 25
(%i1) s: 0$
(%i2) for i: 1 while i <= 10 do s: s+i;
(%o2)                         done
(%i3) s;
(%o3)                          55

条件while i <= 10は、 unless i > 10と、また、thru 10と同値であることに注意してください。

(%i1) series: 1$
(%i2) term: exp (sin (x))$
(%i3) for p: 1 unless p > 7 do
          (term: diff (term, x)/p, 
           series: series + subst (x=0, term)*x^p)$
(%i4) series;
                  7    6     5    4    2
                 x    x     x    x    x
(%o4)            -- - --- - -- - -- + -- + x + 1
                 90   240   15   8    2

以上は、e^sin(x)のTaylor級数の8項を与えます。

(%i1) poly: 0$
(%i2) for i: 1 thru 5 do
          for j: i step -1 thru 1 do
              poly: poly + i*x^j$
(%i3) poly;
                  5      4       3       2
(%o3)          5 x  + 9 x  + 12 x  + 14 x  + 15 x
(%i4) guess: -3.0$
(%i5) for i: 1 thru 10 do
          (guess: subst (guess, x, 0.5*(x + 10/x)),
           if abs (guess^2 - 10) < 0.00005 then return (guess));
(%o5)                  - 3.162280701754386

この例は、 Newton-Raphson反復を最大10回使って、 10の負の平方根を計算します。 もし収束基準が満たされないなら、 戻り値はdoneになります。

いつもある量を制御変数に加える代わりに、 繰り返しそれぞれで量をある他の方法で換えたい時があるかもしれません。 この場合、 step incrementの代わりに next expressionを使うことができます。 これは、ループの間、 制御変数が毎回expressionの評価結果に設定されるようにします。

(%i6) for count: 2 next 3*count thru 20 do display (count)$
                            count = 2

                            count = 6

                           count = 18

for variable: value ...do...の代わりとして、 構文法for variable from value ...do...が使えます。 これは、 from valuestepnext値の後や終了条件の後に置くことを許します。 もしfrom valueが省略されたら、 初期値として1が使われます。

制御変数が実際には決して使われないような繰り返しを実行することに興味があることがあるかもしれません。 それゆえに、 貧弱な初期推測を使って5の平方根を計算する以下の例にあるように、 初期化と更新情報を省略して終了条件だけ与えることが許されます。

(%i1) x: 1000$
(%i2) thru 20 do x: 0.5*(x + 5.0/x)$
(%i3) x;
(%o3)                   2.23606797749979
(%i4) sqrt(5), numer;
(%o4)                   2.23606797749979

もし望むなら、終了条件さえ完全に省略し、 無限にbodyを評価し続けるdo bodyだけを与えることもできます。 この場合、関数returndoの実行を終了するのに使われるべきです。

(%i1) newton (f, x):= ([y, df, dfx], df: diff (f ('x), 'x),
          do (y: ev(df), x: x - f(x)/y, 
              if abs (f (x)) < 5e-6 then return (x)))$
(%i2) sqr (x) := x^2 - 5.0$
(%i3) newton (sqr, 1000);
(%o3)                   2.236068027062195

(returnが実行された時、 xの現在値を doの値として返そうとすることに注意してください。 doがブロックの最後の文なので、 blockから抜けて、 doの値が blockの値として返されます。)

doのもう1つ別の形式がMaximaで利用可能です。構文法は:

for variable in list end_tests do body

listの要素は、 bodyの繰り返しのそれぞれで variableに連続的に割り当てられる任意の式です。 オプションの終了テストend_testsは、 doの実行を終了するのに使うことができます; そうでなければ、 listが使い果たされた時、または、 bodyの中で returnが実行された時、 終了します。 (実際には、listは非アトムの任意の式を取り得えて、連続的な部分が取られます。)

(%i1)  for f in [log, rho, atan] do ldisp(f(1))$
(%t1)                                  0
(%t2)                                rho(1)
                                     %pi
(%t3)                                 ---
                                      4
(%i4) ev(%t3,numer);
(%o4)                             0.78539816
関数: errcatch (expr_1, …, expr_n)

expr_1, …, expr_nを1つずつ評価し、 もしエラーが起こらないなら、[expr_n] (リスト)を返します。 もしいずれかの引数の評価中にエラーが起こったら、 errcatch はエラーが伝搬することを抑制し、 引数をこれ以上評価せずに空のリスト[]を返します。

errcatchは もしエラーがチャッチされないならbatchを終了させるエラーが起こるかもしれないと疑うような batchファイルで役立ちます。

関数: error (expr_1, ..., expr_n)
システム変数: error

expr_1, ..., expr_nを評価して印字します。 そして、エラーがあれば、トップレベルMaximaか直近のerrcatchに戻るようにします。

変数errorはエラーを記述するリストに設定されます。 errorの最初の要素はフォーマット文字列です。 引数expr_1, ..., expr_nの中の文字列すべてを結合したものです。 残りの要素は文字列でない引数の値です。

errormsg()errorをフォーマットし印字します。 これは直近のエラーメッセージを効果的に再印字します。

オプション変数: error_size

デフォルト値: 10

error_sizeは、 現れる式のサイズに従って、エラーメッセージを変更します。 もし式のサイズが、Lisp関数ERROR-SIZEによって決定されるように) error_sizeより大きいなら、 式は、メッセージの中で、シンボルで置き換えられ、 シンボルは式に割り当てられます。 シンボルはリストerror_symsから取られます。

そうでなければ、式はerror_sizeより小さく、 メッセージの中に式が表示されます。

errorerror_symsも参照してください。

例:

Uのサイズは、ERROR-SIZEで決められるように、24です。

(%i1) U: (C^D^E + B + A)/(cos(X-1) + 1)$

(%i2) error_size: 20$

(%i3) error ("Example expression is", U);

Example expression is errexp1
 -- an error.  Quitting.  To debug this try debugmode(true);
(%i4) errexp1;
                            E
                           D
                          C   + B + A
(%o4)                    --------------
                         cos(X - 1) + 1
(%i5) error_size: 30$

(%i6) error ("Example expression is", U);

                         E
                        D
                       C   + B + A
Example expression is --------------
                      cos(X - 1) + 1
 -- an error.  Quitting.  To debug this try debugmode(true);
オプション変数: error_syms

デフォルト値: [errexp1, errexp2, errexp3]

エラーメッセージの中で、 error_sizeより大きな式はシンボルで置き換えられ、 シンボルは式に設定されます。 シンボルはリストerror_symsから取られます。 最初の大きすぎる式は、error_syms[1]で置き換えられ、 2番目は、error_syms[2]で置き換えられ、などなど。

もし大きすぎる式がerror_symsの要素よりもあれば、 シンボルは自動的に構成されます。 n番目のシンボルはconcat ('errexp, n)と同値です。

errorerror_sizeも参照してください。

関数: errormsg ()

直近のエラーメッセージを再印字します。 変数errorはメッセージを保持し、 errormsgはそれをフォーマットし印字します。

オプション変数: errormsg

デフォルト値: true

falseの時、エラーメッセージの出力は抑制されます。

オプション変数errormsgは ブロックの中でローカル値に設定することはできません。 errormsgのグローバル値が常に存在します。

(%i1) errormsg;
(%o1)                                true
(%i2) sin(a,b);
Wrong number of arguments to sin
 -- an error. To debug this try: debugmode(true);
(%i3) errormsg:false;
(%o3)                                false
(%i4) sin(a,b);

 -- an error. To debug this try: debugmode(true);

オプション変数errormsgはブロックの中でローカル値に設定できません。

(%i1) f(bool):=block([errormsg:bool], 
                     print ("value of errormsg is",errormsg))$
(%i2) errormsg:true;
(%o2)                                true
(%i3) f(false);
value of errormsg is true 
(%o3)                                true
(%i4) errormsg:false;
(%o4)                                false
(%i5) f(true);
value of errormsg is false 
(%o5)                                false
特殊演算子: for

繰り返しで使われます。 Maximaの繰り返し機能の記述に関しては、doを参照してください。

関数: go (tag)

制御を goの引数でタグ付けされたブロックの文に移すために block内部で使われます。 文をタグ付けするには、 その文の前に、 アトムの引数を blockの中の別の文として 先行させてください。 例えば:

block ([x], x:1, loop, x+1, ..., go(loop), ...)

goの引数は、同じblockの中に現れるタグの名前でなければいけません。 goを含むblock以外のblockの中のタグに移るために、 goを使うことはできません。

特殊演算子: if

条件評価を表します。 if式の様々な形が認識されます。

if cond_1 then expr_1 else expr_0 は、 もしcond_1true評価されたらexpr_1に*評*価*され、 そうでなければ式はexpr_0に評価されます。

コマンド if cond_1 then expr_1 elseif cond_2 then expr_2 elseif ... else expr_0は、 もしcond_ktrue、かつ、先行する条件がすべてfalseなら、 expr_kに評価されます。 もし条件のいずれもtrueでないなら、式はexpr_0に評価されます。

もしelseがないなら、 最後にelse falseが仮定されます。 すなわち、コマンド if cond_1 then expr_1は、 if cond_1 then expr_1 else falseと同値で、 コマンド if cond_1 then expr_1 elseif ... elseif cond_n then expr_nは、 if cond_1 then expr_1 elseif ... elseif cond_n then expr_n else falseと同値です。

選択肢expr_0, …, expr_nは、任意のMaxima式を取り得ます。 入れ子のif式もあり得ます。 選択肢は、 対応する条件がtrueでない限り、 整理も評価もされません。

条件cond_1, ..., cond_nは、潜在的に、また、実際に truefalseに評価される式です。 条件が実際にはtrueにもfalseにも評価されない時、 ifの振る舞いはグローバルフラグprederrorで決定されます。 prederrortrueの時、 もし評価された条件のいずれかがtrueにもfalseにもならなかったら 、エラーになります。 そうでなければ、trueにもfalseにも評価されない条件が受け入れられ、 結果は条件式になります。

条件は以下のように、他の要素間の関係演算子と論理演算子からなります。

演算                 シンボル     タイプ
 
小なり                <           関係 中置
以下                  <=          関係 中置
等号 (構文法的)        =           関係 中置
不等号 (構文法的)      #           関係 中置
等号 (値)             equal       関係 関数
不等号 (値)           notequal    関係 関数
以上                  >=          関係 中置
大なり                >           関係 中置
かつ                  and         論理 中置
または                or          論理 中置
否定                  not         論理 前置
関数: map (f, expr_1, …, expr_n)

mapは、主演算子(訳注:内部表現の最上位階層のリストに対応する演算子)は 式expr_1, ..., expr_nのそれと同じ演算子を使い、 そのサブパーツは、引数式の対応するサブパーツにfを適用した結果である式を返します。 fn個の引数の関数名か、n個の引数のラムダ形式です。 (訳注:また、expr_1, …, expr_nは内部表現に階層リスト構造を持つ式です。)

maperror - もしmaperrorfalseなら、 マッピング関数のすべては、(1)もしexpr_iのすべてが同じ長さでなければ、 最も短いexpr_iが完了した時点で停止し、 (2)もしexpr_iが同じタイプのオブジェクトでなければ、 fをリスト[expr_1, expr_2, ...]に適用します。 もしmaperrortrueなら、上の2つの場合、エラーメッセージを出力します。

この関数の用法の1つは、ある関数(例えば、partfrac)を非常に長い式に適用する際、 計算の間にリスト保存領域を枯渇させるため式全体に適応するのが不可能な場合に、 それぞれの項に関数をマップすることです。

(%i1) map(f,x+a*y+b*z);
(%o1)                        f(b z) + f(a y) + f(x)
(%i2) map(lambda([u],partfrac(u,x)),x+1/(x^3+4*x^2+5*x+2));
                           1       1        1
(%o2)                     ----- - ----- + -------- + x
                         x + 2   x + 1          2
                                         (x + 1)
(%i3) map(ratsimp, x/(x^2+x)+(y^2+y)/y);
                                      1
(%o3)                            y + ----- + 1
                                    x + 1
(%i4) map("=",[a,b],[-0.5,3]);
(%o4)                          [a = - 0.5, b = 3]


関数: mapatom (expr)

exprがマップルーチンでアトムとして扱われる時だけtrueを返します。 "Mapatoms"はアトム、(有理数を含む)数、添字付き変数です。

オプション変数: maperror

デフォルト値: true

maperrorfalseの時は、 マップ関数すべてに、以下の例のようにさせます。

map (f, expr_1, expr_2, …)

に対しては、 (1) もしexpr_iのすべてが同じ長さでないなら、 最も短いexpr_iの終わりまで完了した時、停止するようにさせ、 (2) もしexpr_iすべてが同じタイプのオブジェクトでないなら、 fを[expr_1, expr_2, ...]に適用するようにさせます。

もしmaperrortrueなら、 上の2つの例に関して、エラーメッセージが表示されます。

オプション変数: mapprint

デフォルト値: true

mapprinttrueの時、 map, mapl, fullmapからの様々な情報メッセージが 一定の状況で生成されます。 これらは mapapplyを使ったり、mapが 最短のリストで切り詰めているような状況を含みます。

もしmapprintfalseなら、これらのメッセージは抑制されます

関数: maplist (f, expr_1, …, expr_n)

expr_1, …, expr_nのパーツにfを適用した結果のリストを返します。 fは、関数名かラムダ式です。

maplistmap (f, expr_1, ..., expr_n)とは違います。 mapは主演算子がexpr_iと同じ式を返します。 (整理とmapapplyを行う場合は例外です。)

オプション変数: prederror

デフォルト値: false

prederrortrueの時、 if文の述語論理かis関数が truefalseに評価されるのに失敗した時はいつでも エラーメッセージが表示されます。

もしfalseなら、この場合,代わりにunknownが返されます。 prederror: falseモードは翻訳コードではサポートされません; しかしながら、maybeは翻訳コードでサポートされます。

ismaybeも参照してください。

関数: return (value)

引数を連れて、陽にブロックから抜けるために使われます。 もっと情報を知るには、blockも参照してください。

関数: scanmap (f, expr)
関数: scanmap (f, expr, bottomup)

トップダウン法で、fexprに再帰的に適用します。 完全な因数分解が望まれる時、これは最も役に立ちます。 例えば:

(%i1) exp:(a^2+2*a+1)*y + x^2$
(%i2) scanmap(factor,exp);
                                    2      2
(%o2)                         (a + 1)  y + x

Note the way in which scanmapが与えられた関数factorexprの構成部分式に適用する方法に注意してください; もし exprの別の形がscanmapに適用されるなら、結果は異なるかもしれません。 従って、 scanmapexpの展開形に適用される時、 %o2が再現されません:

(%i3) scanmap(factor,expand(exp));
                           2                  2
(%o3)                      a  y + 2 a y + y + x

scanmapが 与えられた関数を指数関数を含む部分式すべてに再帰的に適用する方法の別の例です:

(%i4) expr : u*v^(a*x+b) + c$
(%i5) scanmap('f, expr);
                    f(f(f(a) f(x)) + f(b))
(%o5) f(f(f(u) f(f(v)                      )) + f(c))

scanmap (f, expr, bottomup)は、 ボトムアップ法で fexprに適用します。 例えば、未定義fに関して、

scanmap(f,a*x+b) ->
   f(a*x+b) -> f(f(a*x)+f(b)) -> f(f(f(a)*f(x))+f(b))
scanmap(f,a*x+b,bottomup) -> f(a)*f(x)+f(b)
    -> f(f(a)*f(x))+f(b) ->
     f(f(f(a)*f(x))+f(b))

この場合、両方の方法で同じ答えを得ます。

関数: throw (expr)

exprを評価し、 直近のcatchに値を投げ戻します。 throwは、 catchと一緒に、非ローカルリターンメカニズムとして使われます。

特殊演算子: while
特殊演算子: unless

doを参照してください。

関数: outermap (f, a_1, …, a_n)

関数fを 外積a_1掛けるa_2 ... 掛けるa_nの要素のそれぞれに適用します。

fn個の引数の関数の名前か、 n個の引数のラムダ式 です。

それぞれの引数a_kは、 リストか、入れ子のリストか、行列か、他の任意の種類の式を取り得ます。

outermap戻り値は、入れ子の構造です。 xを戻り値とします。 すると、 xは最初のリストか入れ子のリストか行列引数と同じ構造を持ち、 x[i_1]...[i_m]は、 二番目のリストか入れ子のリストか行列引数と同じ構造を持ち、 x[i_1]...[i_m][j_1]...[j_n]は、 三番目のリストか入れ子のリストか行列引数と同じ構造を持ち、 以下同様。 ここで、m, n, ...は、 引数それぞれの要素 をアクセスするために要求される インデックスの数(リストには1つ、行列には2つ、入れ子のリストには1つ以上)です。 リストや行列でない引数は戻り値の構造に影響を与えません。

Note that the effect of outermapの効果は fcartesian_productによって返される 外積の要素のそれぞれに適用することのそれと違います。

outermapは、戻り値で引数の構造を保ちますが、 cartesian_productは違います。

outermapは引数を評価します。

map, maplist, applyも参照してください。

例:

outermapの初等的な例。 よりはっきり引数の組み合わせを示すために、 Fは未定義のままです。

(%i1) outermap(F, [a, b, c], [1, 2, 3]);
(%o1) [[F(a, 1), F(a, 2), F(a, 3)], [F(b, 1), F(b, 2), F(b, 3)], 
                                     [F(c, 1), F(c, 2), F(c, 3)]]
(%i2) outermap(F, matrix([a, b],[c, d]), matrix([1, 2],[3, 4]));
         [ [ F(a, 1)  F(a, 2) ]  [ F(b, 1)  F(b, 2) ] ]
         [ [                  ]  [                  ] ]
         [ [ F(a, 3)  F(a, 4) ]  [ F(b, 3)  F(b, 4) ] ]
(%o2)    [                                            ]
         [ [ F(c, 1)  F(c, 2) ]  [ F(d, 1)  F(d, 2) ] ]
         [ [                  ]  [                  ] ]
         [ [ F(c, 3)  F(c, 4) ]  [ F(d, 3)  F(d, 4) ] ]
(%i3) outermap (F, [a, b], x, matrix ([1, 2], [3, 4]));
       [ F(a, x, 1)  F(a, x, 2) ]  [ F(b, x, 1)  F(b, x, 2) ]
(%o3) [[                        ], [                        ]]
       [ F(a, x, 3)  F(a, x, 4) ]  [ F(b, x, 3)  F(b, x, 4) ]
(%i4) outermap (F, [a, b], matrix ([1, 2]), matrix ([x], [y]));
       [ [ F(a, 1, x) ]  [ F(a, 2, x) ] ]
(%o4) [[ [            ]  [            ] ], 
       [ [ F(a, 1, y) ]  [ F(a, 2, y) ] ]
                              [ [ F(b, 1, x) ]  [ F(b, 2, x) ] ]
                              [ [            ]  [            ] ]]
                              [ [ F(b, 1, y) ]  [ F(b, 2, y) ] ]
(%i5) outermap ("+", [a, b, c], [1, 2, 3]);
(%o5) [[a + 1, a + 2, a + 3], [b + 1, b + 2, b + 3], 
                                           [c + 1, c + 2, c + 3]]

outermapの戻り値のより密な検査。 最初の、二番目の、三番目の引数は、それぞれ、行列、リスト、行列です。 戻り値は行列です。 その行列の要素それぞれはリストで、 それぞれのリストの要素それぞれは行列です。

(%i1) arg_1 :  matrix ([a, b], [c, d]);
                            [ a  b ]
(%o1)                       [      ]
                            [ c  d ]
(%i2) arg_2 : [11, 22];
(%o2)                       [11, 22]
(%i3) arg_3 : matrix ([xx, yy]);
(%o3)                      [ xx  yy ]
(%i4) xx_0 : outermap(lambda([x, y, z], x / y + z), arg_1,
                                                   arg_2, arg_3);
               [  [      a        a  ]  [      a        a  ]  ]
               [ [[ xx + --  yy + -- ], [ xx + --  yy + -- ]] ]
               [  [      11       11 ]  [      22       22 ]  ]
(%o4)  Col 1 = [                                              ]
               [  [      c        c  ]  [      c        c  ]  ]
               [ [[ xx + --  yy + -- ], [ xx + --  yy + -- ]] ]
               [  [      11       11 ]  [      22       22 ]  ]
                 [  [      b        b  ]  [      b        b  ]  ]
                 [ [[ xx + --  yy + -- ], [ xx + --  yy + -- ]] ]
                 [  [      11       11 ]  [      22       22 ]  ]
         Col 2 = [                                              ]
                 [  [      d        d  ]  [      d        d  ]  ]
                 [ [[ xx + --  yy + -- ], [ xx + --  yy + -- ]] ]
                 [  [      11       11 ]  [      22       22 ]  ]
(%i5) xx_1 : xx_0 [1][1];
           [      a        a  ]  [      a        a  ]
(%o5)     [[ xx + --  yy + -- ], [ xx + --  yy + -- ]]
           [      11       11 ]  [      22       22 ]
(%i6) xx_2 : xx_0 [1][1] [1];
                      [      a        a  ]
(%o6)                 [ xx + --  yy + -- ]
                      [      11       11 ]
(%i7) xx_3 : xx_0 [1][1] [1] [1][1];
                                  a
(%o7)                        xx + --
                                  11
(%i8) [op (arg_1), op (arg_2), op (arg_3)];
(%o8)                  [matrix, [, matrix]
(%i9) [op (xx_0), op (xx_1), op (xx_2)];
(%o9)                  [matrix, [, matrix]

outermapは、戻り値の中で引数の構造を保持します。 cartesian_productは保持しません。

(%i1) outermap (F, [a, b, c], [1, 2, 3]);
(%o1) [[F(a, 1), F(a, 2), F(a, 3)], [F(b, 1), F(b, 2), F(b, 3)], 
                                     [F(c, 1), F(c, 2), F(c, 3)]]
(%i2) setify (flatten (%));
(%o2) {F(a, 1), F(a, 2), F(a, 3), F(b, 1), F(b, 2), F(b, 3), 
                                       F(c, 1), F(c, 2), F(c, 3)}
(%i3) map(lambda([L], apply(F, L)),
                     cartesian_product({a, b, c}, {1, 2, 3}));
(%o3) {F(a, 1), F(a, 2), F(a, 3), F(b, 1), F(b, 2), F(b, 3), 
                                       F(c, 1), F(c, 2), F(c, 3)}
(%i4) is (equal (%, %th (2)));
(%o4)                         true

Next: , Previous:   [Contents][Index]