技術資料htp://www2.toyo.ac.jp/~asahi/research/simulation/docs/manyfunction.html
09.02.24 first Up, 09.08.30 "0削除"

(モデル理論アプローチによるシミュレーション)
多数のオートマトンや関数を結合して実行する


 例題として,1,000個の状態機械S1, S2,..., S1000を直列結合し並列処理するシステムをモデル化する。

1 アイデア
 変数nを加えて関数の番号を表す.状態機械Snの状態遷移関数をdelta(n,c,a)で定義する.
 関数defListで1000個の関数の計算を行なう(次状態を計算する).

2 番号リストgenIndex(1,1000)をインデックスに使用する方法
//manyfunc5a.set
func([delta1,deltaA]);
delta1(n,c,a)=cc <-> cc:=a;
deltaA(c,a)=cc <-> 
	Ps:=append([a],c),
	cc:=defList(p(y,n,[Ps]),member(n,genIndex(1,M.g)) );
	p(y,n,[Ps]) <-> [an,cn]:=project(Ps,["r",n,n+1]), y:=delta1(n,cn,an);
preprocess() <-> M.g:=1000;
inputsequence()=0; times()=10;
initialstate()=c <-> c:=append( [1],constantlist(0,M.g-1) );
delta(c,a)=deltaA(c,a);
 上記ユーザモデルの3行目のdelta(n,c,a) の部分が複数の関数(状態遷移関数)を定義している.変数nは状態機械の番号である.ひとつの式であるが,1,000個の関数が定義されていると思っておけばよい.その次の,deltaA(c,a)が1000個の状態機械を直列結合した全体システムSの状態遷移関数である.ただし,その状態変数は c=[c1,c2,...,c1000] である.次状態ccを計算するために,まずリストPs=[a,c1,c2,...,c1000]を作成する.状態機械Snの状態はcn, 入力はan=cn-1であるから,関数project()を使ってPsから2つづつ要素を抽出すればdelta(n,cn,an)を計算することができる.


 全体システムSはひとつの状態機械であるからSimcastで実行することができる.コンパイルして実行すると10回の状態遷移で15秒かかった.上図はその途中を表示している.全体システムの初期状態が c=[1,0,0,...] だったので,1回目の状態遷移で c=[0,1,0,...] と変化している.1が隣の状態機械に移動しているようすがわかる.

3 高速化の方法
 上記のモデルmanyfunc5a.setにおいて,times() =1000に変更すれば1000回の状態遷移を行なうはずであるが,推定25分(1500秒)の実行時間がかかるだろう.計算が遅い理由は,関数defListの中でproject()を使用しているからである.そのため関数projectは,状態遷移1000回×計算1000回=100万回使用されている.以下では,関数projectを使わないで高速化する方法を示す.

3.1 代入すべき値のリストを作成する方法
 defListを使う前に,あらかじめ代入すべき値のリストを作成しておき,それをインデックスとしてdefListを定義する方法がある.
deltaA(c,a)=cc <-> 
	Ls:=transpose([genIndex(1,M.g),c,deleteList(append([a],c),M.g+1)]),
	cc:=defList(p(y,z,[]),member(z,Ls));
	p(y,z,[]) <-> [n,cn,an]:=z, y:=delta(n,cn,an);
 この場合,Ls=[[1,c1,a], [2,c2,c1],[3,c3,c2],...] というリストを作成しておき,要素[n,cn,an] を取り出しながらdelta(n,cn,an)を計算し,並べて,次状態ccを得ている.実行時間は,1000回の状態遷移(times()=1000)で60秒であった.耐えられる実行速度になったが快適とは言えない.その理由は多数の要素をもつリストがあるからである.実際,defListのインデックスとなるLsは3項目×1000組=3000個の要素をもつリストである.長いリストの処理には時間がかかる.

3.2 グローバル変数を利用する方法
 技術資料「漸化式を解く」を参考に,グローバル変数を利用すれば,さらに早くすることができる.
deltaA(c,a)=cc <-> 
	n.g:=1, a.g:=a,
	cc:=defList(p(y,cn,[]),member(cn,c) );
	p(y,cn,[]) <-> n:=n.g, y:=delta(n,cn,a.g), n.g:=n+1, a.g:=cn;
 実行時間は,1000回の状態遷移で27秒であった.

3.3 スプレッドシートを利用する方法
 技術資料「シミュレーションの高速化:グラフ表示の制約」を参考に,スプレッドシートを状態の保存場所にする方法が考えられるが,やらなかった.

4 逐次処理の場合
 これまでは並列処理の場合を述べてきた.逐次処理の場合は次のようにすればよい.
deltaA(c,a)=cc <-> 
	n.g:=1, a.g:=a,
	cc:=defList(p(y,cn,[]),member(cn,c) );
	p(y,cn,[]) <-> n:=n.g, y:=delta(n,cn,a.g), n.g:=n+1, a.g:=y;
変更点はa.g:=yだけである.ひとつの入力5に対して,瞬時に1000個の要素の状態が5になるようすが分かる.
                        東洋大学 旭貴朗