[View] [Edit] [Attachments] [History] [Home] [Changes] [Search] [Help]

ThingLab

Squeak2.3 で、 ThingLab という制約プログラミングの実験ソフトが使えます。


例えば Photoshop なんかで、紙の大きさを設定するのに、縦横の比率をロックすると縦のサイズを
操作するだけで自動的に横のサイズが変わるという便利な機能があります。制約プログラミングとは、
このような考え方を全面的に採用したプログラミングの考え方です。幾何学の定理や物理のシミュレーションを
自然に表現できるという利点があります。ThingLab は 1970年代終盤にAlan Borning 氏により開発されました。

ThingLab の特徴

インストール、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 を実験してみます。




計算機を作る


再び http://www.2share.com/thinglab/ThingLab%20-%20Chapter%202.html
を教科書に、 Second Example をみながら。
この ThingLab 不完全な所があって、さっきのパッチ ThingLab-TextEditor-tak.st を fill in しないと動かないので注意してください。


教科書では、さらに二次方程式を解いたり電子回路を作ったりするのですが、色々読み替えが必要なようで、そこまで行き着きませんでした。これが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 ブラウザには現れない。

これを元に新しいクラスを作ってみた。仕様は次の通り
制約の式はややこしく見えるが、ようは 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 の中に入っているので用意は簡単です。テキストと同じ実験をするには

説明

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

propella home