[View] [Edit] [Attachments] [History] [Home] [Changes] [Search] [Help]
ThingLab
Squeak2.3 で、 ThingLab という制約プログラミングの実験ソフトが使えます。
例えば Photoshop なんかで、紙の大きさを設定するのに、縦横の比率をロックすると縦のサイズを
操作するだけで自動的に横のサイズが変わるという便利な機能があります。制約プログラミングとは、
このような考え方を全面的に採用したプログラミングの考え方です。幾何学の定理や物理のシミュレーションを
自然に表現できるという利点があります。ThingLab は 1970年代終盤にAlan Borning 氏により開発されました。
ThingLab の特徴
- Smalltalk ベース。ルールが満たされなくなった時に、ルールに適合するようにメソッドを呼ぶ仕組み。
- ユーザとして ThingLab をツールとして使う利用者と、ThingLab の部品自体を作る熟練者の2パターン想定。
- ThingLab 内で、既存の部品を組み合わせ GUI だけを使って作った部品も、最初からコードを書いて作った部品も同じようにビルディングブロックとして使える。
インストール、ThingLab 環境の整えかた(windows の例)
面倒臭い人は下をダウンロードして使ってください。(image + changes + V2 source + パッチ済み)
ThingLabImage.zip
真面目な人は以下を全部ダウンロードして圧縮ファイルは解凍し、同じディレクトリに入れる
ftp://st.cs.uiuc.edu/pub/Smalltalk/Squeak/2.3/Squeak23.exe -- 実行バイナリ
ftp://st.cs.uiuc.edu/pub/Smalltalk/Squeak/2.3/2.3.tar.gz -- イメージ
ftp://st.cs.uiuc.edu/pub/Smalltalk/Squeak/sources_files/SqueakV2.sources.gz -- ソース
ftp://st.cs.uiuc.edu/pub/Smalltalk/Squeak/goodies/ThingLab/ThingLab-v2.zip -- ThingLab 本体
http://sumim.no-ip.com:8080/collab/uploads/61/ThingLabTweak.cs -- sumim さんのパッチ
ThingLab-TextEditor-tak.st -- 僕のパッチ
ThingLab-v2.zip は解凍すると ThingLab/Release のディレクトリが出来るが、その内容を全部同じディレクトリに移動。
Squeak23.exe を実行して Squeak を起動。
ワークスペースを開き、
(FileStream readOnlyFileNamed: 'FileInAll.st') fileIn.
(FileStream readOnlyFileNamed: 'ThingLabTweak.cs') fileIn
(FileStream readOnlyFileNamed: 'ThingLab-TextEditor-tak.st') fileIn
を選択し、ctrl - d を押す(accept)
cygwin やシェルが好きな人はこっちが簡単
# まず Squeak2.3 のVM、イメージ、チェンジファイル、ソース、
# ThingLab 自体、sumim さんのパッチをダウンロード
$ wget ftp://st.cs.uiuc.edu/pub/Smalltalk/Squeak/2.3/Squeak23.exe \
ftp://st.cs.uiuc.edu/pub/Smalltalk/Squeak/2.3/2.3.tar.gz \
ftp://st.cs.uiuc.edu/pub/Smalltalk/Squeak/sources_files/SqueakV2.sources.gz \
ftp://st.cs.uiuc.edu/pub/Smalltalk/Squeak/goodies/ThingLab/ThingLab-v2.zip \
http://sumim.no-ip.com:8080/collab/uploads/61/ThingLabTweak.cs
http://languagegame.org:8080/propella/uploads/41/ThingLab-TextEditor-tak.st
# Squeak のイメージとチェンジファイルを解凍してカレントディレクトリ配置
$ tar xzvf 2.3.tar.gz
$ cp 2.3/image/Squeak2.3.image 2.3/image/Squeak2.3.changes .
$ gunzip SqueakV2.sources.gz
# ThingLab本体を解凍して、カレントディレクトリに配置
$ unzip ThingLab-v2.zip
$ mv ThingLab/Release/* .
# Squeak 実行
$ ./Squeak23.exe Squeak2.3.image &
ワークスペースで
(FileStream readOnlyFileNamed: 'FileInAll.st') fileIn.
(FileStream readOnlyFileNamed: 'ThingLabTweak.cs') fileIn
(FileStream readOnlyFileNamed: 'ThingLab-TextEditor-tak.st') fileIn
ThingLab で実験しよう
とりあえず体験するだけ
第1ペインから第4ペインまで(上の左から右に) FixedBridge - Picture - move - Point のように選択
第5ペイン(下側) のどこかアンカーを動してみよう。ブリッジがブルブルと動きます。
Alan Boning の論文を元に幾何学の実験をしてみる。
ThingLab のテキストとして、元になった論文
The Programming Language Aspects of ThingLab, a Constraint-Oriented Simulation Laboratory - Alan Borning 1981
と言うものがありますが(このPDF の URL は忘れてしまった!)これを元に Smalltalk-80版? の解説をしたページがあります。
その中で http://www.2share.com/thinglab/ThingLab%20-%20Chapter%202.html を見ながら ThingLab を実験してみます。
- ウインドウの小窓の意味
- 第1ペイン クラス名
- 第2ペイン 第5ペインの見かけを決める
- 第3ペイン 操作
- 第4ペイン 操作対象のクラス名
- 第5ペイン(下のペイン) 図やコードが表れる。
- クラス Shiaku を作成する
- GeometricObject が無いが ThingLabObject のサブクラスとしてクラスが出来ます。
- 第1ペイン右クリック - Define new thing - Shikaku と入力 (Figure 2.3)
- 第1ペインから第2ペインまで、 Shikaku - picture - insert - ThingLabLine を選択 (Figure 2.4)
- カーソルを下ペインに持っていくと、後は直感的に線が描けると思います。
- ここで、例えば閉じた四角を書いてみる。(Figure 2.5)
- 第2ペインで structure を選択すると、ちゃんと定義が出来ているのが分かる。(Figure 2.6)
- 幾何学法則の実験
- 任意の四角形において、ある辺の中点から隣接した辺の中点に線を引くと、その線は平行四辺形になる。(知らんかった。。。)
- この法則を実験するために、MidPointLine というクラスを使います。第1ペインで MidPointLine を選択して確認してみよう。(Figure 2.8)
- 今度は、SHousoku というクラスを作る(やり方はさっきと同じ)
- SHousoku - picture - insert - Shikaku を選択してから下ペインをクリックすると四角がコピーされる。
- 次に、第3、第4ペインで、constrain - MidPointLine を選択
- 四角の各辺をクリックすると、不思議な事に丁度中点にポイントが置かれる。(Figure 2.10)
- constrain を選択していると、図形挿入時にくっつきます。
- 最後に中点同士を ThingLabLine で結びます(insert - ThingLabLine)。
- これで完成。move - Point を選択してから四角の各点を動かしてみると、中の四角形が平行を保つのが分かります。
- はっきり言ってすごい! (Figure 2.12)
- さらに好きな点にアンカーをくっつけると(insert - Anchor) その点を止めたままで図形を変形させる事が出来ます。(Figure 2.13)
計算機を作る
再び http://www.2share.com/thinglab/ThingLab%20-%20Chapter%202.html
を教科書に、 Second Example をみながら。
この ThingLab 不完全な所があって、さっきのパッチ ThingLab-TextEditor-tak.st を fill in しないと動かないので注意してください。
- 摂氏から華氏への変換器を作る。
- クラス TemperatureConverter を作成(第1ペイン右クリック - Define new thing - TemperatureConverter と入力)
- TemperatureConverter - picture - insert - Times で掛け算を挿入
- 挿入する時、右(出力)ノード、本体、左ノードの順でクリックして位置決め。(エラーが出るが何とか無視しながら)
- 同じく insert - Plus で足し算を挿入
- 挿入時掛け算の出力と足し算の入力をくっつくようにしておきますが、後で marge - Node を使ってくっつけても構いません。
- 追加した演算子は、3つの Node の複合体になっています。教科書とは違って、Lead という要素はありません。
- 数値を入れるまでは演算が出来ないというようなエラーが出ますが、今は無視
- insert - Constraint で二つの定数ボックスをそれぞれ と + にくっつける
- edit - TextThing を押してから定数に数値を入れます。(Figure 2.15)
- 教科書ではここで、この部品を元に別のクラスを作る事になっているのですが、早く動作確認をしたいので計算機を完成させてしまいます。
- insert - Printer で二つのテキストボックスを両端にくっつけます。これで完成。
- 例えば edit - TextThing で左端のボックスに100を入れると、右に 212.0 と出ます。逆に、右に100 と入れると 37.777 と反対の計算も出来てしまいます。この逆向きの計算がスゴイ!
- 教科書の Figure 2.18 のように、テキストボックスの変わりに温度計をつけるには、insert - Themometer を使います。
- 温度計を動かすのは move - Point を使います。
- ここで、Constant や Printer を編集するのがなぜ TextThing で、Themometer を動かすのが Point なのか理解できなかったり覚えられないと思いますが、その時は、試しに edit - Constant 等としてみます。
- するとインスペクタというツールが開き、Constant が Printer で出来ている事が分かります(printer を押すと a Printer と書いてある)。さらに Printer の文字を右クリックして inspect を選ぶと、Printer は TextThing で出来ている事が分かります。
教科書では、さらに二次方程式を解いたり電子回路を作ったりするのですが、色々読み替えが必要なようで、そこまで行き着きませんでした。これが20年以上前のシステムだなんて凄すぎる。
自分で ThingLab のオブジェクトをつくる。
ThingLab では、既存のオブジェクトを組み合わせて簡単に新しいオブジェクトを作る事が出来る一方で、全く新しいオブジェクトを一から作るのはちょっと難しい。オブジェクトを作る為のツールが用意されていないばかりか、Smalltalk のマニアックな機能を沢山使って作られているため、Smalltalk 自身が持つ IDE の機能も役に立たないからだ。(多分)そこで、既存のクラスのソースを元に新しいクラスを作成してみる。
注) ThingLab においては、クラスとオブジェクト(インスタンス)の関係は普段の Squeak 以上に密接に繋がっている。ThingLab クラスはそれぞれ prototype というクラスインスタンス変数を持ち、その中にプロトタイプと呼ばれるオブジェクトを一つずつ持つ。ThingLab ブラウザでは、そのオブジェクトを操作する事によりクラス定義を変更する事が出来る。ThingLab のクラス定義では、クラスそのものの定義と同時にプロトタイプの定義(具体的な座標の値など)も行う。
まず、MidPointLine のソースを見よう。Things/MidPointLine.st がそれだ。
ThingLabObject subclass: #MidPointLine
instanceVariableNames: 'line point '
classVariableNames: ''
poolDictionaries: ''
category: 'Prototypes'!
MidPointLine prototype parts: 'line point'.
MidPointLine prototype field: 'line' replaceWith: (40@40 line: 100@20).
MidPointLine prototype field: 'point' replaceWith: 70@30!
MidPointLine prototype inserters: #('line point1' 'line point2').
MidPointLine prototype constrainers: #('line')!
Constraint owner: MidPointLine prototype
rule: 'point = ((line point1 + line point2) // 2)'
error: 'line location dist: point'
methods: #('self primitiveSet.point: (line point1 + line point2) //2'
'line primitiveSet.point2: line point1 + (point-line point1*2)'
'line primitiveSet.point1: line point2 + (point-line point2*2)' )!
クラス定義の後に、メソッド定義ではなく ThingLab のプロトタイプ定義がある。論文には型チェックの定義も出来るような事が書いてある。その後の制約定義が面白い。
制約定義はなんとなく直感で意味がわかると思うが、満たされるべきルールと満たすためのメソッド、そして諦める時の?エラーから成る。line point1 というような構文は path と言って、ThingLab 独特の物だ。point1 なるメソッドはどこにも無いのにメンバアクセサはデフォルトで使えるようになっている。また要素の代入は primitive.メンバ名: を使う。これらの機能はリフレクションを利用している為、Smalltalk ブラウザには現れない。
これを元に新しいクラスを作ってみた。仕様は次の通り
- point1 から point2 へ直線を引く。
- 線を3等分し、point1 に近いほうに点(point) を打つ。
制約の式はややこしく見えるが、ようは point = (2 point1 + point2) / 3 を変形してあるだけだ。右を動かした場合、左を動かした場合、中の点を動かした場合に備えて3つのメソッドが必要だ。
ThingLabObject subclass: #Trisect
instanceVariableNames: 'line point '
classVariableNames: ''
poolDictionaries: ''
category: 'Prototypes'!
Trisect prototype parts: 'line point'.
Trisect prototype field: 'line' replaceWith: (10@10 line: 100@100).
Trisect prototype field: 'point' replaceWith: 40@40 !
Trisect prototype inserters: #('line point1' 'line point2').
Trisect prototype constrainers: #('line')!
Constraint owner: Trisect prototype
rule: 'point = ((2 * line point1 + line point2) // 3)'
error: 'line location dist: point'
methods: #('self primitiveSet.point: (2 * line point1 + line point2) //3'
'line primitiveSet.point2: 3 * point - (2 * line point1)'
'line primitiveSet.point1: (3 * point - line point2) / 2' )!
ThingLabでオームの法則
http://www.2share.com/thinglab/ThingLab%20-%20Chapter%205.html
の Figure 5.2 を見ながら。制約がどのように働くのを調べてみます。
実はこのサンプル VoltageDivider は最初から ThingLab の中に入っているので用意は簡単です。テキストと同じ実験をするには
- 電流計がアナログになっているので、DigitalAmmeter に変更(アナログの方がシブイですが)
- 電池電圧や抵抗値(抵抗のマークは残念ながら消えています) を画面どおりに変更。
説明
- 備考
- ThingLab の動作はプラン時と実行時に分けられます。
- 各点の電圧は、edit - ElectricalNode で分かります
- 電流は edit - ElectricalLead の current の値。カドの所を押さえます
- 自由度の収集
- 制約解決器は、まず制約を満たすために変更しても良いような十分な自由度を持った部分を全部探す。
- そういう部分とその制約は今後検査対象外に出来る。
- 部分を探すには、階層関係を考慮する。例えば point1 x が変更される可能性がある時。point1 が変更されるとみなす。逆に point2 は関係ないとみなす。
- 一つの制約しか持っていない部品は、とりあえず自由度大とみなして最後に実行。
- 例えば電圧計は両端電圧のみに制約を受ける
- 電流計はある点の電流のみの制約です
- 自由度なしの収集
- 制約解決器はまず自由度なしの部分を集める。
- 見つかったらそこから再帰的にワンステップずつ値が決定する部分を探す。
- B の状態から A の状態を知る時。双方に関する制約があり、A が一つの値に決まる必要がある。
- その場合は A のメッセージ計画(MessagePlan) に uniqueState フラグを立てる。
- 制約解決器はオブジェクトの階層関係を利用する事が出来る。
- あるオブジェクトの状態が既知であるとき、そのオブジェクトの部分オブジェクトは全部既知とみなせる。
- あるオブジェクトの部分オブジェクト全部が既知の時。そのオブジェクトは既知とみなせる。
- あるパーツが複数の制約によって決まる時、一つの制約だけ使って、あとはランタイムにチェック。
- 例
- 実行時、グラウンド(アース)制約によってグラウンドの電圧 b1 lead2 は決定する(もちろんゼロ)。
- 電池の制約も使って、電池の反対の電圧 b1 lead1 も決定する(1.5v)。
- 電流計には、両端の電圧を変えてはいけないという制約があるので、右上の電圧 m1 lead2 も来まる(1.5v)。
- 電圧計には電流が流れないので、電圧計の両端の電流は無し。
- 二つの抵抗の間の電圧と、電圧計以外の電流はまだ分かりません。
- Relaxation これは難しいので訳してみる。
Relaxation
もしもこれらの技術で処理できない制約があった場合、その制約解決器はオブジェクトに循環に対処する方法を要求する。現在 Relaxation が唯一用意された方法だ。(ユーザがさらに情報を追加しない場合だ。下記参照)。Relaxation は全に数値の値を持つオブジェクトにだけ使える、また、この制約は一次方程式によって適切な近似となる必要がある。
Relaxation が使われる時、 Relaxer のインスタンス上で呼び出しがコンパイルされる。実行時に、Relaxer はそれぞれのオブジェクトの数値を制約エラーが最小化するように変更する。これらの変更は、連立一次方程式が、初期のエラーへの注意により、および値に関してのエラー表現の派生語を数値的に見つけることにより計算されるとともに、与えられた値の上の制約に接近することにより決定される???。Relaxation は全ての制約が満たされるまで(全てのエラーはある値以下である)、あるいは、システムが制約を満たす(エラーの数がイテレーション後に減少しない事が出来ないとシステムが決定するまで続く。[完全な Relaxiton の手法は Sutherland 1963 を参照]
頻繁に、さらに多くのパーツが必要以上に relax されるだろう。この状況のためには、プラン時にあるトリックが必要だ。このトリックは、パーツの状態を relax されたとみなしてみる事である。例えば、P があるとしよう。この P パーツは他の既知のパーツへ接続されている制約の最大値とともに探す事によって選択された。P は S の集合内に置かれる。そして既知状態収集の方法は、任意のほかのパーツの状態が結果として既知になるようにみなすよう実行する事だ。P そのものと共に既知になるだろう全てのパーツは relax されたパーツ集合から除去される。このプロセスは relax されたパーツの集合が空になるまで続く。実行時には、ただ S 内のパーツだけが relax される。S 内のそれぞれの P が relax されるようにシステムも新しいパーツの状態を計算するP が知っていたとみなす結果というように知っている。P の制約を満足させる際のエラーを計算する際に、Pそのものの制約と、これら他のパーツの双方の解決時のこのエラーをシステムは考慮する。[発見的な P の選択方法は記号代数的な操作を行う際、未知を選択する為にEL 回路分析プログラムから利用時に適合される)Stallman & Sussman 1977)]
この電圧回路に置いてはr2 lead1 は現在木状の制約接続を持っているオームの法則が r2 の制約だ。r2 の制約は、Kirchoff の法則から成る TwoLeadedObject から継承している。他には知らない制約は無い。のでシステムはそれを知ろうとする値により、 r2 lead1 の電圧と他の全ての電圧が分かる従って、実行時の r2 の電流が分かる。最後に、ワイアの制約により、w1 lead2, w2 loead2, w3 lead1 の全ての電圧が分かる。
うーん。わけわからん。
Links to this Page
- SqueakTips last edited on 9 November 2004 at 5:00:48 pm by 192.168.0.8
- 色々なサンプル last edited on 28 April 2005 at 12:42:45 pm by 192.168.0.4