第4章 Mathematica プログラミング

 この章では,Mathematicaのプログラミング言語としての側面をみていく.Mathematicaはプログラミング言語としてCやJAVAのような手続き型言語だけでなく,関数型言語,ルールベースト,LISP,Prologのような扱いまで広く対応できる.
 手続き型言語とは,プログラミングされた命令を逐次的に実行し,処理の結果に応じて変数の内容を変化させていく.C言語やBASIC、Pascalなどほとんどのプログラミング言語は手続き型言語の構造をもつ.
 関数型言語とは,数学的な言語仕様をもつ言語で,計算は計算結果を引数とした関数呼び出しの繰り返しとして行われる.MathematicaやLispが関数型言語に近い特徴をもつ.

1 プログラミングの基礎

Mathematicaでのパターン [ x_ ]

Mathematicaで関数を定義するときには少し工夫がいる.

4programing_1.gif

4programing_2.gif

4programing_3.gif

これは、記号xのみにしか動作せず、不都合である.これに対し、Mathematicaには,パタ-ンマッチングという考え方があり,x_とすることでパタ-ンに適合する変数に対応する関数ができる.

4programing_4.gif

4programing_5.gif

4programing_6.gif

4programing_7.gif

Mathematicaでの等号=と:=

定義する関数がもう少し複雑になると、さらに工夫する必要がある.

4programing_8.gif

4programing_9.gif

4programing_10.gif

4programing_11.gif

=は即時定義(Set) といい、左辺の内容を右辺に代入する.つまり代入の規則を優先して評価するだけである.これに対して、:=は遅延定義(SetDelayed)といい、右辺をすぐには評価せず、Expand[x^2]全体を保持するので、関数が実際に使われるときに初めて評価する.特に:=は関数を定義するときに非常に有効である.

4programing_12.gif

Global`ff

4programing_13.gif

4programing_14.gif

Global`gg

4programing_15.gif

関数を作る

いままではMathematicaに組み込まれている関数を利用してきたが、ここではユーザーが関数を自作する方法を紹介する.

例として平方関数を作る._はアンダースコアである.

4programing_16.gif

4programing_17.gif

引数のパターンを指定することで、区分的に定義された関数を作ることができる.

4programing_18.gif

4programing_19.gif

次のように、区分的に定義された関数を通常の数学的表現に近い形で記述できる.

4programing_20.gif

これを図示する.

4programing_21.gif

条件分岐

IF

二つの条件分岐の時、IFを用いる.第1引数が真であるなら後続の式、そうでないならその次の式が評価される.

4programing_22.gif

Which

三つ以上の場合の分岐にはWhichを用いる.

4programing_23.gif

4programing_24.gif

4programing_25.gif

4programing_26.gif

繰り返し

平方数のリストを色々な方法で作成する.手続き型のプログラミングでは For、Doを用いることが多い.

For

4programing_27.gif

次は、リスト形式での出力

4programing_28.gif

Do

4programing_29.gif

Nest

関数の反復にはFor、 Doを使うことがある.

4programing_30.gif

4programing_31.gif

4programing_32.gif

しかし,MathematicaにはNestという強力なコマンドがあり、簡潔な表現になる.

4programing_33.gif

2  Mapと Apply

Mathematicaをすこし進んだ使い方をしようとする時、是非マスターしておきたいコマンドの一つとしてMapとApplyがある.ともに関数を引数とし、リストを操作する時に用いる.

Apply

リストを用いた計算過程で、f[{1,2,3}]のようにリストに作用させるのでなく、リストの要素に関数を作用させたい時に用いる.

4programing_34.gif

4programing_35.gif

和を求める.

4programing_36.gif

4programing_37.gif

これは、Applyが式の頭部(Head)を引数に置き換えるからである.

4programing_38.gif

4programing_39.gif

4programing_40.gif

4programing_41.gif

リストに作用する関数も作ることができる.リストの平均を求める関数を作ってみる.

4programing_42.gif

練習5:適当な1次元リストを生成して、その平均を求めてみよう.

Map

Mapはリストの要素一つ一つに関数を作用させたい場合に用いる.

4programing_43.gif

4programing_44.gif

4programing_45.gif

4programing_46.gif

4programing_47.gif

4programing_48.gif

これはsinがリスタブルという性質を持っているからだが、一般には成り立たない.

4programing_49.gif

4programing_50.gif

4programing_51.gif

4programing_52.gif

4programing_53.gif

4programing_54.gif

純関数(無名関数)

MapやApplyを用いる場合は適用される関数の名前を指定する必要があった.ここでは関数名を指定せずに関数を引数にすることができる方法を紹介する.

3乗の関数を考える.そのために,まず名前を付ける.

4programing_55.gif

4programing_56.gif

4programing_57.gif

名前を付けずに行うには、純関数もしくは無名関数という考え方を用いる.

4programing_58.gif

4programing_59.gif

3 プログラミングによる問題解決

2の平方根の近似値を求める

CやJavaなどの手続き型言語とMathematica言語のとの違いを見ていく.

問題の把握

次の関数をもとに,2の平方根に迫る.

4programing_60.gif

4programing_61.gif

4programing_62.gif

4programing_63.gif

4programing_64.gif

4programing_65.gif

4programing_66.gif

Basicプログラミングでは

*DEFDBL X,Y
  INPUT "N=";N
          X=1
       FOR I=1 TO N
          Y=1+1/(1+X)
          X=Y
       NEXT I
   PRINT Y
END *
      

Forループ

4programing_67.gif

4programing_68.gif

4programing_69.gif

4programing_70.gif

4programing_71.gif

4programing_72.gif

4programing_73.gif

4programing_74.gif

4programing_75.gif

関数型に書き換えると,

4programing_76.gif

n=18にすると,

4programing_77.gif

4programing_78.gif

4programing_79.gif

Doループ

4programing_80.gif

4programing_81.gif

関数型に書き換えるには,

4programing_82.gif

n=10にすると,

4programing_83.gif

4programing_84.gif

近似値をリストにするには,

4programing_85.gif

4programing_86.gif

Recusive Programming(再帰的プログラミング)

関数として,自分の定義に自分自身を用いる考え方を「再帰的」と呼ぶ.この考え方はプログラミングではよく用いられる.

4programing_87.gif

n=10にすると,

4programing_88.gif

4programing_89.gif

4programing_90.gif

4programing_91.gif

Nest(反復コマンド)

Mathematicaには繰り返しに対して,Nestという便利な関数がある.これは有用である.

4programing_92.gif

4programing_93.gif

4programing_94.gif

4programing_95.gif

4programing_96.gif

4programing_97.gif

4programing_98.gif

4programing_99.gif

NestListと無名関数を使うことで,

4programing_100.gif

4programing_101.gif

4programing_102.gif

1.0000000000.
1.5000000000.
1.4000000000.
1.4166666667.
1.4137931034.
1.4142857143.
1.4142011834.
1.4142156863.
1.4142131980.
1.4142136249.
1.4142135516.
1.4142135642.

For文でピタゴラス数を求める

ピタゴラス数とは,三平方の定理をみたす自然数のことである.これを求めてみよう.

4programing_103.gif

4programing_104.gif

4programing_105.gif

4programing_106.gif

4programing_107.gif

4programing_108.gif

4programing_109.gif

問題 8:関数型プログラムにする.すなわち、nを与えてn以下のピタゴラス数をリストするプログラムを書きなさい.

4programing_110.gif

以下の問題でのプログラミングではMathematicaらしいプログラミングを心がける.

完全数を求める

自然数の完全数とは,その数とその数のすべての約数の和が等しいものをいう.この場合,約数として自分自身は含めない.最小の完全数は6である.これを探すプログラミングを考えよう.

4programing_111.gif

4programing_112.gif

4programing_113.gif

4programing_114.gif

Divisors[6] から最後の要素を除くには, Drop を使って,properDivisors をつくる.

4programing_115.gif

4programing_116.gif

4programing_117.gif

4programing_118.gif

4programing_119.gif

4programing_120.gif

4programing_121.gif

4programing_122.gif

4programing_123.gif

問題9  この完全数を求めるプログラムを関数型にまとめよう.

4programing_124.gif

4programing_125.gif

4programing_126.gif

ヨセフスの問題(継子立て)

問題:「ロ-マの兵が10人のユダヤ兵を洞窟に追い込んで,いままさに攻撃をしようとしていた.ユダヤの兵士は敵の刃にかかるよりは自刃の道を選んだ.このとき,伝説によれば彼ら10人は輪になって1人おきに死んだという.最後に死んだのは誰か」
この問題をMathematicaで解いてみる.

4programing_127.gif

Mathematicaでは,こんな簡単な1行プログラミングでかけてしまう.10人では,

4programing_128.gif

4programing_129.gif

途中の経過を出力させる.

4programing_130.gif

4programing_131.gif

4programing_132.gif

4programing_133.gif

4programing_134.gif

4programing_135.gif

4programing_136.gif

4programing_137.gif

4programing_138.gif

4programing_139.gif

4programing_140.gif

4programing_141.gif

4programing_142.gif

4programing_143.gif

4programing_144.gif

4programing_145.gif

4programing_146.gif

4programing_147.gif

4programing_148.gif

4programing_149.gif

4programing_150.gif

4programing_151.gif

4programing_152.gif

4programing_153.gif

4programing_154.gif

4programing_155.gif

4programing_156.gif

4programing_157.gif

4programing_158.gif

4programing_159.gif

4programing_160.gif

4programing_161.gif

4programing_162.gif

4programing_163.gif

4programing_164.gif

4programing_165.gif

4programing_166.gif

4programing_167.gif

フィボナッチ数

13世紀イタリアの数学者フィボナッチによって研究された有名な数である.

4programing_168.gif

4programing_169.gif

と定義すればいい.例えば,

4programing_170.gif

4programing_171.gif

4programing_172.gif

4programing_173.gif

実はこのプログラミングは,計算に時間がかかる.1度計算した結果に対しても繰り返し計算するため,無駄に時間をとっていまう.このようなときは次のように改善する.

4programing_174.gif

4programing_175.gif

と定義すればいい.

4programing_176.gif

4programing_177.gif

このような方法は,1度計算したfibb[n]はメモリに記憶することによって,無駄な計算を回避している.

問題 10 フィボナッチ数の話題をもとに,いろいろな三項間漸化式を考察しよう.

collatz 問題(3n+1問題)

この問題は古くから知られている問題で次のようなものである.「ある自然数を考える.これが偶数のときは半分にし,奇数のときは3倍して1足す」このようにして自然数列を定義する.すると,この数列が非常に不思議な振る舞いをすることに気づく.これをMathematicaで確認してみよう.

next[i_?OddQ]:=next[i]=3i+1
next[i_?EvenQ]:=next[i]=i/2
collatz[i_]:=
     FixedPointList[next,i,SameTest -> ((#2==1)&)]

9から始めてみよう.

4programing_178.gif

4programing_179.gif

あるル-プに入ってしまう.1から30までの様子をみる.

4programing_180.gif

4programing_181.gif

すべてル-プに入る.

4programing_182.gif

871もループに入るが,その様子をグラフでみる.

ListPlot[collatz[871],PlotJoined -> True,
             PlotRange -> {0,200000}]

4programing_183.gif

4programing_184.gif

実はこの規則では,すべて自然数がこのル-プに入りそうなことがコンピュ-タで確認されているが,厳密には証明されていない未解決問題である.とりあえず,100から1000の数がループに入るまでどのくらいの長さか見てみよう.

t=Table[Length[collatz[i]],{i,100,1000}]
        

4programing_185.gif

最大の長さは,

Max[t]

4programing_186.gif

である.そしてこれを与える自然数は,

Position[t,179]

4programing_187.gif

である.ともかく不思議な数列だ.

タ-トルグラフィックス

タ-トルコマンド

タ-トルグラフィックスとは,プログラミング言語LOGOなどで有名なグラフィックスメソッドである.これはタ-トル(亀)に長さと角度を指定して線分を描いてグラフィックスを描いていくので,このような名前がついた.Mathematicaでは前後左右を次のように定義して,pathのリストを作成する.

4programing_188.gif

4programing_189.gif

4programing_190.gif

4programing_191.gif

4programing_192.gif

そして,pathのリストを作成後,Line文で線分を描く.

4programing_193.gif

4programing_194.gif

4programing_195.gif

4programing_196.gif

多角形

正n角形を描くために,次のように関数を定義する.

4programing_197.gif

4programing_198.gif

8角形を描く.

4programing_199.gif

4programing_200.gif

4programing_201.gif

渦巻き線(螺旋)

渦巻き線を描くために,次のように拡大比と角度を次のように定義する.

4programing_202.gif

4programing_203.gif

4programing_204.gif

4programing_205.gif

フラクタル図形

タ-トルグラフィックスを再帰的に使うことで,フラクタル図形を描くことができる.ここでは,コッホの曲線(雪片曲線)を描いてみよう.まずは関数Kochを再帰的に定義する.

4programing_206.gif

4programing_207.gif

ここで長さ1の線分に対し,その3等分した中央部を正三角形の2つの斜辺で置き換える.この操作を順次繰り返すと雪片のような曲線が描ける.この曲線の特徴はどの部分に注目しても全体と相似形になっていることだ.このような図形をフラクタル図形といい,直線の次元が1次元なのに対し,この曲線の相似次元はlog4/log3=1.2618次元という.

4programing_208.gif

4programing_209.gif

4programing_210.gif

4programing_211.gif

4programing_212.gif

4programing_213.gif

4programing_214.gif

4programing_215.gif

4programing_216.gif

4programing_217.gif

Spikey Created with Wolfram Mathematica 7.0