技術資料 http://www2.toyo.ac.jp/~asahi/research/simulation/docs/maxmin.html
08.01.21 1st Up by kisoten, 09.09.21 加筆by asahi

言語CASTにおける 最大,最小,最適化

 言語CASTにおいて,最大,最小,最適解に関連する述語や方法について例を示します.

1.最大,最小

 リストL=[30,40,40,20]が与えられているとき,

	最大値  max(L)=40
	最小値  min(L)=20
	4番目  project(L,4)=20
	一致するものの位置(最初) invproject(L,40)=2
	一致するものの位置(全部) invproject(L,40,"l")=[2,3]
	最大値を与える位置(全部) invproject(L,max(L),"l")=[2,3]

となります.

 最後の式invproject(L,max(L),"l")は,
これ1行で最大値max(L)と一致する位置の全部をリストアップする関数です.
モデルの中では

	L:=[30,40,40,20],
	L2:=invproject(L,max(L),"l")

と定義しておくと,変数L2に[2,3]が代入されます.
したがって,リストLの最大値は2番目と3番目にあることが分かります.

2.最適化

 最適化問題 (Optimization Problem) の簡単な例を考えます.

   問:関数fが,f("a")=30; f("b")=40; f("c")=40; f("d")=20;
     で与えられているとき,f(x)を最大にするxを求めよ.
   答:x="b"またはx="c"のときf(x)は最大値40をとる.

 関数fは集合X={"a","b","c","d"} から集合Y={実数} への関数です.
Xは定義域で,{20,30,40}が値域です.
{"b","c"} を最適解集合といい,40を最適値といいます.

1)関数が有限集合F:=[["a",30],["b",40],["c",40],["d",20]] で定義されているとき

【リスト演算】

 リストのリストは行列として扱えるので,
行列Fの転置をとり,[F1,F2]:=transpose(F) とすると,
F1= ["a","b","c","d"], F2= [30,40,40,20]となります.
F2の最大値を与える位置をすべて求め( L2=[2,3] ),
対応するF1の位置の値のリストL1=["b","c"]を求めればよい.

	[F1,F2]:=transpose(F),
	L2:=invprojcet(F2, max(F2),"l"),
	L1:=project(F1,L2),

【defSetの利用】
 別の方法として,関数defSetを使うことができます.
集合Fの要素[u,v]をひとつずつ順にチェックしながら,
第2項vが最大値であるような要素の第1項uを集めて
集合にすれば最適解集合が得られます. 

	func([opt]);
	opt(F)=defSet(p(y,[u,v],[F]),member([u,v],F));
	p(y,[u,v],[F]) <->
		R=project(transpose(F),2),//値f(x)のリスト
		v=max(R),//の最大値が第2項vと等しいような
		y=u; //第1項uを取り出す

とユーザ定義しておけば,opt(F)は関数Fの最適解集合になります.
述語p(y,[u,v],[F])の第3項の[F]は必要です.忘れがちなので要注意.
たとえば,F:=[["a",30],["b",40],["c",40],["d",20]] のとき,
opt(F)=["b","c"] となります.

2)関数が写像(mapping)で定義されているとき

	func([f]);
	f("a")=30; f("b")=40; f("c")=40; f("d")=20;

関数が上のように定義されているとき,

	f.g=defSet(pf(z,x,[]),member(x,["a","b","c","d"]));
	pf(z,x,[]) <-> z:=[x,f(x)];

で,関数fを集合表現f.g に変換できます(MTA教科書4.5).
上記1)のリスト演算を行なうとL1=["b","c"] が得られ,
またはユーザ関数optを使うと,opt(f.g)=["b","c"] となります.

3)初等関数の場合

	func([f]);
	f(x)=y <-> y:=-x*x+5x-6;

関数が上のように数式で定義されている場合でも,
有限個のf(x)を比較するだけなら,
集合表現f.gに変換するやり方2)が使えます.
x=0,1,2,3,4,5に対する最適解は,opt(f.g)=[2,3]となります.

4)連続区間上の関数の場合

 しかし,連続区間[0,5]上で
連続関数(例えば,y=-x*x+5x-6)の最大値を与える実数xを求めたいときは,
連続区間[0,5]上の実数の数は 無限個あるので,
defSet()も使えず,何か別の方法が必要です.
関数のグラフの山登りをする必要があるので,
問題解決システム(MTA教科書第5章)を作成することになる.
 
	//opt01.set  極値を求める問題解決ユーザモデル
	preprocess() <-> e.g:=0.001; //刻み幅
	func([f]);
	  f(x)=y <-> y:=-x*x+5*x-6;
	initialstate() = 2; //状態xの初期値
	finalstate(x) <-> f(x)>=f(x-e.g), f(x)>=f(x+e.g) ;//極値の定義
	delta(x,a) = x2 <-> x2:=x+a, constraint(x2);//状態遷移関数
	genA(x) = [-e.g,e.g]; //アクション集合(代替案集合)
	constraint(x) <-> x >= 0, x<=5;//状態xの制限
	st(x) <-> finalstate(x); //停止条件
	goal(x) = -f(x); //状態を評価する関数

 上記のユーザモデルopt01.setをテキストエディタで作成し,
開発環境Simcastを起動し,「Solverとして」コンパイル/実行すれば,
刻み幅e.gづつ山登りをして,極値に達したら停止します.
極値を与える近似 x=2.499が得られます.

3.まとめ

 リストや有限集合を相手にするときは,
(多くは)CAST言語で「式」を書けば答えが得られます.
しかし,無限集合を相手にするときは,
第2項の4)のように問題解決をするために,
CAST言語で「ユーザモデル」を書く必要があります.