技術資料 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言語で「ユーザモデル」を書く必要があります.