Mathematicaらしい関数
Mathematicaらしい関数
松田裕幸
計算環境 Mathematica 14.0、 MacOS Sonoma 14.3.1, CPU Apple M1, メモリ 16GB
Mathematica関数 Set(=), SetDelayed (:=), Function, Map(/@), Apply(@@), MapApply(@@@), Rule( ), RuleDelayed(), ReplaceAll(/.), Condition(/;), Thread, MapThread, Cases, Select, Reap, Sow, Nest, NestList, FixedPoint, FixedPointList, Fold, FoldList, Catch, Throw
計算環境 Mathematica 14.0、 MacOS Sonoma 14.3.1, CPU Apple M1, メモリ 16GB
Mathematica関数 Set(=), SetDelayed (:=), Function, Map(/@), Apply(@@), MapApply(@@@), Rule( ), RuleDelayed(), ReplaceAll(/.), Condition(/;), Thread, MapThread, Cases, Select, Reap, Sow, Nest, NestList, FixedPoint, FixedPointList, Fold, FoldList, Catch, Throw
はじめに
はじめに
Mathematica は非常に強力なプログラミング言語であり、計算の種類に応じた適切な関数セットが用意されていますが、その全部を使いこなせる人は残念ながら多くはありません。ここではその中でも重要な関数(上記「Mathematica関数」に列挙)を解説し、中置表記があるものについては紹介します。
式の評価について
式の評価について
本題に入る前に式の評価について確認しておきます。数値だけからなる式の評価は数値自身となります。
In[]:=
3
Out[]=
3
シンボル x からなる式の評価はシンボル自身となります。
In[]:=
x
Out[]=
x
ただし、具体的な値がシンボルに「束縛」されると、評価値は値自身となります。
In[]:=
x=12;x
Out[]=
12
この部分だけみると = は通常のプログラミング言語にある代入と同じようにみえますが、Mathematicaはこれを束縛と捉え、その束縛を解く関数 Clear を用意しています。
In[]:=
Clear[x]x
Out[]=
x
ちなみに関数 Remove は指定されたシンボルを名前空間から削除します。Clear しただけだと束縛は解除されますが、シンボル自身は名前空間に残ります。
In[]:=
Remove[x]
Set(=) / SetDelayed (:=)
Set(=) / SetDelayed (:=)
Mathematica では記号 = は割当てと呼ばれ、= の右辺を評価し、その結果を左辺に束縛します。この場合、1行目で 評価され r に束縛された「(乱数)値」が、2行目 Table内で置き換えられています。この段階で r の値は決しているので、すべて同じ値のリストが返ってきます。
In[]:=
r=RandomInteger[100];Table[r,{10}]
Out[]=
{49,49,49,49,49,49,49,49,49,49}
= の代わりに Set を使って r を定義します。
In[]:=
Set[r,RandomInteger[100]]
Out[]=
92
:= で定義した場合、左辺のシンボルが「実際に使われる」時まで、評価が遅延されます(1行目)。2行目で r の値を計算するたびに r はRandomInteger[100] と置き換えられ、遅延されていた評価が実行されます。
In[]:=
r:=RandomInteger[100]Table[r,{10}]
Out[]=
{82,53,47,18,91,22,65,86,25,21}
わかりやすく等価な式で書き直してみます。
In[]:=
r:=RandomInteger[100]{r,r,r,r,r,r,r,r,r,r}
Out[]=
{18,55,18,59,93,25,68,58,4,3}
あるいは
In[]:=
{RandomInteger[100],RandomInteger[100],RandomInteger[100],RandomInteger[100],RandomInteger[100],RandomInteger[100],RandomInteger[100],RandomInteger[100],RandomInteger[100],RandomInteger[100]}
Out[]=
{62,19,29,44,70,51,81,57,59,9}
:= の代わりに SetDelayed を使い r を定義します。
In[]:=
SetDelayed[r,RandomInteger[100]]
なお、他言語で使われる「変数」は Mathematica では正式には「シンボル」と呼ばれますが、特に混乱を招かない場合、通常は変数で済ませます。ただし、数式処理システムとしての役割(値を持たない変数が式に含まれていても計算可能)を強調するとき
In[]:=
x+3x+2
Out[]=
2+4x
は「シンボル 」(今の場合、シンボル x)を使います。
Function
Function
関数は のように名前(ここでは )をつけて使うイメージがありますが、関数の本質は引数と本体のみで、Function はこれを実現します。次の例は、仮引数 、本体 からなる関数に実引数 2 を渡し、結果 9 を得ます。
f(x)=x+1
f
x
x^3+1
In[]:=
Function[x,x^3+1][2]
Out[]=
9
この例は2つの仮引数 と からなっています。実引数 2と3 を得て、結果13を返します。
x
y
In[]:=
Function[{x,y},x^2+y^2][2,3]
Out[]=
13
関数定義に関数名が不要なように関数引数名も不要で、代わりに「位置」に関する対応づけさえできればいいことがわかります。 はスロットと呼ばれ、関数引数に対応します。次の例では実引数 2 がスロット に代入され、その3乗+1が計算されます。
#
#
In[]:=
#^3+1&[2]
Out[]=
9
次は 2 が第1スロット、3 が第2スロットに代入されます。
In[]:=
#1^2+#2^2&[2,3]
Out[]=
13
この形式は Python でも使いますが、Mathematica では新しい書き方です。
In[]:=
(x|->x^3+1)[2]
Out[]=
9
連想形式のデータに対してはキーワードをそのままスロット名として使うことができます。
In[]:=
data=<|"price1"->100,"price2"->140|>;#price1+#price2&[data]
Out[]=
240
置き換えシステムとパターンマッチング
置き換えシステムとパターンマッチング
Mathematicaでは計算は置き換えを行っているにすぎません。すでにみた例でいえば、r は1回評価され決した値で置き換えられていますが、
In[]:=
r=RandomInteger[100];{r,r,r,r,r,r,r,r,r,r}
Out[]=
{15,15,15,15,15,15,15,15,15,15}
次の例では、すべての r がいったん RandomInter[100]で置き換えられ、その評価値が結果に残ります。
In[]:=
r:=RandomInteger[100]{r,r,r,r,r,r,r,r,r,r}
Out[]=
{0,61,22,50,84,68,43,33,34,94}
以上は exact な値同士で置き換えが起きましたが、同様なことをパターンを介して行うことができます。例で説明します。これは2個の引数(値は何でもよい)を受取り値1を返す関数 f を定義します。
In[]:=
f[_,_]:=1
引数の数があっているので答え1を返していますが、
In[]:=
f[1,2]
Out[]=
1
これは引数が1つしかないので、「未評価」として入力がそのまま出力となって返ってきます。
In[]:=
f[999]
Out[]=
f[999]
「_」はblankと呼ばれ、引数パターンとして使われます。パターン「__」(blank2個
)は1個以上の引数にマッチします。この場合、3引数にマッチし、結果 2 を得てます。
)は1個以上の引数にマッチします。この場合、3引数にマッチし、結果 2 を得てます。
In[]:=
f[__]:=2f[2,3,4]
Out[]=
2
パターン「___」(blank3個)は0個以上の引数にマッチします。この例は引数0個の場合です。
In[]:=
f[___]:=4f[]
Out[]=
4
ではマッチした引数を関数本体(右辺)で使いたいときはどうすればいいでしょう。引数にシンボルを追加します。2 が x にマッチし、3 が y にマッチし、2+3 = 5 を計算します。
In[]:=
f[x_,y_]:=x+yf[2,3]
Out[]=
5
次の例で Sequence は引数列を表し、リスト式の中で組み込んで使うことが多いです。
In[]:=
f[x__]:=xf[2,3,4]
最後にこんな例はどうでしょう?
ここで関数 f は(blank _ がないため)引数に「シンボル」x と y そのもの を期待しています。引数 1 と 2 は x, y にパターンマッチしないので未評価として f[1, 2] を返してます。では、どんな場合に、このパターンにマッチするでしょうか。簡単です。実際にシンボル x と y を渡せばいいわけです。
関数引数に対する制約
関数引数に対する制約
たとえば関数
で引数 n が取る値を整数に限定したいとするとMathematicaでは次のような書き方ができます。
あるいは任意の真偽値を返す関数、たとえば素数判定関数
を使いたいときは 先頭に? を付けて使います。
オプション引数について簡単に説明します。
関数 f が次のように定義されています。
しかし引数 b の はたいていの場合、値1をとると分かっているとします。その場合、次のように記述することで関数 f を呼び出す際、b に対応する部分を省略(オプション)することができます。
ただし具体的に b の値を指定すれば その値が a + b で使われます。
Map(/@) / Apply(@@) / MapApply(@@@)
Map(/@) / Apply(@@) / MapApply(@@@)
Mapはいまやどのプログラミング言語でも一般的になってきましたが Mathematicaではver1.0のときから導入されています。仕掛けは単純でリストの各要素に同一関数を適用した結果のリストを返します。たとえば、リストの各要素を2倍するには次のように書きます。
Mapの中置形式 /@ を使うと次のように短く書けます。
ただし2引数を想定した場合、/@ をそのまま使うことはできず、次のように @@@(MapApply) に書かなければなりません。
あるいは
以上を整理し直してみます。
ここでMap 関数を Grid および Partition と組み合わせたこんな例を紹介します。素数を囲む四角は Framed を使い作っています。
Rule( ) / RuleDelayed()
Rule( ) / RuleDelayed()
/. の左辺に対し、の左辺で指定した変数をの右辺の値で置き換えます。
は先に右辺を評価し、その結果で置き換えるのに対し
では、 の左辺(今の場合、x )の置き換えが起きるたびに、右辺(今の場合、RandomReal[])が評価され、代入されます。
ReplaceAll(/.)
ReplaceAll(/.)
関数形式 f[...]に対し、引数が1個以上(2個の下線__で表す)のもの「すべて」を “OK” で置き換えます。
引数が0個以上(3個の下線___で表す)のものすべてを “OK” で置き換えます。
Condition(/;)
Condition(/;)
与えられたリストに対し、負の要素を w で置き換える状況を考えてみます。この例は次のように読みます:{6, -7, 3, 2, -1, -2}の要素を x で置き換えます。ただし、この状況では x が何を指すのか不明です。続けて /; 以降をみると具体的に x が指定(0未満)されています。ついで、そんな x を w で置き換える指示を Rule によって出しています。
与えられた整数ペアに対し、共に素数だけからなるペアのリストを返します。
Thread / MapThread
Thread / MapThread
関数 f を変数リスト varList と値リスト valueList に適用し、串刺し f[x, 1], f[y, 9], f[z, 11] からなるリスト を作ります。
たとえば関数として Rule を適用した場合はこうなります。
同じことを中置形式で作ります。
MapThread
は基本、Thread と同じです。
ただし次の例のように Thread対象をリストの深さで選ぶ場合には MapThread を利用します。
Cases
Cases
与えられたリストから整数要素のみを集めたリストを作ります。
整数以外(実数)のリストを返します。
リストを要素とするリストからペアだけを集め、当該ペアの要素の和からなるリストを返します。
Select
Select
Reap / Sow
Reap / Sow
整数リスト A に対し
素数だけを取り出したリストを計算します。(AppendToは副作用として第1引数に第2引数が追加される。)
Reap / Sow は表現が簡潔というだけでなく、AppendTo による明示的なメモリ領域操作を使わず、システム内に確保されたバッファ領域を使うため、処理時間も短くなります。
次は関数 FindMinimum のヘルプから引用する例ですが、FindMinimum が行う近似計算の途中解を Sow で集め、最終的に Reap で回収した内容を pts に代入し、元式に対応する等高線プロット上にptsの軌跡を描画します。
Nest / NestList
Nest / NestList
たとえば次のような例、x の初期値を 0 に対し、 1 を1万回加える、を考えます。
上記 Do 形式の式を Nest 形式で書き直してみました。
あまり使い道はありませんが、Nest を使うと、こんなトリッキーな例も作れます。
連分数をつくってみます。
最後は、このような形状をもった図形
を、NestList
を使い、回転移動させます。Rotate によって回転させながら、Translate によって位置移動を行っています。
FixedPoint / FixedPointList
FixedPoint / FixedPointList
FixedPoint関数はNestと類似します。違いは自己適用において事前の値と現在の値が等しくなると自動的に繰り返し適用を終了する点にあります。次の例は自己適用計算を15回繰り返しています。ただし、後半は同じ値 2 が続いています。
これに対し、FixedPoint を使い、終了までの回数を 1000 として動かしましたが、同じ値が2回続いた(最小不動点に到達した)ため計算は終了します。
Fold / FoldList
Fold / FoldList
階乗計算について考えてみます。
Doを使い計算し、同じ結果を得ます。
なお、Fold も Do を使った計算より高速になります。
Catch / Throw
Catch / Throw
終わりに
終わりに
長年 Mathematica を使ってきて、これだけ知っていれば Mathematica 通と呼ばれる関数たちを紹介しました。それでももしかしたら取りこぼしがあるかもしれません。普段お使いの中で、この不明な記号や関数があれば、ぜひこちらまでご連絡いただければ幸いです。ある程度、溜まった段階で、「Mathematicaらしい関数」第2段を出したいと思います。