Version 6.5
psim 言語リファレンスマニュアル
Copyright © 2008-2023 NTT DATA Mathematical Systems, Inc. All Rights Reserved.
psim 言語は、Python 上で動作するシミュレーションの記述、実行、分析をサポートするための言語である。
主な機能としては、以下がある。
離散イベントシミュレーションを記述、実行する機能
エージェントベースシミュレーションを記述、実行する機能
フローベースでシミュレーションを記述、実行する機能
分析機能
乱数生成機能
強化学習機能
S4 Simulation System の様々な機能は psim 言語を使う事で実現されている。
psim の機能を使えるようにするには、最初に、
を実行する。
また、初期化のために、
を実行する。
シミュレーションの内部状態を全て初期化する。
プロセスは、Python のジェネレータ関数として定義する。
Python では、関数内に yield がひとつでも含まれればジェネレータ関数となる。
プロセス内には、任意の Python のコードが書ける。また、プロセス内には待ち受けを実行するために、複数の
を記述する事が出来る。待ち受けは、任意の Python の制御構造内に記述する事が出来る。
しかしながら、ひとつも yield がない場合、無効なプロセスとなる。(プロセスを登録する時にエラーが発生する)
また、以下のように proc 内で proc2 を呼出し、proc2 内で yield を書いてもエラーにはならないが、proc2 内で yield を実行しても、スケジューラに命令が渡らないため、待ち受けは実行されない。(サブプロセスを実現したいのであれば、2.17 章章を参照)
エラーコード
プロセスはインスタンスメソッドとして定義する事も可能である。
プロセスをシミュレーターに登録するには、activate を実行する。
プロセス process を起動する。起動時間 at と起動遅延時間 delay とガード式 cond はオプショナルであるが、複数を指定した場合はエラーとなる。at が指定された場合は、シミュレーション時間 at にプロセスを起動する。delay が指定された場合は、プロセスの起動を指定時間遅らせる。cond が指定された場合、まず cond の成立を待ち受ける。何れも指定されなかった場合は、起動前の待ち受けは行われない。起動条件成立後、プロセス名 name のプロセス process を実行する。at もしくは delay が指定された時のみ、優先度 priority は有効となり、同時刻の起動優先度を示す。終了、一時停止、再開ハンドラをそれぞれ、terminatedHandler,suspendedHandler, resumedHandler で指定する事が出来る。各ハンドラは、1 引数の関数で、プロセス状態が変化した時に、発火値の設定された単一の待ち受け結果を引数として呼出される。ハンドラを明示的に指定しなかった場合は、空のハンドラが設定される。(*args, **keys) に書かれた引数は全て process に送られる。返り値はプロセスの実行状態を現す継続オブジェクトである。
def proc(delay, msg):
yield pause(delay)
print(msg)
activate(proc, at = 10, priority = 3,
name = "process foo")(3, "Hello world!")
start()
なお、たとえ、プロセスが無引数だったとしても、activate のふたつ目の括弧は省略出来ない。
エラーコード
は、エラーとはならないが、無処理となる。
シミュレーションを開始するには、start を実行する。
シミュレーションを開始する。until が指定された場合は、シミュレーション時間が until になったら、シミュレーションを停止する。until が指定されなかった場合は、スケジューラのキューが空になるまで実行し、キューが空になると停止する。odesolver は連続シミュレーションを実行する際の常微分方程式ソルバーを指定する。常微分方程式ソルバーは数種類用意されており、詳細は、2.14.8 章 を参照の事。
シミュレーションを停止する。シミュレーション実行中にシミュレーションを停止したい場合は、プロセス内で、finish() を呼ぶと、シミュレーションが停止する。
プロセス内では様々な待ち受けを行う事が出来る。待ち受けの条件をガード式と呼ぶ。
プロセス定義内に、この記述があると、プロセスの実行を一旦停止し、スケジューラにガード式が戻る。スケジューラはガード式によって、プロセスの実行を制御する。
現在のシミュレーション時間を返す。
シミュレーション時間 delay だけプロセスの実行を停止するガード式である。優先度は priority、ガード名は name となる。同時刻に複数の時間待ち受けが成立した場合、優先度 priority が高いものが先に実行される。発火値は None である。
名前 name のイベントオブジェクトを作成する。キューの種別は queue となる。キューについては、2.24 章を参照。monitor が真の場合は、イベントの待ち行列数の時系列変化を時系列モニターに記録する。
イベントオブジェクト event が発火するまで、プロセスの実行を停止するガード式である。優先度は priority、ガード名は name となる。同時刻に複数のイベント待ち受けが成立した場合、キュー種別によって、実行順が定まる。発火値はイベント発火時に指定された値となる。canceled には 1 引数の関数、あるいは、None を指定する。None でない場合、複合待ち受けにおいて、この待ち受け操作が完了した後にその待ち受けパスがキャンセル(2.9.4 章)された場合、待ち受け結果を引数として canceled ハンドラが呼ばれる。
イベントオブジェクト event を発火する。event で待ち受けている全てのイベント待ち受け状態のプロセスを再開する。val が指定された場合、イベント待ち受けの発火値に指定された値が渡る。n が指定された場合は最大 n 個のイベント待ち受け状態のプロセスを再開し、そうでなければ、全てのイベント待ち受け状態のプロセスを再開する。
イベント発火 e.signal(val, n) を実行後、常に成立する待ち受けを行う。
イベントオブジェクト event の名前を取得する。
イベントオブジェクト event を待ち受けている数を返す。
イベントオブジェクトの時系列変化を記録した時系列モニターを返す。イベントオブジェクトで時系列モニターを記録した場合のみ、参照可能となる。列数は 1 であり、発火待ち数を示す。
容量が capacity で、名前 name のファシリティオブジェクトを作成する。キューの種別は queue となる。キューについては、2.24 章を参照。monitor が真の場合は、ファシリティの待ち行列数の時系列変化を時系列モニターに記録する。
容量が capacity で、名前 name のファシリティオブジェクトを作成する。キューの種別は queue となる。キューについては、2.24 章を参照。monitor が真の場合は、ファシリティの待ち行列数の時系列変化を時系列モニターに記録する。
schedule は時間と容量からなるタプルのリスト [(時間_1, 容量_1), (時間_2, 容量_2), …] である。offset には開始時間を指定する。つまり、offset + 時間_i に、容量が容量_i に変化する。repeat に数値が指定された場合、任意の k \ge 0 に対し、offset + repeat * k + 時間_i に、容量が容量_i に変化する。ただし repeat に数値を指定する場合は、schedule 内の最大時間以上でなくてはならない。また、時間_i < 時間_{i + 1} でなくてはならない。schedule が長さ 0 のリストであった場合は、容量変化スケジュールは登録されない。
gfailure にジェネレータが指定された場合、故障の発生間隔を返す乱数生成器として利用される。grepair にジェネレータが指定された場合、故障発生後に回復するまでの時間を返す乱数生成器として利用される。gfailure にジェネレータが指定され、grepair にジェネレータが指定されていない場合は、一度故障すると回復しない。
releaseIfStopped が指定されていた場合、ファシリティロックが利用不可になった時に、強制的に release を実行する。ファシリティロックを利用しているプロセスは、facilityLock.isAvailable() にて、現在利用可能か否かを確認する事ができる。もしくはガード式 facilityLock.stopped() を使う事で、利用不可能になる事を待ち受ける事も出来る。
releaseIfStopped が指定されていない場合は、強制的な release は発生しない。その場合、一時的に facility.sizeBuffer() > facility.capacity - facility.nfailure になる場合がある。
ファシリティ facility からロックを取得出来るまで、プロセスの実行を停止するガード式である。優先度は priority、ガード名は name となる。発火値としてファシリティロックオブジェクトが返される。canceled には 1 引数の関数、あるいは、None を指定する。None でない場合、複合待ち受けにおいて、この待ち受け操作が完了した後にその待ち受けパスがキャンセル(2.9.4 章)された場合、待ち受け結果を引数として canceled ハンドラが呼ばれる。
ファシリティのロックを解放する。ファシリティを待ち受けているファシリティ待ち受け状態のプロセスが再開する。プロセスの再開順序は、ファシリティの取得待ち受けで指定された優先度の高いもの、優先度が同じ場合は作成順番が早いものとなる。
ファシリティのロックの解放 facilityLock.release() を実行後、常に成立する待ち受けを行う。
あるいは、2.22.7 章のAPIも利用可能である。
ファシリティロックが現在利用可能かどうかを調べ、真偽を返す。利用不可能とは、ファシリティ容量が減少し、利用不可能になった場合と、故障が発生し、利用不可能になった場合がある。
ファシリティロックが利用不可能になるのを待ち受けるガード式である。利用不可能とは、ファシリティ容量が減少し、利用不可能になった場合と、故障が発生し、利用不可能になった場合がある。ガード名は name となる。
ファシリティの取得時に canceled ハンドラとして、releaseIfRequested を指定すると、キャンセルされた場合に、自動的にファシリティを解放する。
ファシリティオブジェクト facility の名前を取得する。
ファシリティオブジェクト facility の容量を取得する。
ファシリティオブジェクト facility の現在のバッファ数を返す。ロックが満杯の時、facility.sizeBuffer() == facility.capacity となる。
ファシリティオブジェクト facility の現在停止中のバッファ数を返す。
ファシリティオブジェクト facility を待ち受けている数を返す。
ファシリティオブジェクトの時系列変化を記録した時系列モニターを返す。ファシリティオブジェクトで時系列モニターを記録した場合のみ、参照可能となる。列数は 2 であり、それぞれ、要求待ち数、バッファ数(利用可能なファシリティ数)を示す。
容量が capacity で、名前 name のファシリティオブジェクトを作成する。キューの種別は queue となる。キューについては、2.24 章を参照。monitor が真の場合は、ファシリティの待ち行列数の時系列変化を時系列モニターに記録する。
段取替に対応した、容量が 1 固定の、名前 name のファシリティオブジェクトを作成する。キューの種別は queue となる。キューについては、2.24 章を参照。monitor が真の場合は、ファシリティの待ち行列数の時系列変化を時系列モニターに記録する。
products には、このファシリティが対応する品種のリストを指定する。
product には、初期の品種を指定する。products の要素でなくてはならない。
changeoverMat には、段取替時間を行列形式(リストのリスト)で指定する。品種A から 品種B への段取替時間を changeoverMat[品種Aのインデックス][品種Bのインデックス] に指定する。ここで品種Aのインデックスとは、products リスト内の品種Aのインデックスである。なお、changeoverMat[i][i] は指定しても利用されない。
品種 product の段取替時間 time を指定する。既に指定されている品種の場合はエラーとなるので、一度削除する必要がある。
その他のオプションは、Faciltiy と同じである。
段取替ファシリティ changeoverFacility からロックを取得出来るまで、プロセスの実行を停止するガード式である。優先度は priority、ガード名は name となる。発火値としてファシリティロックオブジェクトが返される。canceled には 1 引数の関数、あるいは、None を指定する。None でない場合、複合待ち受けにおいて、この待ち受け操作が完了した後にその待ち受けパスがキャンセル(2.9.4 章)された場合、待ち受け結果を引数として canceled ハンドラが呼ばれる。 段取替ファシリティは最初に段取替を実施する。品種 product が現時点で設定されている品種である場合は、何もしない。そうでない場合、指定された品種へ段取替を実施する。
段取り替え中は、段取替ファシリティをロックする。
段取替ファシリティ changeoverFacility からロックを取得出来るまで、プロセスの実行を停止するガード式である。優先度は priority、ガード名は name となる。発火値としてファシリティロックオブジェクトが返される。canceled には 1 引数の関数、あるいは、None を指定する。None でない場合、複合待ち受けにおいて、この待ち受け操作が完了した後にその待ち受けパスがキャンセル(2.9.4 章)された場合、待ち受け結果を引数として canceled ハンドラが呼ばれる。
段取替ファシリティは最初に段取替を実施する。品種 product が現時点で設定されている品種である場合は、何もしない。そうでない場合、指定された品種へ段取替を実施する。
段取り替え中は、ファシリティをロックする。
request 中にスケジュールによるキャパシティの減少、故障が発生した場合、
段取替中なら、段取替は中止され、品種は段取替前の状態から変化しない。
ファシリティロックの取得待ち状態なら、取得待ちを続ける。ただし、releaseIfStopped が指定されている場合は強制的に開放する(従来の仕様)
request 中にキャンセルが発生した場合、
段取替中なら、段取替は中止され、品種は段取替前の状態から変化しない。
ファシリティロックの取得待ち状態なら、待ち受けを停止する。
判定方法
段取替要求は外部要因(スケジュールや故障)で失敗する事がある。要求後は、必ず品種が切り替わったかどうかを確認し、適切な処理を書く必要がある。
result = yield changeoverFacility.request("A",
name = "request")
if changeoverFacility.product == "A":
# 段取替成功
else:
# 段取替失敗
現時点の品種を返す。(読み込み専用)
段取替ファシリティオブジェクト changeoverFacility の名前を取得する。
段取替ファシリティオブジェクト changeoverFacility の容量を取得する。
段取替ファシリティオブジェクト changeoverFacility の現在のバッファ数を返す。ロックが満杯の時、changeoverFacility.sizeBuffer() == changeoverFacility.capacity となる。
段取替ファシリティオブジェクト changeoverFacility の現在停止中のバッファ数を返す。
段取替ファシリティオブジェクト changeoverFacility を待ち受けている数を返す。
段取替ファシリティオブジェクトの時系列変化を記録した時系列モニターを返す。ファシリティオブジェクトで時系列モニターを記録した場合のみ、参照可能となる。列は それぞれ、要求待ち数、バッファ数(利用可能なファシリティ数)、容量、停止中数、段取替中数、品種を示す。
容量が capacity で、初期量が buffer で、名前が name のタンクオブジェクトを作成する。追加操作用のキューの種別は putQueue となる。取得操作用のキューの種別は getQueue となる。キューについては、2.24 章章を参照。monitor が真の場合は、タンクの待ち行列数の時系列変化を時系列モニターに記録する。
容量が capacity で、初期量が buffer で、名前が name のタンクオブジェクトを作成する。追加操作用のキューの種別は putQueue となる。取得操作用のキューの種別は getQueue となる。キューについては、2.24 章章を参照。monitor が真の場合は、タンクの待ち行列数の時系列変化を時系列モニターに記録する。
schedule は時間と容量からなるタプルのリスト [(時間_1, 容量_1), (時間_2, 容量_2), …] である。offset には開始時間を指定する。つまり、offset + 時間_i に、容量が容量_i に変化する。repeat に数値が指定された場合、任意の k \ge 0 に対し、offset + repeat * k + 時間_i に、容量が容量_i に変化する。ただし repeat に数値を指定する場合は、schedule 内の最大時間以上でなくてはならない。また、時間_i < 時間_{i + 1} でなくてはならない。schedule が長さ 0 のリストであった場合は、容量変化スケジュールは登録されない。
overflow は、2 引数の関数あるいは None を指定する。None でない場合、現在のバッファ数が容量を越えてしまった場合に、第1引数がタンクオブジェクト、第2引数が容量を越えてしまった量が設定されて呼ばれる。
タンクに val を加えるガード式である。優先度は priority、ガード名は name となる。タンクに空きがある場合は、即座に発火する。タンク容量を越えてしまいタンクに追加が出来ない場合は、空きが出来るまでプロセスを停止する。空きが出来たら、キューの種別によって実行順が定まる。発火値は None となる。val は 0 以上でなくてはならない。canceled には 1 引数の関数、あるいは、None を指定する。None でない場合、複合待ち受けにおいて、この待ち受け操作が完了した後にその待ち受けパスがキャンセル(2.9.4 章)された場合、待ち受け結果を引数として canceled ハンドラが呼ばれる。
タンクから val を取得するガード式である。優先度は priority、ガード名は name となる。タンク容量が足らず取得が出来ない場合は、取得出来るまでプロセスを停止する。実行順はキューの種別によって定まる。発火値は None となる。val は 0 以上でなくてはならない。canceled には 1 引数の関数、あるいは、None を指定する。None でない場合、複合待ち受けにおいて、この待ち受け操作が完了した後にその待ち受けパスがキャンセル(2.9.4 章)された場合、待ち受け結果を引数として canceled ハンドラが呼ばれる。
タンクオブジェクト tank の名前を取得する。
タンクオブジェクト tank の容量を取得する。
タンクオブジェクト tank の現在のバッファ量を返す。タンクが空の時、tank.sizeBuffer() == 0 となり、タンクが満杯の時、tank.sizeBuffer() == tank.capacity となる。
タンクオブジェクト tank からの取得を待ち受けている数を返す。
タンクオブジェクト tank からの取得を待ち受けている各要求の合計要求量を返す。
タンクオブジェクト tank への追加を待ち受けている数を返す。
タンクオブジェクト tank への追加を待ち受けている各要求の合計要求量を返す。
タンクオブジェクトの時系列変化を記録した時系列モニターを返す。タンクオブジェクトで時系列モニターを記録した場合のみ、参照可能となる。列数は 5 であり、それぞれ、追加待ち数、追加待ち合計、取得待ち数、取得待ち合計、バッファ量を示す。
オブジェクトリストが buffer で、容量が capacity で、名前が name のストアオブジェクトを作成する。buffer はリストである。capacity はリストの最大サイズを指し、False が指定された場合は、容量制限は無しとなる。追加操作用のキューの種別は putQueue となる。取得操作用のキューの種別は getQueue となる。キューについては、2.24 章章を参照。monitor が真の場合は、ストアの待ち行列数の時系列変化を時系列モニターに記録する。init 引数には値と優先度からなるタプルのリスト [(値1, 優先度1), (値2, 優先度2), …] を指定する事が出来る。空リストでない場合、シミュレーション開始時に各要素に対し、store.put1(値, priority = 優先度) が実行される。容量以上の要素を指定した場合、追加キューに並ぶ。
オブジェクトリストが buffer で、容量が capacity で、名前が name のストアオブジェクトを作成する。buffer はリストである。capacity はリストの最大サイズを指し、False が指定された場合は、容量制限は無しとなる。追加操作用のキューの種別は putQueue となる。取得操作用のキューの種別は getQueue となる。キューについては、2.24 章章を参照。monitor が真の場合は、ストアの待ち行列数の時系列変化を時系列モニターに記録する。init 引数には値と優先度からなるタプルのリスト [(値1, 優先度1), (値2, 優先度2), …] を指定する事が出来る。空リストでない場合、シミュレーション開始時に各要素に対し、store.put1(値, priority = 優先度) が実行される。容量以上の要素を指定した場合、追加キューに並ぶ。
schedule は時間と容量からなるタプルのリスト [(時間_1, 容量_1), (時間_2, 容量_2), …] である。offset には開始時間を指定する。つまり、offset + 時間_i に、容量が容量_i に変化する。repeat に数値が指定された場合、任意の k \ge 0 に対し、offset + repeat * k + 時間_i に、容量が容量_i に変化する。ただし repeat に数値を指定する場合は、schedule 内の最大時間以上でなくてはならない。また、時間_i < 時間_{i + 1} でなくてはならない。schedule が長さ 0 のリストであった場合は、容量変化スケジュールは登録されない。
overflow は、2 引数の関数あるいは None を指定する。None でない場合、現在のバッファ数が容量を越えてしまった場合に、第1引数がストアオブジェクト、第2引数が容量を越えてしまった数が設定されて呼ばれる。
ストアのオブジェクトリストに buffer を加えるガード式である。優先度は priority、待ち受け名は name となる。buffer は追加するオブジェクトのリストである。ストア容量を越えてしまいオブジェクト追加が出来ない場合は、空きが出来るまでプロセスを停止する。canceled には 1 引数の関数、あるいは、None を指定する。None でない場合、複合待ち受けにおいて、この待ち受け操作が完了した後にその待ち受けパスがキャンセル(2.9.4 章)された場合、待ち受け結果を引数として canceled ハンドラが呼ばれる。 disposal が 0 以上の値が設定されていた場合、disposal 時間経過後に、ストアの追加待ち行列もしくはストア内に残っていた場合強制廃棄される。disposed に 1 引数の関数が指定されていた場合、廃棄されたオブジェクトを引数に、disposed 関数がそれぞれ呼び出される。ストアの追加待ちの状態で破棄された場合、store の追加処理は終了するが、待ち受け結果には “disposed” が含まれる。
注意: 破棄されると、disposed 関数が呼ばれ、ストアから除去されるが、対象となるオブジェクト自体が破棄されるわけでない。オブジェクトを参照しているプロセスが存在する場合、ユーザーコードで後始末を行う必要がある。
ストアのオブジェクトリストに obj を加えるガード式である。優先度は priority、待ち受け名は name となる。obj は追加するオブジェクトである。ストア容量を越えてしまいオブジェクト追加が出来ない場合は、空きが出来るまでプロセスを停止する。canceled には 1 引数の関数、あるいは、None を指定する。None でない場合、複合待ち受けにおいて、この待ち受け操作が完了した後にその待ち受けパスがキャンセル(2.9.4 章)された場合、待ち受け結果を引数として canceled ハンドラが呼ばれる。 disposal が 0 以上の値が設定されていた場合、disposal 時間経過後に、ストアの追加待ち行列もしくはストア内に残っていた場合強制廃棄される。disposed に 1 引数の関数が指定されていた場合、廃棄されたオブジェクトを引数に、disposed 関数が呼び出される。ストアの追加待ちの状態で破棄された場合、store の追加処理は終了するが、待ち受け結果には “disposed” が含まれる。
注意: 破棄されると、disposed 関数が呼ばれ、ストアから除去されるが、対象となるオブジェクト自体が破棄されるわけでない。オブジェクトを参照しているプロセスが存在する場合、ユーザーコードで後始末を行う必要がある。
ストアのオブジェクトリストから n 個のオブジェクトを取得するガード式である。condition に1引数の関数を指定した場合、condition が成立するようなオブジェクトのみを取得する。優先度は priority、待ち受け名は name となる。待ち受け結果は取得したリストである。オブジェクト数が足らず取得出来ない場合は、取得出来るまでプロセスを停止する。canceled には 1 引数の関数、あるいは、None を指定する。None でない場合、複合待ち受けにおいて、この待ち受け操作が完了した後にその待ち受けパスがキャンセル(2.9.4 章)された場合、待ち受け結果を引数として canceled ハンドラが呼ばれる。
ストアのオブジェクトリストから ひとつのオブジェクトを取得するガード式である。condition に1引数の関数を指定した場合、condition が成立するようなオブジェクトのみを取得する。優先度は priority、待ち受け名は name となる。待ち受け結果は取得したオブジェクトである。オブジェクト数が足らず取得出来ない場合は、取得出来るまでプロセスを停止する。canceled には 1 引数の関数、あるいは、None を指定する。None でない場合、複合待ち受けにおいて、この待ち受け操作が完了した後にその待ち受けパスがキャンセル(2.9.4 章)された場合、待ち受け結果を引数として canceled ハンドラが呼ばれる。
ストアのオ
ストアオブジェクト store の名前を取得する。
ストアオブジェクト store の容量を取得する。
ストアオブジェクト store の現在のバッファ数を返す。ストアが空の時、store.sizeBuffer() == 0 となり、ストアが満杯の時、store.sizeBuffer() == store.capacity となる。
ストアオブジェクト store からの取得を待ち受けている数を返す。
ストアオブジェクト store からの取得を待ち受けている各要求の合計要求量を返す。
ストアオブジェクト store への追加を待ち受けている数を返す。
ストアオブジェクト store への追加を待ち受けている各要求の合計要求量を返す。
ストアのオブジェクトリストを返す。この値を書き換える場合は、他のプロセスも参照する可能性もあるので、必ずアトミックに行わなくてはならない。つまり、store.buffer を読み取った時点と、書き込む時点間に、プロセスの切り替えが発生してはならない。store.replace を利用した場合は、アトミック性が保証される。
ストアのオブジェクトリストを引数に filter 関数を呼び出し、その結果であるリストが、ストアのリストに置き換わる。
store = Store()
def proc():
yield store.put1(3)
yield store.put1(4)
yield store.put1(2)
def proc2():
yield pause(1)
gotlist = []
def filter(lst):
rest = []
for elem in lst:
if elem == 4:
gotlist.append(elem)
else:
rest.append(elem)
return rest
store.replace(filter)
print("rest", store.buffer) # (=> [3, 2])
print("gotlist", gotlist) # (=> [4])
activate(proc)()
activate(proc2)()
start()
は、ストアの中から、値が 4 の要素のみを取り出す。
ストアオブジェクトの時系列変化を記録した時系列モニターを返す。ストアオブジェクトで時系列モニターを記録した場合のみ、参照可能となる。列数は 5 であり、それぞれ、追加待ち数、追加待ち合計、取得待ち数、取得待ち合計、バッファ数を示す。
複数のガード式を組み合わせて、より複雑な待ち受けを実行する事が出来る。
ガード式_ 1 と、ガード式_2 を OR 待ち受けするガード式である。ガード式_1 かガード式_2 のどちらか一方が成立すれば、残りのガード式は除去(2.9.4 章)され、このガード式が成立する。
ガード式_ 1 からガード式_n を OR 待ち受けするガード式である。あるガード式_i (1 \le i \le n) が成立すれば、残りのガード式_j (j \neq i)は除去(2.9.4 章)され、このガード式が成立する。
ガード式_1 と、ガード式_2 を AND 待ち受けするガード式である。ガード式_1 とガード式_2 の両方が成立すれば、このガード式が成立する。なお、AND 待ち受けは、待ち受けの完了を同期化するもので、待ち受けの成立時間を同期化するものではない。
ガード式_1 から ガード式_n を AND 待ち受けするガード式である。全ての ガード式_i (1 \le i \le n) が成立すれば、このガード式が成立する。なお、AND 待ち受けは、待ち受けの完了を同期化するもので、待ち受けの成立時間を同期化するものではない。
ガード式_1 と、ガード式_2 を 逐次待ち受けするガード式である。まずガード式_1 を待ち受けし、ガード式_1 が成立したら、ガード式_2 の待ち受けを開始する。ガード式_2 が成立すれば、このガード式が成立する。
ガード式_1 から ガード式_n を 逐次待ち受けするガード式である。まず ガード式_1 を待ち受けし、ガード式_1 が成立したら、ガード式_ 2 の待ち受けを開始する。同様にガード式_ i (1\le i \le n-1) が成立したら、ガード式_{i+1} の待ち受けを開始する。ガード式_n が成立すれば、このガード式が成立する。
OR 待ち受けのある子ガード式のひとつが成立すると、OR 待ち受けが成立する。その時、残りのガード式は除去される。除去とは、以下を指す。
そのガード式がまだ待ち受け登録されていない場合(逐次待ち受けの後半など)、待ち受け登録の予約が除去される。
そのガード式が既に登録されているが、まだ成立していない場合(資源待ち受けなど)、その資源待ち受けが除去される。
そのガード式が既に成立している場合(逐次待ち受けの前半など)、何もしない。
ただし、資源待ち受け(ファシリティの取得、タンクからの取得など)の場合、キャンセルハンドラを指定する事が出来る。キャンセルハンドラを指定している場合、上記 3. の場合に、キャンセルハンドラが呼ばれる。
結合優先度は Python の演算子の優先度に従う。つまり、優先度の高い順に、>>, &, | になる。例えば、a, b, c, d, e はガード式とすると、
は、
と解釈される。
複数のイベントオブジェクトを組み合わせて、複合イベントオブジェクトを作る事が出来る。また、複合イベントオブジェクトに対して、待ち受けを実行する事が出来る。
イベントオブジェクトevent_1 とイベントオブジェクト event_2 の OR 複合イベントオブジェクトを作成する。
event_1 と event_2 の OR 複合イベントオブジェクトを待ち受けるガード式である。event_1 と event_2 のどちらかが発火するまで、プロセスの実行を停止する。優先度は priority、ガード名は name となる。canceled には 1 引数の関数、あるいは、None を指定する。None でない場合、複合待ち受けにおいて、この待ち受け操作が完了した後にその待ち受けパスがキャンセル(2.9.4 章)された場合、待ち受け結果を引数として canceled ハンドラが呼ばれる。
イベントオブジェクト event_1 からイベントオブジェクト event_n の OR 複合イベントオブジェクトを作成する。
event_1 から event_n の OR 複合イベントオブジェクトを待ち受けるガード式である。ある event_i (1 \le i \le n) が発火するまで、プロセスの実行を停止する。優先度は priority、ガード名は name となる。canceled には 1 引数の関数、あるいは、None を指定する。None でない場合、複合待ち受けにおいて、この待ち受け操作が完了した後にその待ち受けパスがキャンセル(2.9.4 章)された場合、待ち受け結果を引数として canceled ハンドラが呼ばれる。
イベントオブジェクト event_1 とイベントオブジェクト event_2 の AND 複合イベントオブジェクトを作成する。
event_1 と event_2 の AND 複合イベントオブジェクトを待ち受けるガード式である。event_1 と event_2 の両方が発火するまで、プロセスの実行を停止する。優先度は priority、ガード名は name となる。canceled には 1 引数の関数、あるいは、None を指定する。None でない場合、複合待ち受けにおいて、この待ち受け操作が完了した後にその待ち受けパスがキャンセル(2.9.4 章)された場合、待ち受け結果を引数として canceled ハンドラが呼ばれる。
イベントオブジェクト event_1 からイベントオブジェクト event_n の AND 複合イベントオブジェクトを作成する。
event_1 から event_n の AND 複合イベントオブジェクトを待ち受けるガード式である。全てのevent_i (1 \le i \le n) が発火するまで、プロセスの実行を停止する。優先度は priority、ガード名は name となる。canceled には 1 引数の関数、あるいは、None を指定する。None でない場合、複合待ち受けにおいて、この待ち受け操作が完了した後にその待ち受けパスがキャンセル(2.9.4 章)された場合、待ち受け結果を引数として canceled ハンドラが呼ばれる。
イベントオブジェクト event_1 とイベントオブジェクト event_2 の逐次複合イベントオブジェクトを作成する。
event_1 と event_1 の逐次複合イベントオブジェクトを待ち受けるガード式である。まず event_1 の待ち受けを開始する。event_1 が発火すると event_2 の待ち受けを開始し、event_2 が発火するまで、プロセスの実行を停止する。優先度は priority、ガード名は name となる。canceled には 1 引数の関数、あるいは、None を指定する。None でない場合、複合待ち受けにおいて、この待ち受け操作が完了した後にその待ち受けパスがキャンセル(2.9.4 章)された場合、待ち受け結果を引数として canceled ハンドラが呼ばれる。
イベントオブジェクト event_1 からイベントオブジェクト event_n の逐次複合イベントオブジェクトを作成する。
event_1 から event_n の逐次複合イベントを待ち受けるガード式である。まず event_1 の待ち受けを開始する。event_1 が発火すると event_2 の待ち受けを開始する。同様に event_i (1 \le i \le n-1) が発火すると、event_{i+1} の待ち受けを開始する。event_n が発火するまで、プロセスの実行を停止する。優先度は priority、ガード名は name となる。canceled には 1 引数の関数、あるいは、None を指定する。None でない場合、複合待ち受けにおいて、この待ち受け操作が完了した後にその待ち受けパスがキャンセル(2.9.4 章)された場合、待ち受け結果を引数として canceled ハンドラが呼ばれる。
結合優先度は Python の演算子の優先度に従う。つまり、優先度の高い順に、>>, &, | になる。例えば、a, b, c, d, e はイベントとすると、
は、
と解釈される。
複数のファシリティオブジェクトを組み合わせて、複合ファシリティオブジェクトを作る事が出来る。また、複合ファシリティオブジェクトに対して、待ち受けを実行する事が出来る。
ファシリティオブジェクトfacility_1 とファシリティオブジェクト facility_2 の OR 複合ファシリティオブジェクトを作成する。
facility_1 と facility_2 の OR 複合ファシリティオブジェクトを待ち受けるガード式である。facility_1 と facility_2 のどちらかからロックを取得出来るまで、プロセスの実行を停止する。優先度は priority、ガード名は name となる。canceled には 1 引数の関数、あるいは、None を指定する。None でない場合、複合待ち受けにおいて、この待ち受け操作が完了した後にその待ち受けパスがキャンセル(2.9.4 章)された場合、待ち受け結果を引数として canceled ハンドラが呼ばれる。
ファシリティオブジェクト facility_1 からファシリティオブジェクト facility_n の OR 複合ファシリティオブジェクトを作成する。
facility_1 から facility_n の OR 複合ファシリティオブジェクトを待ち受けるガード式である。ある facility_i (1 \le i \le n) のロックが取得出来るまで、プロセスの実行を停止する。優先度は priority、ガード名は name となる。canceled には 1 引数の関数、あるいは、None を指定する。None でない場合、複合待ち受けにおいて、この待ち受け操作が完了した後にその待ち受けパスがキャンセル(2.9.4 章)された場合、待ち受け結果を引数として canceled ハンドラが呼ばれる。
ファシリティオブジェクト facility_1 とファシリティオブジェクト facility_2 の AND 複合ファシリティオブジェクトを作成する。
facility_1 と facility_2 の AND 複合ファシリティオブジェクトを待ち受けるガード式である。facility_1 と facility_2 の両方のロックが取得出来るまで、プロセスの実行を停止する。優先度は priority、ガード名は name となる。canceled には 1 引数の関数、あるいは、None を指定する。None でない場合、複合待ち受けにおいて、この待ち受け操作が完了した後にその待ち受けパスがキャンセル(2.9.4 章)された場合、待ち受け結果を引数として canceled ハンドラが呼ばれる。
ファシリティオブジェクト facility_1 からファシリティオブジェクト facility_n の AND 複合ファシリティオブジェクトを作成する。
facility_1 から facility_n の AND 複合ファシリティオブジェクトを待ち受けるガード式である。全てのfacility_i (1 \le i \le n) のロックが取得出来るまで、プロセスの実行を停止する。優先度は priority、ガード名は name となる。canceled には 1 引数の関数、あるいは、None を指定する。None でない場合、複合待ち受けにおいて、この待ち受け操作が完了した後にその待ち受けパスがキャンセル(2.9.4 章)された場合、待ち受け結果を引数として canceled ハンドラが呼ばれる。
ファシリティオブジェクト facility_1 とファシリティオブジェクト facility_2 の逐次複合ファシリティオブジェクトを作成する。
facility_1 と facility_1 の逐次複合ファシリティオブジェクトを待ち受けるガード式である。まず facility_1 の待ち受けを開始する。facility_1 のロックが取得出来たら facility_2 の待ち受けを開始し、facility_2 のロックが取得出来るまで、プロセスの実行を停止する。優先度は priority、ガード名は name となる。canceled には 1 引数の関数、あるいは、None を指定する。None でない場合、複合待ち受けにおいて、この待ち受け操作が完了した後にその待ち受けパスがキャンセル(2.9.4 章)された場合、待ち受け結果を引数として canceled ハンドラが呼ばれる。
ファシリティオブジェクト facility_1 からファシリティオブジェクト facility_n の逐次複合ファシリティオブジェクトを作成する。
facility_1 から facility_n の逐次複合ファシリティを待ち受けるガード式である。まず facility_1 の待ち受けを開始する。facility_1 のロックが取得出来たら facility_2 の待ち受けを開始する。同様に facility_i (1 \le i \le n-1) のロックが取得出来たら、facility_{i+1} の待ち受けを開始する。facility_n のロックが取得出来るまで、プロセスの実行を停止する。優先度は priority、ガード名は name となる。canceled には 1 引数の関数、あるいは、None を指定する。None でない場合、複合待ち受けにおいて、この待ち受け操作が完了した後にその待ち受けパスがキャンセル(2.9.4 章)された場合、待ち受け結果を引数として canceled ハンドラが呼ばれる。
結合優先度は Python の演算子の優先度に従う。つまり、優先度の高い順に、>>, &, | になる。例えば、a, b, c, d, e はファシリティとすると、
は、
と解釈される。
複合ファシリティのロックを取得した場合、解放忘れがあると、永久にファシリティを占有してしまうので注意が必要である。必ず 2.22.7 章 の方法で全てのファシリティを解放する必要がある。
あるいは、ファシリティの取得の canceled ハンドラに releaseIfRequested (2.5.5 章) を指定しておく事も出来る。
複数のタンクオブジェクトを組み合わせて、複合タンクオブジェクトを作る事が出来る。また、複合タンクオブジェクトに対して、待ち受けを実行する事が出来る。
タンクオブジェクトtank_1 とタンクオブジェクト tank_2 の OR 複合タンクオブジェクトを作成する。
tank_1 と tank_2 の OR 複合タンクオブジェクトを待ち受けるガード式である。tank_1 と tank_2 のどちらかから取得出来るまで、プロセスの実行を停止する。指定した val を複数のタンクに分散して成立する事はなく、あるタンクに対してのみ成立する。優先度は priority、ガード名は name となる。canceled には 1 引数の関数、あるいは、None を指定する。None でない場合、複合待ち受けにおいて、この待ち受け操作が完了した後にその待ち受けパスがキャンセル(2.9.4 章)された場合、待ち受け結果を引数として canceled ハンドラが呼ばれる。
tank_1 と tank_2 の OR 複合タンクオブジェクトを待ち受けるガード式である。tank_1 と tank_2 のどちらかへ追加出来るまで、プロセスの実行を停止する。指定した val を複数のタンクに分散して成立する事はなく、あるタンクに対してのみ成立する。優先度は priority、ガード名は name となる。canceled には 1 引数の関数、あるいは、None を指定する。None でない場合、複合待ち受けにおいて、この待ち受け操作が完了した後にその待ち受けパスがキャンセル(2.9.4 章)された場合、待ち受け結果を引数として canceled ハンドラが呼ばれる。
タンクオブジェクト tank_1 からタンクオブジェクト tank_n の OR 複合タンクオブジェクトを作成する。
tank_1 から tank_n の OR 複合タンクオブジェクトを待ち受けるガード式である。ある tank_i (1 \le i \le n) から取得出来るまで、プロセスの実行を停止する。指定した val を複数のタンクに分散して成立する事はなく、あるタンクに対してのみ成立する。優先度は priority、ガード名は name となる。canceled には 1 引数の関数、あるいは、None を指定する。None でない場合、複合待ち受けにおいて、この待ち受け操作が完了した後にその待ち受けパスがキャンセル(2.9.4 章)された場合、待ち受け結果を引数として canceled ハンドラが呼ばれる。
tank_1 から tank_n の OR 複合タンクオブジェクトを待ち受けるガード式である。ある tank_i (1 \le i \le n) へ追加出来るまで、プロセスの実行を停止する。指定した val を複数のタンクに分散して成立する事はなく、あるタンクに対してのみ成立する。優先度は priority、ガード名は name となる。canceled には 1 引数の関数、あるいは、None を指定する。None でない場合、複合待ち受けにおいて、この待ち受け操作が完了した後にその待ち受けパスがキャンセル(2.9.4 章)された場合、待ち受け結果を引数として canceled ハンドラが呼ばれる。
タンクオブジェクト tank_1 とタンクオブジェクト tank_2 の AND 複合タンクオブジェクトを作成する。
tank_1 と tank_2 の AND 複合タンクオブジェクトを待ち受けるガード式である。tank_1 と tank_2 の両方から取得出来るまで、プロセスの実行を停止する。指定した val を複数のタンクに分散して成立する事はなく、全てのタンクに対して成立する。優先度は priority、ガード名は name となる。canceled には 1 引数の関数、あるいは、None を指定する。None でない場合、複合待ち受けにおいて、この待ち受け操作が完了した後にその待ち受けパスがキャンセル(2.9.4 章)された場合、待ち受け結果を引数として canceled ハンドラが呼ばれる。
tank_1 と tank_2 の AND 複合タンクオブジェクトを待ち受けるガード式である。tank_1 と tank_2 の両方へ追加出来るまで、プロセスの実行を停止する。指定した val を複数のタンクに分散して成立する事はなく、全てのタンクに対して成立する。優先度は priority、ガード名は name となる。canceled には 1 引数の関数、あるいは、None を指定する。None でない場合、複合待ち受けにおいて、この待ち受け操作が完了した後にその待ち受けパスがキャンセル(2.9.4 章)された場合、待ち受け結果を引数として canceled ハンドラが呼ばれる。
タンクオブジェクト tank_1 からタンクオブジェクト tank_n の AND 複合タンクオブジェクトを作成する。
tank_1 から tank_n の AND 複合タンクオブジェクトを待ち受けるガード式である。全てのtank_i (1 \le i \le n) から取得出来るまで、プロセスの実行を停止する。指定した val を複数のタンクに分散して成立する事はなく、全てのタンクに対して成立する。優先度は priority、ガード名は name となる。canceled には 1 引数の関数、あるいは、None を指定する。None でない場合、複合待ち受けにおいて、この待ち受け操作が完了した後にその待ち受けパスがキャンセル(2.9.4 章)された場合、待ち受け結果を引数として canceled ハンドラが呼ばれる。
tank_1 から tank_n の AND 複合タンクオブジェクトを待ち受けるガード式である。全てのtank_i (1 \le i \le n) へ追加出来るまで、プロセスの実行を停止する。指定した val を複数のタンクに分散して成立する事はなく、全てのタンクに対して成立する。優先度は priority、ガード名は name となる。canceled には 1 引数の関数、あるいは、None を指定する。None でない場合、複合待ち受けにおいて、この待ち受け操作が完了した後にその待ち受けパスがキャンセル(2.9.4 章)された場合、待ち受け結果を引数として canceled ハンドラが呼ばれる。
タンクオブジェクト tank_1 とタンクオブジェクト tank_2 の逐次複合タンクオブジェクトを作成する。
tank_1 と tank_1 の逐次複合タンクオブジェクトを待ち受けるガード式である。まず tank_1 の待ち受けを開始する。tank_1 から取得出来たら tank_2 の待ち受けを開始し、tank_2 から取得出来るまで、プロセスの実行を停止する。優先度は priority、ガード名は name となる。canceled には 1 引数の関数、あるいは、None を指定する。None でない場合、複合待ち受けにおいて、この待ち受け操作が完了した後にその待ち受けパスがキャンセル(2.9.4 章)された場合、待ち受け結果を引数として canceled ハンドラが呼ばれる。
tank_1 と tank_1 の逐次複合タンクオブジェクトを待ち受けるガード式である。まず tank_1 の待ち受けを開始する。tank_1 へ追加出来たら tank_2 の待ち受けを開始し、tank_2 へ追加出来るまで、プロセスの実行を停止する。優先度は priority、ガード名は name となる。canceled には 1 引数の関数、あるいは、None を指定する。None でない場合、複合待ち受けにおいて、この待ち受け操作が完了した後にその待ち受けパスがキャンセル(2.9.4 章)された場合、待ち受け結果を引数として canceled ハンドラが呼ばれる。
タンクオブジェクト tank_1 からタンクオブジェクト tank_n の逐次複合タンクオブジェクトを作成する。
tank_1 から tank_n の逐次複合タンクを待ち受けるガード式である。まず tank_1 の待ち受けを開始する。tank_1 から取得出来たら tank_2 の待ち受けを開始する。同様に tank_i (1 \le i \le n-1) から取得出来たら、tank_{i+1} の待ち受けを開始する。tank_n から取得出来るまで、プロセスの実行を停止する。優先度は priority、ガード名は name となる。canceled には 1 引数の関数、あるいは、None を指定する。None でない場合、複合待ち受けにおいて、この待ち受け操作が完了した後にその待ち受けパスがキャンセル(2.9.4 章)された場合、待ち受け結果を引数として canceled ハンドラが呼ばれる。
tank_1 から tank_n の逐次複合タンクを待ち受けるガード式である。まず tank_1 の待ち受けを開始する。tank_1 へ追加出来たら tank_2 の待ち受けを開始する。同様に tank_i (1 \le i \le n-1) へ追加出来たら、tank_{i+1} の待ち受けを開始する。tank_n へ追加出来るまで、プロセスの実行を停止する。優先度は priority、ガード名は name となる。canceled には 1 引数の関数、あるいは、None を指定する。None でない場合、複合待ち受けにおいて、この待ち受け操作が完了した後にその待ち受けパスがキャンセル(2.9.4 章)された場合、待ち受け結果を引数として canceled ハンドラが呼ばれる。
結合優先度は Python の演算子の優先度に従う。つまり、優先度の高い順に、>>, &, | になる。例えば、a, b, c, d, e はタンクとすると、
は、
と解釈される。
複数のストアオブジェクトを組み合わせて、複合ストアオブジェクトを作る事が出来る。また、複合ストアオブジェクトに対して、待ち受けを実行する事が出来る。
ストアオブジェクトstore_1 とストアオブジェクト store_2 の OR 複合ストアオブジェクトを作成する。
store_1 と store_2 の OR 複合ストアオブジェクトを待ち受けるガード式である。store_1 と store_2 のどちらかから取得出来るまで、プロセスの実行を停止する。指定した n を複数のストアに分散して成立する事はなく、あるストアのみに対してのみ成立する。優先度は priority、ガード名は name となる。canceled には 1 引数の関数、あるいは、None を指定する。None でない場合、複合待ち受けにおいて、この待ち受け操作が完了した後にその待ち受けパスがキャンセル(2.9.4 章)された場合、待ち受け結果を引数として canceled ハンドラが呼ばれる。
store_1 と store_2 の OR 複合ストアオブジェクトを待ち受けるガード式である。store_1 と store_2 のどちらかから取得出来るまで、プロセスの実行を停止する。優先度は priority、ガード名は name となる。canceled には 1 引数の関数、あるいは、None を指定する。None でない場合、複合待ち受けにおいて、この待ち受け操作が完了した後にその待ち受けパスがキャンセル(2.9.4 章)された場合、待ち受け結果を引数として canceled ハンドラが呼ばれる。
store_1 と store_2 の OR 複合ストアオブジェクトを待ち受けるガード式である。store_1 と store_2 のどちらかへ追加出来るまで、プロセスの実行を停止する。指定した buffer を複数のストアに分散して成立する事はなく、あるストアのみに対してのみ成立する。優先度は priority、ガード名は name となる。canceled には 1 引数の関数、あるいは、None を指定する。None でない場合、複合待ち受けにおいて、この待ち受け操作が完了した後にその待ち受けパスがキャンセル(2.9.4 章)された場合、待ち受け結果を引数として canceled ハンドラが呼ばれる。
ストアオブジェクト store_1 からストアオブジェクト store_n の OR 複合ストアオブジェクトを作成する。
store_1 から store_n の OR 複合ストアオブジェクトを待ち受けるガード式である。ある store_i (1 \le i \le n) から取得出来るまで、プロセスの実行を停止する。指定した n を複数のストアに分散して成立する事はなく、あるストアのみに対してのみ成立する。優先度は priority、ガード名は name となる。canceled には 1 引数の関数、あるいは、None を指定する。None でない場合、複合待ち受けにおいて、この待ち受け操作が完了した後にその待ち受けパスがキャンセル(2.9.4 章)された場合、待ち受け結果を引数として canceled ハンドラが呼ばれる。
store_1 から store_n の OR 複合ストアオブジェクトを待ち受けるガード式である。ある store_i (1 \le i \le n) から取得出来るまで、プロセスの実行を停止する。優先度は priority、ガード名は name となる。canceled には 1 引数の関数、あるいは、None を指定する。None でない場合、複合待ち受けにおいて、この待ち受け操作が完了した後にその待ち受けパスがキャンセル(2.9.4 章)された場合、待ち受け結果を引数として canceled ハンドラが呼ばれる。
store_1 から store_n の OR 複合ストアオブジェクトを待ち受けるガード式である。ある store_i (1 \le i \le n) へ追加出来るまで、プロセスの実行を停止する。指定した buffer を複数のストアに分散して成立する事はなく、あるストアのみに対してのみ成立する。優先度は priority、ガード名は name となる。canceled には 1 引数の関数、あるいは、None を指定する。None でない場合、複合待ち受けにおいて、この待ち受け操作が完了した後にその待ち受けパスがキャンセル(2.9.4 章)された場合、待ち受け結果を引数として canceled ハンドラが呼ばれる。
ストアオブジェクト store_1 とストアオブジェクト store_2 の AND 複合ストアオブジェクトを作成する。
store_1 と store_2 の AND 複合ストアオブジェクトを待ち受けるガード式である。store_1 と store_2 の両方から取得出来るまで、プロセスの実行を停止する。指定した n を複数のストアに分散して成立する事はなく、全てのストアのみに対してのみ成立する。優先度は priority、ガード名は name となる。canceled には 1 引数の関数、あるいは、None を指定する。None でない場合、複合待ち受けにおいて、この待ち受け操作が完了した後にその待ち受けパスがキャンセル(2.9.4 章)された場合、待ち受け結果を引数として canceled ハンドラが呼ばれる。
store_1 と store_2 の AND 複合ストアオブジェクトを待ち受けるガード式である。store_1 と store_2 の両方から取得出来るまで、プロセスの実行を停止する。優先度は priority、ガード名は name となる。canceled には 1 引数の関数、あるいは、None を指定する。None でない場合、複合待ち受けにおいて、この待ち受け操作が完了した後にその待ち受けパスがキャンセル(2.9.4 章)された場合、待ち受け結果を引数として canceled ハンドラが呼ばれる。
store_1 と store_2 の AND 複合ストアオブジェクトを待ち受けるガード式である。store_1 と store_2 の両方へ追加出来るまで、プロセスの実行を停止する。指定した buffer を複数のストアに分散して成立する事はなく、全てのストアのみに対してのみ成立する。優先度は priority、ガード名は name となる。canceled には 1 引数の関数、あるいは、None を指定する。None でない場合、複合待ち受けにおいて、この待ち受け操作が完了した後にその待ち受けパスがキャンセル(2.9.4 章)された場合、待ち受け結果を引数として canceled ハンドラが呼ばれる。
ストアオブジェクト store_1 からストアオブジェクト store_n の AND 複合ストアオブジェクトを作成する。
store_1 から store_n の AND 複合ストアオブジェクトを待ち受けるガード式である。全てのstore_i (1 \le i \le n) から取得出来るまで、プロセスの実行を停止する。指定した n を複数のストアに分散して成立する事はなく、全てのストアのみに対してのみ成立する。優先度は priority、ガード名は name となる。canceled には 1 引数の関数、あるいは、None を指定する。None でない場合、複合待ち受けにおいて、この待ち受け操作が完了した後にその待ち受けパスがキャンセル(2.9.4 章)された場合、待ち受け結果を引数として canceled ハンドラが呼ばれる。
store_1 から store_n の AND 複合ストアオブジェクトを待ち受けるガード式である。全てのstore_i (1 \le i \le n) から取得出来るまで、プロセスの実行を停止する。優先度は priority、ガード名は name となる。canceled には 1 引数の関数、あるいは、None を指定する。None でない場合、複合待ち受けにおいて、この待ち受け操作が完了した後にその待ち受けパスがキャンセル(2.9.4 章)された場合、待ち受け結果を引数として canceled ハンドラが呼ばれる。
store_1 から store_n の AND 複合ストアオブジェクトを待ち受けるガード式である。全てのstore_i (1 \le i \le n) へ追加出来るまで、プロセスの実行を停止する。指定した buffer を複数のストアに分散して成立する事はなく、全てのストアのみに対してのみ成立する。優先度は priority、ガード名は name となる。canceled には 1 引数の関数、あるいは、None を指定する。None でない場合、複合待ち受けにおいて、この待ち受け操作が完了した後にその待ち受けパスがキャンセル(2.9.4 章)された場合、待ち受け結果を引数として canceled ハンドラが呼ばれる。
ストアオブジェクト store_1 とストアオブジェクト store_2 の逐次複合ストアオブジェクトを作成する。
store_1 と store_1 の逐次複合ストアオブジェクトを待ち受けるガード式である。まず store_1 の待ち受けを開始する。store_1 から取得出来たら store_2 の待ち受けを開始し、store_2 から取得出来るまで、プロセスの実行を停止する。優先度は priority、ガード名は name となる。canceled には 1 引数の関数、あるいは、None を指定する。None でない場合、複合待ち受けにおいて、この待ち受け操作が完了した後にその待ち受けパスがキャンセル(2.9.4 章)された場合、待ち受け結果を引数として canceled ハンドラが呼ばれる。
store_1 と store_1 の逐次複合ストアオブジェクトを待ち受けるガード式である。まず store_1 の待ち受けを開始する。store_1 から取得出来たら store_2 の待ち受けを開始し、store_2 から取得出来るまで、プロセスの実行を停止する。優先度は priority、ガード名は name となる。canceled には 1 引数の関数、あるいは、None を指定する。None でない場合、複合待ち受けにおいて、この待ち受け操作が完了した後にその待ち受けパスがキャンセル(2.9.4 章)された場合、待ち受け結果を引数として canceled ハンドラが呼ばれる。
store_1 と store_1 の逐次複合ストアオブジェクトを待ち受けるガード式である。まず store_1 の待ち受けを開始する。store_1 へ追加出来たら store_2 の待ち受けを開始し、store_2 へ追加出来るまで、プロセスの実行を停止する。優先度は priority、ガード名は name となる。canceled には 1 引数の関数、あるいは、None を指定する。None でない場合、複合待ち受けにおいて、この待ち受け操作が完了した後にその待ち受けパスがキャンセル(2.9.4 章)された場合、待ち受け結果を引数として canceled ハンドラが呼ばれる。
ストアオブジェクト store_1 からストアオブジェクト store_n の逐次複合ストアオブジェクトを作成する。
store_1 から store_n の逐次複合ストアを待ち受けるガード式である。まず store_1 の待ち受けを開始する。store_1 から取得出来たら store_2 の待ち受けを開始する。同様に store_i (1 \le i \le n-1) から取得出来たら、store_{i+1} の待ち受けを開始する。store_n が取得出来るまで、プロセスの実行を停止する。優先度は priority、ガード名は name となる。canceled には 1 引数の関数、あるいは、None を指定する。None でない場合、複合待ち受けにおいて、この待ち受け操作が完了した後にその待ち受けパスがキャンセル(2.9.4 章)された場合、待ち受け結果を引数として canceled ハンドラが呼ばれる。
store_1 から store_n の逐次複合ストアを待ち受けるガード式である。まず store_1 の待ち受けを開始する。store_1 から取得出来たら store_2 の待ち受けを開始する。同様に store_i (1 \le i \le n-1) から取得出来たら、store_{i+1} の待ち受けを開始する。store_n が取得出来るまで、プロセスの実行を停止する。優先度は priority、ガード名は name となる。canceled には 1 引数の関数、あるいは、None を指定する。None でない場合、複合待ち受けにおいて、この待ち受け操作が完了した後にその待ち受けパスがキャンセル(2.9.4 章)された場合、待ち受け結果を引数として canceled ハンドラが呼ばれる。
store_1 から store_n の逐次複合ストアを待ち受けるガード式である。まず store_1 の待ち受けを開始する。store_1 へ追加出来たら store_2 の待ち受けを開始する。同様に store_i (1 \le i \le n-1) へ追加出来たら、store_{i+1} の待ち受けを開始する。store_n へ追加出来るまで、プロセスの実行を停止する。優先度は priority、ガード名は name となる。
結合優先度は Python の演算子の優先度に従う。つまり、優先度の高い順に、>>, &, | になる。例えば、a, b, c, d, e はストアとすると、
は、
と解釈される。
ここで言う連続シミュレーションとは、常微分方程式(ODE, Ordinary Differential Equation)の初期値問題(IVP, Initial Value Problem)の数値解法の事を指し、時間 t_0 で、y が y_0 であった場合に、y = y(t) \quad (t_0 \le t \le T) の近似解を求める問題である。
\begin{aligned} \frac{dy}{dt} &= f(t, y) \quad (t_0 \le t \le T) \nonumber \\ y(t_0) &= y_0 \nonumber \end{aligned}
k 階の常微分方程式は以下のように表される。
\begin{aligned} y^{(k)} &= f(t, y, y', y'', \cdots, y^{(k-1)}) \nonumber \\ y(t_0) &= y_0 \nonumber \\ y'(t_0) &= y'_0 \nonumber \\ y''(t_0) &= y''_0 \nonumber \\ \vdots &= \vdots \nonumber \\ y^{(k-1)}(t_0) &= y^{(k-1)}_0 \nonumber \end{aligned}
ここで、y = y^0, y' = y^1, \cdots, y^{(k-1)}=y^{k-1} と置けば、次のような1階常微分方程式に変換する事が出来る。
\begin{aligned} (y^{kー1})' &= f(t, y^0, y^1, y^2, \cdots, y^{k-1}) \nonumber \\ (y^{kー2})' &= y^{k-1} \nonumber \\ \vdots &= \vdots \nonumber \\ (y^1)' &= y^2 \nonumber \\ (y^0)' &= y^1 \nonumber \end{aligned}
連続シミュレーションの実行(2.14.3 章)では、1階常微分方程式のみを指定可能なので、高階常微分方程式の場合はこのような変換を手動で行う必要がある。
初期値が buf で、最小値が lowerで、最大値が upper で、名前が name の連続変数オブジェクトを作成する。最小値が None の場合は最小値は設定されない。最大値が None の場合は最大値は設定されない。monitor が真の場合は、変数値の時系列変化を時系列モニターに記録する。localid が None の場合、この連続変数はグローバル変数扱いになり、localid が None でなかった場合、この連続変数はローカル変数扱いになる。ローカル変数は、continuous 待ち受けで特殊な処理が行われる。ローカル変数の場合、item 引数にフローアイテムを設定する事で、そのローカル変数にフローアイテムを結びつける事が出来る。
名前が name の補助変数オブジェクトを作成する。補助変数とは、複数の連続変数の関数として表現される変数である。args には、補助変数が参照する連続変数のリストを指定する。expr はスカラー値を返す関数であり、第1引数は、必ずシミュレーション時間を指す。第2引数以降は、args で指定した連続変数オブジェクトの値が渡される。つまり引数の数は、1 + len(args) となる。monitor が真の場合は、変数値の時系列変化を時系列モニターに記録する。
a = Value(3.0, name = "a")
b = Value(4.0, name = "b")
c = Value(5.0, name = "c")
e = Expression([a, b, c],
lambda t, a, b, c: a + b * c,
name = "e")
import math
def calc(t, a, b, c):
return math.sin(a) + math.exp(b) * c
a = Value(3.0, name = "a")
b = Value(4.0, name = "b")
c = Value(5.0, name = "c")
e = Expression([a, b, c],
calc,
name = "e")
連続シミュレーションを行うガード式である。vars には更新する連続変数のリストを指定する。args には参照する連続変数あるいは補助変数のリストを指定する。f には、vars の各変数の導関数を指定する。第1引数は、必ずシミュレーション時間を指す。第2引数以降には、vars で指定した連続変数の値、続いて、args で指定した連続変数あるいは補助変数の値が続く。ただし、i 番目の連続変数 vars[i] がローカル変数であった場合、同一の localid であるローカル変数値からなるリストが渡され、それに次いで、そのローカル変数のそのリスト上でのインデックス番号が渡される。つまり引数の数は、ローカル変数の個数を len(localvars) とすると、1 + len(vars) + len(localvars) + len(args) となる。返り値は、要素数が len(vars) 個のリストであり、それぞれが、vars の各変数の微係数である。vars で指定した変数のうちひとつでも、上下限に逹した場合は、その時点で連続シミュレーションを停止する。ガード名は、name となる。発火値として、連続シミュレーション結果オブジェクトを返す。f に渡されるローカル変数は、同一の localid であるローカル変数値からなるリストであるが、「ローカル変数.items」は特殊なリストを返し、各ローカル変数に割当てられているフローアイテムのリストである。
以下のような 3 変数の連立常微分方程式を考える。(伝染病のモデルとして有名な SIR モデル)
\begin{aligned} \frac{dS}{dt} &= -\beta S I \nonumber \\ \frac{dI}{dt} &= \beta S I - \gamma I \nonumber \\ \frac{dR}{dt} &= \gamma I \nonumber \end{aligned}
それぞれの、時間 0 における値を以下とする。
\begin{aligned} S(0) &= 999 \nonumber \\ I(0) &= 1 \nonumber \\ R(0) &= 0 \nonumber \end{aligned}
このような微分方程式をシミュレーションするコードは以下のように表現する事が出来る。
S = Value(999, name = "S", monitor = True)
I = Value(1, name = "I", monitor = True)
R = Value(0, name = "R", monitor = True)
def proc():
beta = 0.001
gamma = 0.2
yield continuous([S, I, R],
[],
lambda T, S, I, R: (
-beta * S * I,
beta * S * I - gamma * I,
gamma * I))
activate(proc)()
start()
次に、タンカーモデルを考える。石油タンクが平均10の指数分布間隔で港に到着し、それぞれタンカーには固有のタンク容量と、注入速度が与えられている。港には石油タンクがあり、タンカーが到着すると、石油を与えられている注入速度で注入する。このようなモデルは以下のように記述する事が出来る。
initialize()
tank = Value(0.0, lower = 0.0, monitor = True)
class Tanker:
def __init__(self):
self.capacity = next(exponentialDistribution(
mean = 10.0))
self.velocity = next(exponentialDistribution(
mean = 1.0))
def tanker():
gen = exponentialDistribution(mean = 10.0)
while True:
yield pause(next(gen))
yield subactivate(putting)(Tanker())
def putting(tanker):
localtank = Value(tanker.capacity,
lower = 0.0,
upper = tanker.capacity)
yield continuous([tank, localtank],
[],
lambda t, tank, locaktank: (
tanker.velocity,
-tanker.velocity))
activate(tanker)()
start(until = 100)
この例では、動的に作成される一時的な変数 localtank が出現している。しかしながら、ローカル変数としては定義していない。
次に、基本的には前述のモデルと同様だが、港の石油タンクに注入する速度には上限があり、上限を越えた場合は、各注入速度が按分されるようなモデルを考える。そのようなモデルは以下のように、ローカル変数を使う事で容易に記述する事が出来る。
initialize()
setGlobalSeed(0)
tank = Value(0.0, lower = 0.0, monitor = True)
class Tanker:
def __init__(self):
self.capacity = next(exponentialDistribution(
mean = 10.0))
self.velocity = next(exponentialDistribution(
mean = 1.0))
def tanker():
gen = exponentialDistribution(mean = 10.0)
while True:
yield pause(next(gen))
yield subactivate(putting)(Tanker())
def putting(tanker):
localtank = Value(tanker.capacity,
lower = 0.0,
upper = tanker.capacity,
localid = "localtank",
item = tanker)
def calc(t, tank, localtank, i):
maxv = 2.0
s = sum([item.velocity for item in localtank.items])
if s >= maxv:
return (tanker.velocity * maxv / s,
-tanker.velocity * maxv / s)
else:
return (tanker.velocity,
-tanker.velocity)
yield continuous([tank, localtank],
[],
calc)
activate(tanker)()
start(until = 100)
この例では、localtank は、ローカル変数と定義している。そのため、calc の第3引数 localtank は、その時点で注入している全てのタンカーの石油残量のリストを示しており、その中の i 番目の値が、そのタンカーの石油残量を示している。localtank.items は、個々のタンカーの特性を示す Tanker オブジェクトのリストを示している。つまり、[item.velocity for item in localtank.items] は注入速度のリストを示し、sum([item.velocity for item in localtank.items])は、注入速度の合計値を示す。
連続シミュレーション中の状態を待ち受けるガード式である。args には参照する連続変数あるいは補助変数のリストを指定する。until には、スカラー値を返す関数を指定する。この関数値が正になると、このガード式は発火する。until の第1引数は、必ずシミュレーション時間を指す。第2引数以降には、args で指定した連続変数を指定する。ただし、i 番目の連続変数 vargs[i] がローカル変数であった場合、同一の localid であるローカル変数値からなるリストが渡され、それに次いで、そのローカル変数のそのリスト上でのインデックス番号が渡される。つまり引数の数は、ローカル変数の個数を len(localargs) とすると、1 + len(args) + len(localargs) となる。ガード名は、name となる。
S = Value(999, name = "S", monitor = True)
I = Value(1, name = "I", monitor = True)
R = Value(0, name = "R", monitor = True)
def proc():
beta = 0.001
gamma = 0.2
yield (continuous([S, I, R],
[],
lambda T, S, I, R: (
-beta * S * I,
beta * S * I - gamma * I,
gamma * I)) |
continuousWait([I, R],
lambda T, I, R: I + R - v))
activate(proc)()
start()
連続変数 value が上限に逹した為に、連続シミュレーションが停止した場合に真となる。
連続変数 value が下限に逹した為に、連続シミュレーションが停止した場合に真となる。
連続変数オブジェクトの時系列変化を記録した時系列モニターを返す。連続変数オブジェクトで時系列モニターを記録した場合のみ、参照可能となる。列数は 1 であり、連続変数値を示す。
補助変数オブジェクトの時系列変化を記録した時系列モニターを返す。補助変数オブジェクトで時系列モニターを記録した場合のみ、参照可能となる。列数は 1 であり、補助変数値を示す。
常微分方程式(Ordinary Differential Equation, ODE) ソルバーとしては、以下が用意されている。これらは、2.1.3 章の start (シミュレーションの開始 API) の odesolver 引数に指定する事が出来る。
Dormand-Prince の5(4) 次の陽的 Runge-Kutta 法によるソルバー。dt は時間刻み幅。rtol は相対許容誤差。atol は絶対許容誤差。
Dormand-Prince の 8(5,3) 次の陽的 Runge-Kutta 法によるソルバー。dt は時間刻み幅。rtol は相対許容誤差。atol は絶対許容誤差。
Adams 法によるソルバー(non-stiff な問題用)。dt は時間刻み幅。rtol は相対許容誤差。atol は絶対許容誤差。
後退差分法(BDF) 法によるソルバー(stiff な問題用)。dt は時間刻み幅。rtol は相対許容誤差。atol は絶対許容誤差。
常に成立するガード式である。
常に成立しないガード式である。
条件式 cond を評価し、真なら成立し、偽なら成立しないガード式である。評価は待ち受け依頼時に一度だけ行われる。評価後に、条件が変わっても発火する事はない。もし、待ち受け依頼時と、待ち受け実行時で条件の真偽が変わる可能性がある場合は、2.15.4 章 章のガード式を利用する。
判定関数 condFunc を評価し、真なら成立し、偽なら成立しないガード式である。判定関数の評価は待ち受け実行時に一度だけ行われる。評価後に、条件が変わっても発火する事はない。待ち受け依頼時と、待ち受け実行時で条件の真偽が変わる可能性がない場合は、2.15.3 章のガード式を利用する事も出来る。
プロセスの状態には、活性状態(active)、一時停止状態(suspended)、終了状態(terminated) がある。活性状態のサブ状態として、実行待ち状態(waiting)、実行状態(running) がある。実行待ち状態とは、まだプロセスの起動条件を満たしていない状態であり、起動条件を満たすと自動的に実行状態に遷移する。
プロセスの状態によって、終了(terminate)、一時停止(suspend)、再開(resume)する事が出来る。定義されていない遷移はエラーとなる。
プロセスの終了とは、そのプロセスが実行している全ての待ち受けが削除され、また、そのプロセスに登録されている全てのハンドラが削除される。サブプロセスも終了する。終了したプロセスは再開する事は出来ない。
プロセスの一時停止とは、そのプロセスが実行している全ての待ち受けが一時停止し、また、そのプロセスに登録されている全てのハンドラも一時停止する。サブプロセスも一時停止する。
プロセスの再開とは、一時停止しているプロセスの一時停止状態の全ての待ち受けが再開し、また、一時停止しているプロセスの一時停止状態の全てのハンドラが再開する。サブプロセスも再開する。実行待ち状態で、一時停止していた場合は、再開すると、実行待ち状態に戻る。実行状態で、一時停止していた場合は、再開すると、実行状態に戻る。
プロセスの継続オブジェクト cont が実行待ち状態かどうかを調べる。
プロセスの継続オブジェクト cont が実行状態かどうかを調べる。
プロセスの継続オブジェクト cont が活性状態かどうかを調べる。
プロセスの継続オブジェクト cont が一時停止状態かどうかを調べる。
プロセスの継続オブジェクト cont が終了状態かどうかを調べる。
プロセスの継続オブジェクト cont の終了を待ち受けるガード式である。対象プロセスが終了状態以外から終了状態に遷移した時に成立する。待ち受け開始時に終了状態であった場合は成立しない。外部プロセスが cont.terminate(val) を実行して終了した場合は、発火値は val となる。ただし、自プロセスの終了を待ち受ける事は出来ない。自プロセスの終了を待ち受けるには、2.16.10 章章のハンドラ登録を利用する。
プロセスの継続オブジェクト cont の一時停止を待ち受けるガード式である。対象プロセスが一時停止状態以外から一時停止状態に遷移した時に成立する。待ち受け開始時に一時停止状態であった場合は成立しない。外部プロセスが cont.suspend(val) を実行して一時停止した場合は、発火値は val となる。ただし、自プロセスの一時停止を待ち受ける事は出来ない。自プロセスの一時停止を待ち受けるには、2.16.11 章章のハンドラ登録を利用する。
プロセスの継続オブジェクト cont の再開を待ち受けるガード式である。対象プロセスが活性状態以外から活性状態に遷移した時に成立する。待ち受け開始時に活性状態であった場合は成立しない。外部プロセスが cont.resume(val) を実行して再開した場合は、発火値は val となる。ただし、自プロセスの再開を待ち受ける事は出来ない。自プロセスの再開を待ち受けるには、2.16.12 章 章のハンドラ登録を利用する。
プロセスの継続オブジェクト cont を終了する。既に終了状態であった場合は何もしない。また、自プロセスを終了させる事は出来ない。自プロセスを終了するには、2.16.8 章章のガード式を利用する。終了する前に、発火値を val として、対象プロセスの終了ハンドラが実行され、対象プロセスの終了を待ち受けているガード式が発火する。
活性状態のプロセスの継続オブジェクト cont を一時停止する。既に一時停止状態であった場合は何もしない。また、自プロセスを一時停止させる事は出来ない。自プロセスを一時停止するには、2.16.9 章 章のガード式を利用する。一時停止する前に、発火値を val として、対象プロセスの一時停止ハンドラが実行され、対象プロセスの一時停止を待ち受けているガード式が発火する。
一時停止状態のプロセスの継続オブジェクト cont を再開する。既に活性状態であった場合は何もしない。再開止する前に、発火値を val として、対象プロセスの再開ハンドラが実行され、対象プロセスの再開を待ち受けているガード式が発火する。
現在実行中のプロセスを終了するガード式である。終了する前に、発火値を val として、対象プロセスの終了ハンドラが実行され、対象プロセスの終了を待ち受けているガード式が発火する。
現在実行中のプロセスを一時停止するガード式である。他プロセスが再開させるまでプロセスの実行を停止する。一時停止する前に、発火値を val として、対象プロセスの一時停止ハンドラが実行され、対象プロセスの一時停止を待ち受けているガード式が発火する。
プロセスの継続オブジェクト cont の終了ハンドラを設定する。プロセスが終了状態以外から終了状態に遷移した時に handler が実行される。handler は 1 引数の関数で、プロセスが終了した時に、発火値の設定された単一の待ち受け結果を引数として呼出される。
プロセスの継続オブジェクト cont の一時停止ハンドラを登録する。プロセスが一時停止状態以外から一時停止状態に遷移した時に handler が実行される。handler は 1 引数の関数で、プロセスが一時停止した時に、発火値の設定された単一の待ち受け結果を引数として呼出される。
プロセスの継続オブジェクト cont の再開ハンドラを登録する。プロセスが活性状態以外から活性状態に遷移した時に handler が実行される。handler は 1 引数の関数で、プロセスが再開した時に、発火値の設定された単一の待ち受け結果を引数として呼出される。
自プロセスの継続オブジェクトを取得するガード式である。待ち受け結果は自プロセスの継続オブジェクトとなる。
以下のコードは同じ動作をする。
def handler(result):
print("terminated")
def proc():
cont = yield currentProc()
cont.setTerminatedHandler(handler)
yield pause(100)
activate(proc)()
start()
def handler(result):
print("terminated")
def proc():
yield pause(100)
activate(proc, terminatedHandler = handler)()
start()
def handler(result):
print("terminated")
def proc():
yield pause(100)
cont = activate(proc)()
cont.setTerminatedHandler(handler)
start()
initialize()
def printMessage(msg):
print(msg)
def terminatedHandler(result):
printMessage("terminated %s at %s" % (result.val, now()))
def suspendedHandler(result):
printMessage("suspended %s at %s" % (result.val, now()))
def resumedHandler(result):
printMessage("resumed %s at %s" % (result.val, now()))
def proc1():
yield pause(1000)
def proc2(p):
yield (p.terminated() >> runAction(printMessage)(
"terminated signal was observed by proc2") |
p.suspended() >> runAction(printMessage)(
"suspended signal was observed by proc2") |
p.resumed() >> runAction(printMessage)(
"resumed signal was observed by proc2"))
yield go(proc2)(p)
def proc3(p):
for i in range(3):
p.suspend("by proc3")
yield pause(3)
p.resume("by proc3")
yield pause(3)
p.terminate("by proc3")
p = activate(proc1)()
p.setTerminatedHandler(terminatedHandler)
p.setSuspendedHandler(suspendedHandler)
p.setResumedHandler(resumedHandler)
activate(proc2)(p)
activate(proc3)(p)
start()
サブプロセスとは、プロセス内から再帰的に呼び出すプロセスの事である。
サブプロセスは通常のプロセスと同様に定義する事が出来る。サブプロセスの実行を OR 複合待ち受けと併用して利用する場合で、サブプロセスの終了より先に、他の OR 複合待ち受けが成立した場合、サブプロセスの継続オブジェクトに対し、終了シグナルを送り、サブプロセスを呼出した親プロセスは継続の実行を進める。そのため、OR 複合待ち受けと併用して利用する場合、サブプロセスは終了される事を想定しておく必要がある。
def proc():
...
yield call(subProc)() | cancelEvet.wait()
...
def subProc()
for count in range(10):
yield pause(10)
yield event.wait()
print(count)
activate(proc)()
start()
サブプロセスを起動し、サブプロセスの完了を待ち受けるガード式である。シミュレーション時間 delay 後に、プロセス名 name のサブプロセス process を実行し、その完了を待ち受ける。delay が指定された時のみ、優先度 priority は有効となり、同時刻の起動優先度を示す。終了、一時停止、再開ハンドラをそれぞれ、terminatedHandler, suspendedHandler, resumedHandler で指定する事が出来る。各ハンドラは、1 引数の関数で、プロセス状態が変化した時に、発火値の設定された単一の待ち受け結果を引数として呼出される。ハンドラを明示的に指定しなかった場合は、空のハンドラが設定される。(*args,**keys) に書かれた引数は全て process に送られる。なお、引数が評価されるのは、待ち受け実行時ではなく、待ち受け依頼時である。サブプロセスは他のガード式と同様に、複合待ち受けの一部として指定された場合、並行に待ち受けを行う。
サブプロセスを起動するガード式である。このガード式自体は即座に成立する。起動遅延時間 delay とガード式 cond はオプショナルであるが、両方を指定した場合はエラーとなる。delay が指定された場合は、起動を指定時間遅らせる。cond が指定された場合、まず cond の成立を待ち受ける。何れも指定されなかった場合は、起動前の待ち受けは行われない。起動条件成立後、プロセス名 name のサブプロセス process を実行する。delay が指定された時のみ、優先度 priority は有効となり、同時刻の起動優先度を示す。終了、一時停止、再開ハンドラをそれぞれ、terminatedHandler,suspendedHandler, resumedHandler で指定する事が出来る。各ハンドラは、1 引数の関数で、プロセス状態が変化した時に、発火値の設定された単一の待ち受け結果を引数として呼出される。ハンドラを明示的に指定しなかった場合は、空のハンドラが設定される。(*args, **keys) に書かれた引数は全て process に送られる。なお、引数が評価されるのは、待ち受け実行時ではなく、待ち受け依頼時である。待ち受け結果はサブプロセスの継続オブジェクトである。サブプロセスを実行したプロセスが終了したら、サブプロセスも終了する。
単一の call 待ち受けを実行した場合、サブプロセスが完了するまで、親プロセスの実行が停止する。
複合待ち受けの一部に call 待ち受けが含まれていた場合、他の待ち受けと同様に、並行観測を行う。つまり、複数の call 待ち受けが、ガード式に含まれていた場合、一時的に複数のサブプロセスが起動する事になる。
複数の call を OR 結合した場合、複数のプロセスが起動する。それぞれのプロセスは独立に処理を進めるが、あるプロセスが終了したタイミングで、ガード式は成立し、他のプロセスには終了シグナルが送られる。
複数の call を AND 結合した場合、複数のプロセスが起動する。それぞれのプロセスは独立に処理を進めるが、全てのプロセスが終了したタイミングで、ガード式は成立する。
複数の call を逐次結合した場合、順番にプロセスが起動する。全てのプロセスが終了したタイミングで、ガード式は成立する。
現在の実行中のプロセスを、指定されたプロセスに置き換えるガード式である。現在の実行中のプロセスは終了され、シミュレーション時間 delay 後に、サブプロセス process を実行する。ガード名は name となる。delay が指定された時のみ、優先度 priority は有効となり、同時刻の起動優先度を示す。go はスタックを消費しない。(*args, **keys) に書かれた引数は全て process に送られる。なお、引数が評価されるのは、待ち受け実行時ではなく、待ち受け依頼時である。ただし、移動するタイミングは、go が含まれるガード式全体が成立した時である。go は状態遷移を記述するために利用される。例えば、yield R1 >> go(p1)() | R2 >> go(p2)() とした場合、R1 が成立すれば p1 に遷移し、R2 が成立すれば p2 に遷移する。なお、yield R1 >> go(p1)() & R2 >> go(p2)() や yieldgo(p1) >> go(p2) はエラーとはならないが、go がガード式の末尾以外(2.18.5 章章参照) で利用された場合の動作は未定義である。go で遷移しても、直前の待ち受け結果(2.23 章章参照)は保存され、遷移先で、yield last() を実行すれば、go を含めた待ち受け結果が得られる。
以下のような例を考える。
例電話オペレーターは電話がなると応答する。応答には 3 分を要する。しかし応答中に何らかの緊急割り込み(上司からの要求かもしれないし、腹痛かもしれない)が発生する場合がある。すると、1 分間の処理時間を要する。処理が終わったら、残りの応答を行い、電話待ち状態に戻る。しかしながら、割り込み処理の最中に電話が切られてしまう可能性もある。その場合は、電話待ち状態に戻る。
この例の状態遷移図を書くと図のようになる。
それを状態遷移の実行 go を使って書くと以下のようになる。
ring = Event()
stop = Event()
emergency = Event()
class TelephoneOperator:
def wait(self):
print("state: wait at %d" % now())
yield ring.wait() >> go(self.answer)()
def answer(self):
print("state: answer at %d" % now())
start = now()
yield (pause(3) >> go(self.wait)() |
emergency.wait() >> go(self.work)(start))
def work(self, start):
print("state: work at %d" % now())
rest = 3 - (now() - start)
yield (stop.wait() >> go(self.wait)() |
pause(1) >> go(self.answerRest)(rest))
def answerRest(self, rest):
print("state: answerRest at %d" % now())
yield pause(rest) >> go(self.wait)()
def proc():
yield pause(1)
ring.signal()
yield pause(1)
emergency.signal()
operator = TelephoneOperator()
activate(operator.wait)()
activate(proc)()
start()
ただし、後述のサブ状態と絡むが、以下のように、状態遷移はプロセスメソッド内に内包してしまう記法を推奨する。self の記述を最低限に抑え、状態遷移のみに着目してモデリングする事が出来る。状態遷移内でのメンバー参照は、「self.メンバー名」で可能である。
class TelephoneOperator:
def office(self):
def wait():
print("state: wait at %d" % now())
yield ring.wait() >> go(answer)()
def answer():
print("state: answer at %d" % now())
start = now()
yield (pause(3) >> go(wait)() |
emergency.wait() >>
go(work)(start))
def work(start):
print("state: work at %d" % now())
rest = 3 - (now() - start)
yield (stop.wait() >> go(wait)() |
pause(1) >> go(answerRest)(rest))
def answerRest(rest):
print("state: answerRest at %d" % now())
yield pause(rest) >> go(wait)()
yield go(wait)()
ここで、先の電話オペレーターの状態の更に上位の状態として、出社状態、帰宅状態を考える。それぞれ 1000 分で状態が切り替わるとする。出社状態はコンポジット状態であり、その中には、先の状態遷移が内包されている。それらをサブ状態と呼ぶ。
このようなサブ状態を含む状態遷移は以下のようにして記述する事が出来る。
メインの状態として、office と home があり、相互に切り替わる。office 状態のサブ状態の起動には call を利用すれば良い。
class TelephoneOperator:
def start(self):
def office():
def wait():
print("state: office.wait at %d" % now())
yield ring.wait() >> go(answer)()
def answer():
print("state: office.answer at %d" % now())
start = now()
yield (pause(3) >> go(wait)() |
emergency.wait() >>
go(work)(start))
def work(start):
print("state: office.work at %d" % now())
rest = 3 - (now() - start)
yield (stop.wait() >> go(wait)() |
pause(1) >> go(answerRest)(rest))
def answerRest(rest):
print("state: office.answerRest at %d" %
now())
yield pause(rest) >> go(wait)()
print("state: office at %d" % now())
yield (call(wait)() |
pause(1000) >> go(home)())
def home():
print("state: home at %d" % now())
yield pause(1000) >> go(office)()
yield go(office)()
ここで、電話オペレーターの出社状態では、通常の業務を行うと共に、400 分単位で、スキルが向上するとする。このような並行して動作する状態遷移は並行状態と呼ぶ。
このような並行状態は以下のようにして記述する事が出来る。
通常の業務とスキル向上は並行して進むプロセスなので、call を使って、OR 並列プロセスとして起動すれば良い。(この例の場合、無限ループなので、AND 並列でも構わない)
class TelephoneOperator:
def start(self):
def office():
def wait():
print("state: office.wait at %d" % now())
yield ring.wait() >> go(answer)()
def answer():
print("state: office.answer at %d" % now())
start = now()
yield (pause(3) >> go(wait)() |
emergency.wait() >>
go(work)(start))
def work(start):
print("state: office.work at %d" % now())
rest = 3 - (now() - start)
yield (stop.wait() >> go(wait)() |
pause(1) >> go(answerRest)(rest))
def answerRest(rest):
print("state: office.answerRest at %d" %
now())
yield pause(rest) >> go(wait)()
def skillUp():
print("state: office.skillUp at %d" %
now())
yield pause(400) >> go(skillUp)()
print("state: office at %d" % now())
yield (call(wait)() |
call(skillUp)() |
pause(1000) >> go(home)())
def home():
print("state: home at %d" % now())
yield pause(1000) >> go(office)()
yield go(office)()
先の例と同じ例を考えるが、出社状態に戻った時は以前の業務の続きから行うとする。スキル向上も総業務時間で発生するとする。状態を抜ける時に履歴を残しておき、再度その状態に戻った時に、その履歴と同じ状態に復帰するというモデリングである。
このような並行状態は以下のようにして記述する事が出来る。
履歴を実現するには、go と call だけでは実現出来ない。履歴については、プロセスの suspend/resume を利用する事が出来る。
class TelephoneOperator:
def start(self):
def officeWork():
def wait():
print("state: office.wait at %d" % now())
yield ring.wait() >> go(answer)()
def answer():
print("state: office.answer at %d" % now())
start = now()
yield (pause(3) >> go(wait)() |
emergency.wait() >>
go(work)(start))
def work(start):
print("state: office.work at %d" % now())
rest = 3 - (now() - start)
yield (stop.wait() >> go(wait)() |
pause(1) >> go(answerRest)(rest))
def answerRest(rest):
print("state: office.answerRest at %d" %
now())
yield pause(rest) >> go(wait)()
def skillUp():
print("state: office.skillUp at %d" %
now())
yield pause(400) >> go(skillUp)()
yield (call(wait)() |
call(skillUp)())
def office():
print("state: office at %d" % now())
self.officeProc.resume()
yield pause(1000)
self.officeProc.suspend()
yield go(home)()
def home():
print("state: home at %d" % now())
yield (pause(1000) >> go(office)())
self.officeProc = activate(officeWork)()
yield go(office)()
ガード式 X がガード式 Y の末尾である事を \text{tail}(X, Y) と書くとすれば、以下のように定義される。
\begin{aligned} \text{tail}(W, W_1 \:\text{|}\: W_2) &= \text{tail}(W, W_1) \vee \text{tail}(W, W_2) \nonumber \\ \text{tail}(W, W_1 \:\text{\&}\: W_2) &= F \nonumber \\ \text{tail}(W, W_1 \:>>\: W_2) &= \text{tail}(W, W_2) \nonumber \\ \text{tail}(W, W) &= T \nonumber \\ \text{tail}(W, W') &= F \quad (W \neq W') \nonumber \end{aligned}
関数 action を実行するガード式である。action は、任意の関数である。単体で利用した場合、AND/OR 式の中に含めても即座に実行されるので、あまり意味がない。逐次待ち受けの場合に、独自の処理を挿入したい場合などに、利用出来る。(*args, **keys) に書かれた引数は全て action に送られる。なお、引数が評価されるのは、待ち受け実行時ではなく、待ち受け依頼時である。発火値はアクションの実行結果となる。
e1 = Event()
e2 = Event()
def action():
print("e1 fired")
def proc1():
...
yield sequenceOf(e1.wait(name = "e1"),
runAction(action)(),
e2.wait(name = "e2"))
...
def proc2():
...
e1.signal()
...
e2.signal()
...
値 value を発火値とするガード式である。このガード式自体は即座に発火する。
現在のシミュレーション時間を発火値とするガード式である。このガード式自体は即座に発火する。逐次待ち受けの一部で利用した場合、yield を実行した時刻ではなく、recordNow ガード式が実行された時刻が発火値となる。
指定したガード式のハンドラを登録する。この式自体もガード式であるが、即座に成立する。handler は 1 引数の関数で、ガード式が成立したら、待ち受け結果を引数として呼出される。ガード式が成立したら登録されたハンドラは除去される。また、addHandler を実行したプロセスが終了した時に、登録されたハンドラは除去される。発火値はハンドラオブジェクトであり、removeHandler で除去する事が出来る。
def handler(result):
if "e1" in result:
(e1 が発火)
else:
(e2 が発火)
e1 = Event()
e2 = Event()
def proc1():
...
yield addHandler(handler,
(e1.wait(name = "e1") |
e2.wait(name = "e2")))
...
def proc2():
...
e1.signal()
e2.signal()
...
指定したガード式のグローバルハンドラを登録する。addHandler とは違い、この式自体はガード式ではない。handler は 1 引数の関数で、ガード式が成立したら、待ち受け結果を引数として呼出される。ガード式が成立したら登録されたハンドラは除去される。addHandler と違い、addGlobalHandler を実行したプロセスが終了しても、登録されたハンドラは除去されない。返り値はハンドラオブジェクトであり、removeHandler で除去する事が出来る。
登録されたハンドラを除去する。
待ち受け結果は、
のようにして取得する事が出来る。
result は任意の変数であり、成立した待ち受けの結果が含まれている。
ガード式に OR 待ち受けが含まれていた場合、どちらの待ち受けが成立したのかを取得する事が出来る。ガード式にはガード名を指定出来るが、待ち受けの成立検査を行うには、必ずガード式にガード名を指定しておかなくてはならない。
待ち受け結果の中に、ガード名で示される待ち受けの結果が含まれていた場合に真を返す。そうでなければ偽を返す。
result = event.wait(name = "fired") | \
pause(100, name = "timeout")
if "fired" in result:
(event が発火)
else:
(timeout が発生)
イベントの発火で val を指定した場合や、ファシリティのロック取得で、個々の待ち受けの発火値を取得する事が出来る。ガード式にはガード名を指定出来るが、発火値の取得を行うには、必ずガード式にガード名を指定しておかなくてはならない。
待ち受け結果の中に、ガード名で示される待ち受けの結果が含まれていた場合、その発火値を返す。
event = Event()
def proc1():
result = event.wait(name = "fired")
print(result["fired"])
def proc2():
event.signal("fire")
def proc3():
result = yield facility.request(name = "request")
yield pause(100)
result["request"].release()
各ガード式の発火時間を得る事が出来る。ガード式にはガード名を指定出来るが、ガード式の発火時間を得るには、必ずガード式に待ち受け名を指定しておかなくてはならない。
待ち受け結果の中に、待ち受け名で示される待ち受けの結果が含まれていた場合、その待ち受けが成立したシミュレーション時間を返す。
待ち受けが複合待ち受けだった場合、ガード式の成立順番を得る事が出来る。ガード式にはガード名を指定出来るが、ガード式の成立順番を得るには、必ずガード式にガード名を指定しておかなくてはならない。
待ち受け結果の中に、待ち受け名で示される待ち受けの結果が含まれていた場合、その発火順序を示すインデックスを返す。最後に成立した待ち受けのインデックスは 0 で、インデックスが大きくなる程過去に成立した事を示す。ただし、AND/逐次待ち受けが含まれていた場合、単純に個々の待ち受けが成立した順番を示しているわけではなく、ガード式の成立した順番を示す。
result = event.wait(name = "fired") & \
pause(100, name = "timeout")
if result.index("fired") < result.index("timeout"):
(timeout が発生してから event が発火した)
else:
(event が発火してから timeout が発生した)
待ち受けが複合待ち受けでなく、単一待ち受けであった場合、待ち受け結果の val メンバーに、単一待ち受けの発火値が入っている。また、この方法を利用する場合、単一待ち受けのガード名は省略する事が出来る。ただし、複合待ち受けの結果の場合は、この方法は使用出来ない。
event = Event()
def proc1():
result = event.wait()
print(result.val)
def proc2():
event.signal("fire")
facility が None なら待ち受け結果に含まれる全てのファシリティロックを解放する。facility が 指定されているなら待ち受け結果に含まれる全ての facility のファシリティロックを解放する。ファシリティロックがひとつも含まれていない場合は何もしない。待ち受け結果に含まれる全てのファシリティロックが解放済みなら True を返す。そうでなければ False を返す。
以下のように使用する事が出来る。
def proc4():
result = yield ((facility1 & facility2).request() |
pause(10, name = "timeout"))
if "timeout" in result:
...
else:
...
result.releaseAllFacilities()
facility1 と facility2 の双方のファシリティロックを取得しようとするが、一定時間取得出来ない場合はタイムアウト処理を行う例であるが、このような場合は、releaseAllFacilities を使わないと、問題が生じる。
この例の場合は、4 つのケースがある。
facility1 のロックが時間内に取得出来、その後タイムアウトが発生。
facility2 のロックが時間内に取得出来、その後タイムアウトが発生。
facility1 と facility2 のロックが時間内に取得出来た。
どちらのロックも取得出来ずにタイムアウトが発生。
どのようなケースでも、releaseAllFacilities を実行しておけば、全てのファシリティロックを解放してくれる。
もし、ファシリティロックの解放忘れがあると、永久にファシリティを占有してしまうので、注意が必要である。
あるいは、ファシリティの取得の canceled ハンドラに releaseIfRequested (2.5.5 章) を指定しておく事も出来る。
def proc5():
result = yield ((facility1 & facility2).request(
canceled = releaseIfRequested) |
pause(10, name = "timeout"))
if "timeout" in result:
(タイムアウトが発生した場合は、)
(必ず全てのファシリティを自動解放している)
...
else:
(タイムアウトが発生なかった場合は、)
(必ず両方のロックを取得している)
...
result.releaseAllFacilities()
直前の待ち受け結果を返すガード式である。直前の待ち受け結果とは、そのプロセスがひとつ前に実行した「yield ガード式」の結果である。得られた結果には2.22 章章の操作が可能である。go で状態遷移した場合も、直前の待ち受け結果は保存される。つまり、go で遷移した直後に yield last() を実行すれば、go を実行したガード式の結果が得られる。
キューには、FIFO, PriorityQ, Stack がある。
先入れ、先出しのキューを示す。First In, First Out の略である。1, 2, 3 の順番で入力された場合、1, 2, 3 で出力する。優先度 priority は無視される。
優先度付きキューを示す。入力された順番とは関係なく、優先度 priority の高い順番に出力する。
後入れ、先出しのキューを示す。LIFO (Last In, FirstOut) キューとも言う。1, 2, 3 の順番で入力された場合、3, 2, 1 で出力する。優先度 priority は無視される。
ランダムなキューを示す。入力された順番とは関係なく、
ガード式の処理内部でエラーが発生した場合、スタックトレースはスケジューラ内部の行数を示すため、ユーザコードのどの部分でエラーが発生したかが分からない。start() を実行する前に psimDebug() を呼んでおけば、スタックトレースにユーザコード上の行数を表示するようになる。
以下のコードは pause の引数にエラーがある。
エラーコード
実行するとエラーが発生しスタックトレースが表示されるが、どこでエラーが発生しているかが分からない。
Traceback (most recent call last):
...
File "psim\core.py", line ..., in registerRequest
RuntimeError: unsupported operand type(s) for +: 'float' and 'str'
(try psimDebug() before start() to show detail)
以下のコードのように psimDebug() を書いておく。
エラーコード
実行すると、8 行目でエラーが発生している事が分かる。
Traceback (most recent call last):
...
File "psim\core.py", line ..., in registerRequest
RuntimeError: unsupported operand type(s) for +: 'float' and 'str'
...
File "....py", line 8, in proc
yield pause("abc")
...
S4 Simulation System にてエージェントベースモデリングをする際は、大きくわけて、
環境
エージェント集合
エージェント
に抽象化する。
環境は、エージェント行動の基盤となるジオメトリ情報や、全エージェントのテーブルなどを管理するものである。
エージェント集合は、互いに影響を及ぼしあいながら行動する複数のエージェントの集りを表現するものである。エージェント集合は必ず環境に属す。
エージェントは、個々の自律的に動作する主体を表現するものである。エージェントには、固定ステップで同期的に動作する同期エージェント、個々のエージェントが非同期に動作する非同期エージェントがある。エージェントは必ずエージェント集合に属す。
また、エージェント結果を表示するために、エージェントパネルが用意されている。
環境は、エージェント行動の基盤となるジオメトリ情報や、全エージェントのテーブルなどを管理するものである。
個々のエージェントは独自の属性を持つ。そのため、位置情報などをエージェントの内部属性として保持する事は禁止はしていない。しかしながら、位置情報はエージェント間で共有する必要があるので、位置情報に関しては、必ず環境の setPositionm, getPosition を経由してやりとりする事を推奨する。
環境を作成する。name には名前を指定する。
環境とは、エージェント行動の基盤となるジオメトリ情報や、全エージェントのテーブルなどを管理するものである。
エージェントは必ずひとつの環境を持つ。各エージェントには、環境の位置属性値が、エージェントの属性値として、付与される。
環境生成後に呼ばれる。
新規のエージェントが作成されたら、必ずこのメソッドが呼ばれる。
エージェントは必ずひとつの環境に属す。
各エージェントに環境に固有の属性を設定する。
エージェント agent の環境に固有の位置属性を更新する。
エージェントの環境上の位置属性が変わったら、必ずこのメソッドが呼ばれる。
pos は、環境上の位置属性(座標やノード番号など)であり、そのフォーマットは、環境ごとに異なる。
エージェント agent の環境に固有の位置属性を返す。
環境上の位置属性(座標やノード番号など)であり、そのフォーマットは、環境ごとに異なる。
環境内のランダムな位置属性を返す。
環境上の位置属性(座標やノード番号など)であり、そのフォーマットは、環境ごとに異なる。
環境内のエージェントの中で、srcAgent からの距離が、d 以内のエージェントのリストを返す。
widthDistance が True の場合は、距離とエージェントタプルのリストを返す。
この環境を panel 上に描画する。
この環境上で、エージェントのリスト agents を panel 上に描画する。
グラフ構造を表すための EnvironmentBase を継承した環境クラス。 graph は NetworkX のグラフオブジェクトを指定する。無向グラフなら networkx.Graph, 有向グラフなら networkx.DiGraph が指定可能である。
グラフ構造を表す。NetworkX の Graph もしくは DiGraph のオブジェクトである。
NetworkX の様々な API が利用可能である。基本的な操作は以下になる。
graph.nodes(): ノードのリストを返す
graph.edges(): エッジのリストを返す。(ふたつのノードからならタプル)
graph.node[v]: ノード v の実体を返す。
graph.node[v][ATTRNAME]: ノード v の属性 ATTRNAME を返す。(左辺値の場合は設定する)
graph[u][v]: エッジ (u, v) の実体を返す。
graph[u][v][ATTRNAME]: エッジ (u, v) の属性 ATTRNAME を返す。(左辺値の場合は設定する)
より詳細な使い方は、NetworkX のマニュアルを参照の事。
このメンバー値にキーがノード番号、値が x と y からならるタプルであるような辞書を指定していた場合、draw メソッドでは、その位置にプロットを行う。
最小経路長を返す。
srcAgent と tgtAgent が指定された場合は、その距離を返す。
srcAgent のみが指定された場合は、グラフ上の全ノードまでの距離を、ノード番号(位置属性)をキーとした辞書の形式で返す。
srcAgent も tgtAgent も指定されなかった場合は、グラフ上の全ノード間の距離を、第1キーが起点ノード番号、第2キーが終点ノード番号とした、辞書の形式で返す。
cutoff は、探索を停止する距離である。
エージェント agent の環境に固有の位置属性を更新する。
エージェントの環境上の位置属性が変わったら、必ずこのメソッドが呼ばれる。
pos が node を示している場合、エージェントはノード node 上にいる事を示す。
pos が(edge[0], edge[1], d) の形式の場合、エージェントはエッジ (edge[0], edge[1]) 上にいる事を示す。edge[0] の位置を v0, edge[1] の位置を v1 とすると、(1 - d) * v0 + d * v1 の位置にいる事を示す。
setPosition 内部では、findNeighborAgents が高速に動作出来るように、内部にエージェントの位置情報を保持している。具体的には、以下のような実装になっている。この他の処理を加えても良いが、通常ここにあるよう処理は残して置く必要がある。
def setPosition(self, agent, pos):
try:
origPos = self._agentAttrs[agent]
if isinstance(origPos, (list, tuple)):
(エッジ上)
self.graph[origPos[0]][origPos[1]]
["agents"].remove(agent)
else:
(ノード上)
self.graph.node[origPos]
["agents"].remove(agent)
except:
pass
self._agentAttrs[agent] = pos
if isinstance(pos, (list, tuple)):
(エッジ上)
self.graph[pos[0]][pos[1]]
["agents"].append(agent)
else:
(ノード上)
self.graph.node[pos]["agents"].append(agent)
エージェント agent の環境に固有の位置属性を返す。
エージェントの環境上の位置属性が変わったら、必ずこのメソッドが呼ばれる。
位置属性が node を示している場合、エージェントはノード node 上にいる事を示す。
位置属性が(edge[0], edge[1], d) の形式の場合、エージェントはエッジ (edge[0], edge[1]) 上にいる事を示す。edge[0] の位置を v0, edge[1] の位置を v1 とすると、(1 - d) * v0 + d * v1 の位置にいる事を示す。
getPosition の実装は以下のようになっている。基本的には setPosition された値をそのまま返却している。
空のグラフを作成する。 directed が True なら有向グラフ、そうでないなら無向グラフになる。 ユーザーがグラフを自分で初期化する必要がある。
例えば、以下のように initAfter メソッドで初期化する事ができる。
def initAfter(self, **keys):
self.graph.add_node(0)
self.graph.add_node(1)
self.graph.add_node(2)
self.graph.add_node(3)
self.graph.add_edge(0, 1)
self.graph.add_edge(0, 2)
self.graph.add_edge(0, 3)
self.graph.add_edge(1, 2)
self.graph.add_edge(1, 3)
self.graph.add_edge(2, 3)
ノード数 n, エッジ数 m のランダムグラフを作成する。 ただし、m が完全グラフのエッジ数を越えた場合は、完全グラフを返す。 directed が True なら有向グラフ、そうでないなら無向グラフになる。 seed は乱数の種を指定する。しかし seed が None ならグローバル系列から乱数の種を初期化する。
ノード数 n のランダムグラフを作成する。おのおののエッジは確率 p で生成される。 directed が True なら有向グラフ、そうでないなら無向グラフになる。 seed は乱数の種を指定する。しかし seed が None ならグローバル系列から乱数の種を初期化する。
Barabasi-Albert モデルに従ったスケールフリーネットワークを作成する。 m 個のノードからなら空のグラフから開始し、ノード数が n になるまで成長させる。ノードを追加する時、既に存在する m 個のノードにエッジを張るが、この時、エッジが張られる確率は、それぞれのノードのその時点での次数に比例する。 グラフは無向グラフになる。 seed は乱数の種を指定する。しかし seed が None ならグローバル系列から乱数の種を初期化する。
スケールフリー性(次数分布のべき乗則)を持ったネットワークを作成する。m 個のノードからなら空のグラフから開始し、ノード数が n になるまで成長させるのは Barabasi-Albert モデルと同様だが、ノードの追加時に、確率 p で、triangle を生成する。 グラフは無向グラフになる。 seed は乱数の種を指定する。しかし seed が None ならグローバル系列から乱数の種を初期化する。
ノード数 n の完全グラフを作成する。 directed が True なら有向グラフ、そうでないなら無向グラフになる。
幅 width、高さ height の格子グラフを作成する。 type が 4 なら 4 方格子、6 なら 6 方格子、8 なら 8 方格子になる。 directed が True なら有向グラフ、そうでないなら無向グラフになる。
4 方格子もしくは8 方格子の場合、キーが座標 (x, y) で、値がノード番号であるような辞書を返す。座標値は、左下が (0, 0) である。
4 方格子もしくは8 方格子の場合、キーがノード番号で、値が座標 (x, y) であるような辞書を返す。座標値は、左下が (0, 0) である。
GEXF フォーマットのファイルからグラフを作成する。data フォルダの下の、basename よりデータを読み込む。
GEXF フォーマットでは、配置情報を記録する仕様が別途定義されている。Gephi で自動配置した結果を GEXF フォーマットでエクスポートすると、viz/position/x と viz/position/y にそれぞれ配置位置情報が入っている。そのため、initAfter メソッドは以下のようにしている。
def initAfter(**keys):
(Gephi でエクスポートした gexf ファイルの場合、)
(ノード属性の viz/position/x と viz/position/y にそれぞれ、)
(配置位置情報が入っている。)
self.layout = {}
try:
for v in self.graph.nodes_iter():
attrs = self.graph.node[v]
x = attrs["viz"]["position"]["x"]
y = attrs["viz"]["position"]["y"]
self.layout[v] = (x, y)
except:
(おそらく、Gephi 以外で作成されたもので、配置位置情報が無い、)
(あるいは、別の場所にある。)
(表示したい場合は、適切なレイアウト情報を設定する必要がある。)
pass
GraphML フォーマットのファイルからグラフを作成する。data フォルダの下の、basename よりデータを読み込む。
2 次元ユークリッド空間を作成する。x \in [x0, x1], y \in [y0, y1] の範囲の空間となる。トーラスとして実装しており、必ず範囲内に丸められる。x \leftarrow x0 + (x - x1) mod (x1 - x0), y \leftarrow y0 + (y - y1) mod (y1 - y0)
srcAgent から tgtAgent までのユークリッド距離を返す。
注意 ソーシャルフォースモデル環境はミクロ人流環境に統合されました。 SFMEnvironmentBaseクラスの機能はすべてMicroPedEnvironmentBaseクラスを用いてご利用いただけますので、新たに作成されるモデルではMicroPedEnvironmentBaseクラスをご利用ください。
ミクロ人流モデルは、2次元平面の中の歩行者一人一人の動きをシミュレーションするモデルである。 S4ではソーシャルフォースモデル(SFM)とフロアフィールドモデル(FFM)の2種類のミクロ人流シミュレーション用モデルを用意している。 ソーシャルフォースモデルについては3.2.14.2 章節、フロアフィールドモデルについては3.2.14.5 章節を参照。また、モデルの使い分けについては3.2.14.8 章を参照。
ソーシャルフォースモデル(Social Force Model, SFM) とは、群集行動の力学ベースモデルのひとつである。各歩行者は質量を持つ質点として表され、平面内で運動する粒子とみなす。各歩行者は、目的地を持つが、他の歩行者や、障害物から相互に干渉を受けながら、それぞれが運動するようなモデルである。
質量 m_i を持つ歩行者i は、以下の運動方程式に従う。
m_i\frac{d\vec{v}_i}{dt} = m_i\frac{v_i^0\vec{e}_i(t)-\vec{v}_i(t)}{\tau_i}+ R(c, \sum_{j (\ne i)}{\vec{f}_{ij}} + \sum_{W}{\vec{f}_{iW}})
ここで、\vec{e}_i は目的地に向かうベクトル、 v_i^0 は歩行者の最適な速度、 \vec{v}_i(t) は現在の速度であり、 \tau_i は加速時間である。 R(c, p) は、平均 p、分散共分散共分散行列が \left( \begin{matrix} \sigma^2 & 0 \\ 0 & \sigma^2 \end{matrix} \right), \sigma = c||p|| の多変量正規分布に従う乱数である。
\vec{f}_{ij} は歩行者 j から 歩行者 i に与える外力であり、ソーシャルフォースの計算方法にCS-SFMを指定する場合とTTC-SFMを指定する場合で定義が異なる。詳しい定義は(3.2.14.3 章章)を参照。
\vec{f}_{iW} は障害物 W から 歩行者 i に与える外力であり、以下のように表される。
\begin{aligned} \vec{f}_{iW} &= \Biggl\{ A_i \exp\left( \frac{r_i-d_{iW}}{B_i} \right) + kg(r_i-d_{iW}) \Biggr\} \vec{n}_{iW} \nonumber \\ &+ \kappa g(r_i-d_{iW}) \Bigl\{ \vec{v}_i \cdot \vec{t}_{iW} \Bigr\} \vec{t}_{iW} \nonumber \end{aligned}
ここで、r_{iW} は壁までの距離、 \vec{n}_{iW} は壁への法線方向の単位ベクトルであり、 \vec{t}_{iW} は (-n^2_{iW}, n^1_{iW}) である。 A_i は歩行者 i の相互作用の強さ、 B_i は歩行者 i の相互作用の範囲、 kは弾性係数、\kappaは散逸係数とする。
エージェント間に働く外力の計算方法はCS-SFMとTTC-SFMの2つの方法から指定する。 CS-SFMでは他の歩行者からの距離に応じて外力を受けるのに対して、TTC-SFMでは歩行者の速度と距離から他の歩行者に接近しそうな時刻と位置を計算し、接触を避けようとするような外力を受ける。そのため、TTC-SFMの方が外力の定義は複雑なものになる。 CS-SFMを指定した場合の\vec{f}_{ij}の定義は以下の通りである。
\begin{aligned} \vec{f}_{ij} &= \Biggl\{ w(\varphi_{ij})A_i \exp\left( \frac{r_i+r_j-d_{ij}}{B_i} \right) + kg(r_i+r_j-d_{ij}) \Biggr\} \vec{n}_{ij} \nonumber \\ &+ \kappa g(r_i+r_j-d_{ij}) \Bigl\{ (\vec{v}_j-\vec{v}_i) \cdot \vec{t}_{ij} \Bigr\} \vec{t}_{ij} \nonumber \end{aligned}
ただし、r_i、r_jは歩行者i、jの半径、 d_{ij} は歩行者 i と j の距離、 kは弾性係数、 \kappa は散逸係数、 \vec{n}_{ij} は歩行者 j から i に向かう単位ベクトルとする。 \vec{t}_{ij} は (-n^2_{ij}, n^1_{ij}) と定義し、\vec{n}_{ij}を90度回転させたベクトルとする。 g は以下のように定義される関数とする。
g(x) = \left\{ \begin{matrix} x & x \ge 0 \\ 0 & \text{otherwise} \\ \end{matrix} \right.
\varphi_{ij}は歩行者iの速度v_iと歩行者iから歩行者jに向かうベクトルのなす角である。w(\varphi_{ij})は次のように定義される。
w(\varphi_{ij}) = \lambda + (1-\lambda)\dfrac{1+\cos{\varphi_{ij}}}{2}, \quad 0\leq \lambda \leq 1
ただし、\lambdaは非等方性のパラメータである。このようにwをソーシャルフォースにかけることで、それぞれの歩行者は自分の後方にいる歩行者よりも前方にいる歩行者からより大きな力を受けるという非等方性を実現する。\lambda=1はまったく非等方性を考慮しないことを意味する。\lambdaは0に近いほど非等方性が強く考慮される。
TTC-SFMを指定した場合の\vec{f}_{ij}の定義は以下の通りである。
\begin{aligned} \vec{f}_{ij} = w(\varphi_{ij})A_i \dfrac{v_i}{t_i}\exp\left( \dfrac{r_i+r_j-d_{ij}}{B_i} \right) \vec{n'}_{ij} + kg(r_i+r_j-d_{ij}) \vec{n}_{ij} \\ + \kappa' g(r_i+r_j-d_{ij}) \Bigl\{ (\vec{v}_j-\vec{v}_i) \cdot \vec{t}_{ij} \Bigr\} \vec{t}_{ij} \end{aligned}
ただし、r_i, r_j, d_{ij}, k, \vec{n}_{ij}, \vec{t}_{ij}, g, w(\varphi_{ij})はCS-SFMの場合と同じものとする。v_iは歩行者iの速度とする。
\kappa'は散逸係数であるが、TTC-SFMでは散逸を考えることで衝突後の回避がスムーズに行えなくなることがあるため、通常は\kappa'=0としている。SFMEnvironmentBaseの引数でttc_dissip=Trueと指定することによって\kappa'をソーシャルフォースパラメータの散逸係数(つまり、SFMEnvironmentBaseの引数kappa)と同じ値に設定し、散逸を考慮してシミュレーションを行うこともできる。
TTC-SFMでは歩行者間外力の計算の中で別の歩行者と接近しそうなタイミングを計算する。具体的には、次のような手順を取る。
まず、歩行者iと歩行者kがそれぞれ同じ速度で進み続けた場合に最接近するまでの時間をt_{ik}とする。ただし、\theta_{ik}を歩行者kの歩行者iに対する相対速度と歩行者kから歩行者iに向かうベクトルのなす角度とし、\theta_{ik} > \frac{\pi}{4}の場合はt_{ik}=\inftyと定義する。歩行者i以外のすべての歩行者kについてt_{ik}を計算し、t_i = \min_{i\neq k}{t_{ik}}と定義する。t_i=\inftyとなる場合もあるが、その場合はv_i/t_i=0と定義する。
\vec{n'}_{ij}は歩行者iと歩行者jがどちらも同じ速度で進み続けたとしたときのt_i秒後の歩行者jから歩行者iに向かう単位ベクトルとする。
CS-SFMでは、複数の人流の交差においてエージェント速度が落ちすぎて停滞してしまうような現象が見られることがある。このような場合、TTC-SFMを選択することでエージェント速度が落ちすぎることなくスムーズな移動が実現されやすい。
一つの出口にエージェントが集中するような混雑分析をしたい場合、TTC-SFMでは不自然に大きな速度を持つエージェントが多く観察されることがある。CS-SFMを選択することで、この現象は解決される可能性がある。CS-SFMを選択したにもかかわらず、速度が上限に近いエージェントが多く観察される場合は、「エージェント集合のステップ間隔」をより小さく設定することで解決することがある。
フロアフィールドモデル(Floor Field Model, FFM)とは、セルオートマトンによるミクロ人流モデルである。1セルは一人の歩行者の占有領域に相当しており、それぞれのセルは1人のエージェントが占有しているか、空いているかの2状態を取る。退出などの混雑時のシミュレーションではセルの1辺の長さは一般的に30-40cm程度に設定される。
各歩行者はフロアフィールドと呼ばれる「場」を用いて歩行者が占有していない隣接セルに移動する確率を計算し、確率に基づいて次に進むセルを決定する。フロアフィールドの種類には、
フロアフィールドモデルの1ステップは以下のような流れとなる。
動的フロアフィールドの拡散・減衰
動的フロアフィールドの値は、環境オブジェクトの属性alpha
で設定される拡散係数によって拡散し、MicroPedEnvironmentBase
の属性delta
で設定される減衰係数によって減衰する。
具体的には、ステップ数tにおける動的フロアフィールドのセル(i,, j)の値D_{i,j}^tに対して、拡散係数を\alpha, 減衰係数を\deltaとして次式のように更新が行われる。
D_{i,j}^{t+1} = (1-\alpha)(1-\delta)D_{i,j}^{t} +
\frac{\alpha(1-\delta)}{4}(D_{i+1,j}^t + D_{i,j+1}^t + D_{i-1,j}^t +
D_{i,j-1}^t)
なお、障害物セルの上では上記の拡散・減衰の後に動的フロアフィールドの値は0に設定される。つまり、障害物以外のセルからの拡散・減衰時に障害物セルの影響はないが、障害物セルからの拡散・拡散は起こらない。なお、シミュレーション領域の周囲は障害物セルで囲われていると解釈される。
動的フロアフィールドの拡散・減衰はシミュレーション空間が大きくなるにつれて計算に時間がかかるようになる。とくに、エージェントの密度が低い場合は動的フロアフィールドの影響が非常に小さくなることがある。このような場合には、動的フロアフィールドとの結合定数k_O
を0として設定することにより、動的フロアフィールドの拡散・減衰をスキップし、高速にシミュレーションすることができる。
各エージェントの移動セルの決定
移動を行う各エージェントに対して、移動可能なそれぞれのセルへの移動確率を計算する。この移動確率に基づき、各エージェントが移動するセルを乱数を用いて決定する。
各エージェントが移動しうる隣接セルは「ノイマン近傍(隣接4セル)」もしくは「ムーア近傍(隣接8セル)」から選択可能で、MicroPedEnvironmentBase()
の引数においてnbd="Neumann"
or"Moore"
として指定できる。各エージェントの移動可能セルは、現在エージェントが位置するセルと隣接セルのうち、他のエージェントが占有していない、非障害物のセルとする。
セル(i,j)エージェントaの各隣接セル(i',j')への移動確率p_{i',j'}^{i,j}は以下のように計算される。 p_{i,j}^a = N_a \exp(k_D D_{i,j} \cdot (i'-i, j'-j)^\mathsf{T})\exp(- k_S \delta_d(r_d) S_{i,j}^a)\exp(k_O O_{i,j}^a) ただし、D_{i,j}をセル(i,j)の動的フロアフィールドの値、k_Dを動的フロアフィールドとの結合定数、S_{i,j}をエージェントaのセル(i,j)の目的地フロアフィールドの値、k_Sを目的地フロアフィールドとの結合定数、O_{i,j}をセル(i,j)の障害物フロアフィールドの値、k_Oを障害物フロアフィールドとの結合定数とする。\delta(r_d)はムーア近傍を選んだときにのみ意味を持ち、(i',j')が(i,j)に対して斜めに位置するときにr_d、それ以外の時に1を取る。r_dは斜め移動の際の目的地フロアフィールドのマスク値であり、デフォルトでは1/\sqrt{2}と設定されている。この値を1より小さく設定することにより、目的地に向かう際に斜め移動ばかりを好む傾向を打ち消すことができる。N_aはエージェントごとに移動確率の合計が1となるようにするための規格化定数である。
移動確率を計算した後、移動確率に基づいて移動セルを決定する。この段階では複数エージェントが同じセルに移動しようとする可能性がある。
移動セルの競合の解消
複数エージェントが同じセルに移動しようとしている箇所については、摩擦係数\muと移動確率に基づいて競合を解消する。
エージェントの移動と動的フロアフィールドの更新
それぞれのエージェントを移動セルに移動させる。 また、セル(i,j)に位置していたエージェントがセル(i', j')に移動したとき、動的フロアフィールドのセル(i,j)の値に(i'-i, j'-j)^\mathsf{T}を長さが1となるように規格化したベクトルを加える。
FFMはセルの上を1ステップに1セルずつ進んでいくモデルであるため、basev = セルの1辺の長さ/エージェント集合のステップ間隔 が最高速度となる。 そのため、エージェントの速さとして basev 以上の値を指定してもエージェントは basev の速さで進むと解釈され、シミュレーションされる(そのように解釈されるエージェントがいる場合、警告のメッセージが出力されるが、シミュレーションは停止しない)。 逆に、basevより遅い速度が指定されたエージェントについては、overstepと呼ばれる概念を導入し、エージェントを定期的にその場にとどまらせることで複数ステップを通した平均速度を与えられた速度に近づける操作を行う。basevのp倍速エージェントの具体的な操作は以下の通りである。
FFMにおいては斜めの移動を許さないノイマン近傍が良く用いられる。ノイマン近傍を用いると斜め移動が禁じられる分、エージェントの動きはカクカクとしたものになるが、ノイマン近傍による移動は方向による移動距離の違いが発生しないため、モデルがシンプルになり、詳細な分析の際に有用である。
ムーア近傍を用いると、エージェントが斜めに移動することにより移動方向による移動距離の違いが発生するが、エージェントの動きはノイマン近傍よりも滑らかになる。移動距離の違いにより、
という2つの問題が発生する。S4では上記の問題について
という仕組みを作っているため、上記の問題については通常気にする必要がない設計としている。 エージェントがスムーズに移動するシミュレーションを行う場合や、セルの粗さが気になる場合にはムーア近傍の利用を推奨する。
SFM、FFMはどちらも人流をエージェント一人一人の動きからモデリングするが、SFMはFFMよりも粒度の細かいリアルな挙動のモデリングに、FFMはSFMよりも粒度を粗くし混雑現象の発生などの多くの人を巻き込んだ現象を軽量にモデリングする点に比重を置いている。どちらのモデルも、狭い出口にエージェントが集中する際のボトルネックの再現や、対向流に対する列形成などの重要な群衆行動の再現が確認されているモデルである。
一つの違いは空間のモデリングの違いである。SFMは連続空間としてモデリングされているが、FFMはセル空間としてモデリングされているため、エージェントの挙動はSFMでは滑らかに、FFMではカクカクとした離散的なものになる。よりリアルな(連続的な)挙動の再現のためにはSFMを用いるとよい。
計算量の観点では、エージェント数が多くなるにつれてFFMはSFMよりも高速にシミュレーションが行えるようになる。非常にエージェント数の大きいシミュレーションを行いたいが、計算効率が悪すぎると感じる場合はFFMを用いるとよい。逆に、あまりエージェント数が大きくないが空間が非常に大きいシミュレーションはSFMの方が効率よくシミュレーションできることもある。FFMが極端に遅い場合はこのケースに該当すると考えられるが、エージェント同士があまり干渉しない場合は動的フロアフィールドの影響が小さいと考えられるため、動的フロアフィールドとの結合定数k_D
の値を0と設定し、計算速度を上げるという選択も考えられる。
非常に混雑した状況のシミュレーションでは、SFMのエージェント同士の反発力の調整が非常に難しい場合がある。SFMのエージェント同士の反発が激しい場合は、反発力を小さくするようにパラメータを調整するほかに、エージェント集合のステップ間隔を小さくする、エージェントの最高速度を小さくするといった解消の方法がある。エージェント集合のステップ間隔を小さくするとシミュレーション自体は非常になめらかになるが、シミュレーションの計算時間が大きくなってしまう。FFMを用いると、ステップ間隔の大きさを適度に保ったまま、非常に混雑したシミュレーションの実行が可能になるが、エージェントの挙動は離散的なものになる。FFMを用いる場合、SFMとは異なり、ステップ間隔を必要以上に小さくすると本来起こるはずであったエージェント同士の競合が起こらなくなることがあるため、とくに混雑状況下ではシミュレーションの結果に本質的に影響することに注意が必要である。
S4で提供する3Dアニメーションの作成や視野についてのAPIを用いるシミュレーションを行う場合、FFMでも利用可能ではあるが、FFMよりもSFMの方が望ましい。これは、FFMではエージェントの空間が離散的であることから、速度もSFMと比べて非連続的であるため、不自然なアニメーションや視野を得ることによる。
シミュレーション空間は2次元の平面であり、左下の座標 (x_0, y_0) と、右上の座標 (x_1,y_1) で定められる。
その中に任意の障害物を配置させる事ができる。障害物は任意の多角形として指定する事が出来る。
ホールにも対応するが、ミクロ人流モデルでは障害物を越える事ができないため、連結していない領域間の移動は、別途処理が必要となる。
FFMを用いる場合、各セルは立ち入り禁止セルとなるか移動可能セルとなるかの2値を取る。 セルの面積のうち何割が障害物として設定されているかによって立ち入り禁止セルと移動可能セルを判定している。 この値はMicroPedEnvironmentBaseの引数 ob_rate として設定できる。
SFMでは、各エージェントが(可視な)単一の目的地を持つような場合に、エージェント間障害物間との相互干渉をモデリングする。つまりSFMだけでは、目的地が可視でない場合、エージェントがスタックしてしまうような現象が容易に発生する。そこで、経路グラフによる経路探索モデル(PGM)では、SFMとは別に、複数の経路ポイントを経由した歩行者の行動もサポートするように設計されている。FFMを選択した場合にもPGMを用いることができる。
エージェントの通過する可能性のある地点を経路地点と呼ぶ。経路地点は面積を持つ円である。
互いに経路地点の中心を視認出来る経路地点の組はエッジで結ばれる。そのようにして作成された無向(もしくは有向)グラフを経路グラフと呼ぶ。
SFM では、障害物を越えて目的地に到達する事ができない。視認できない目的地が設定された場合は、経路グラフを元に途中の経路が選択される。そのため、シミュレーション空間のあらゆる位置から視認確認可能な経路地点が少なくともひとつは存在しなくてはならない。
経路グラフの作成方法には幾つかの方法がある。
一番簡単な経路グラフ作成方法である。
格子状に経路地点を自動登録し、可視な隣接するエッジは自動接続される。
経路地点を手動で登録する。エッジに関しては、可視なエッジが自動的に接続される。
経路地点及びエッジを全て手動で登録する。
v1 = env.addPathPoint(x1, y1, r1)
v2 = env.addPathPoint(x2, y2, r2)
...
e1 = env.addPathEdge(v1, v2)
e2 = env.addPathEdge(v2, v4)
...
経路選択モデルは、ユーザが任意に修正可能な仕組みにするが、基本モデルとして、目的地までの最短経路距離を効用とするロジットモデルが実装されている。
経路選択関数は、ミクロ人流エージェントが、ある経路地点に到達した時に呼ばれ、次に選択すべき経路地点を返す関数である。
基本実装されている経路選択モデルでは、次の経路地点 k を選択する確率は以下となる。
P_k = \frac{\text{exp}(- \mu D_{kG})} {\sum_{k' \in R}{\text{exp}(- \mu D_{k'G})}}
D_{uv} は経路地点 u から v の最短距離、\mu はスケールパラメータである。\mu が大きくなると、ほぼ最適解を選ぶようになり、\mu が 0 に近づくと、最適でない解を選ぶ確率が増大する。
他の効用を利用した経路選択モデルに拡張したり、全く別のモデルを実装する事も可能である。
ミクロ人流エージェントに、現在地と目的地が指定されて配置されると、目的地に向かうために最初に向かうべき経路地点を選択する。その時、この経路選択モデルが適用される。また、ある経路地点に到達したら、次の経路地点を選択するために、この経路選択モデルが適用される。
PGMとは別の経路地点を用いない経路計算手法も実装されている。 経路地点を用いないことには次のような利点がある: - 経路地点やエッジを設定する手間が不要になる(ただしエージェントの出現地点などを指定する際に経路地点を用いる場合、経路地点の設定は必要となる)。
PGMの場合経路地点を辿っていくため経路地点の配置によっては不自然な経路になることがあるのに対し、空間上の任意の点を通るため自然な経路となる。
PGMの場合次の経路地点が不可視となった場合に特別な対処が必要となる(最悪の場合迷子になり移動できなくなる)のに対し、任意の点同士の経路を求められるため、目的地を見失った場合でも単純に経路を再計算するだけで復帰できる。
ミクロ人流環境初期化時に移動可能領域のボロノイ図を作り、保持しておく。 エージェントごとの経路計算において、出発地・目的地から最も近いボロノイ点までの直線経路およびボロノイ図中の境界線に沿って移動する経路を求めることによって出発地から目的地までの経路を得る。 経路計算の際、ボロノイ図境界線のうちエージェント自身の直径よりも狭い幅を持つ通路は除いており、 ミクロ人流エージェントがモデルに従って実際に動作した際に細い詰まってしまうことを回避する。
CMMで経路を求めたうえで、最適化計算によって経路長の短いパスを求める(CMMは領域の中心を経路の基本とするため、不自然な大回りをする傾向がある)。具体的には次のようなステップで経路を計算する: 1. あらかじめ領域を離散化した各点と障害物までの距離を求めておく
CMMの解から曲がり角などを抽出して適当な折れ線を得て、初期解とする。
経路長と障害物までの距離、慣性の項からなる目的関数を定式化し、これを最適化することで障害物に近すぎない範囲で経路長が短い経路を求める(最適化にはscipy.optimize.leastsqを用いている)。
CMM同様任意の2点間の経路を求めることができ、経路グラフの枝を必要としない。 また、経路計算後に左側通行/右側通行を指向する後処理を加えることができる。 この処理は得られた経路の各点を進行方向に対して左(右)に指定の距離だけ摂動させることによって行われる。 ただし、摂動によって障害物に近づきすぎる場合は摂動しない。
CMM/TIMの経路計算の結果、経路情報として次の2つが得られる:
points適当に離散化して得られる経路上の点列
各点に対し、その点から最も近い障害物までの距離
エージェントは開始位置からpointsを順に辿っていくことで目的地に向かっていくが、毎時刻ごとにpointsの中で現在地から可視なうち最も遠い(インデックスの大きい)点を目標位置とする。 この際、可視かどうかはpointsを中心としrsを半径とする円の中にエージェントの現在位置が含まれるかどうかで判定する(計算速度のため)。 もし目標位置が不可視となった場合、エージェントは経路の再計算を行う。
経路探索手法にTIMを選んだ場合、次のパラメータを指定することができる:
epsilonエージェントが障害物から保とうとする距離(1.0m)
エージェントごとに経路をばらつかせるかどうかのフラグ(bool値)。デフォルトではFalse。Trueの場合経路長の短さ重視の解/もとのCMMの解の間でランダムに経路を選択するようになる(False)。
領域を離散化する際の粒度(0.1m)
片側通行するかどうか(False)。(片側通行に関するパラメータは、経路計算手法にCMMを選んだ場合も適用される。)
片側通行する際にどちらにずらすかのフラグ。True:左側通行、False:右側通行(True)。
片側通行を指向する際に、元の経路からその向きにずらす最大距離(1.0m)。デフォルトでは上記のepsilonと同じ値に設定される。
最適化計算時に経路長を短くする/障害物を回避する、のどちらを重視するかをコントロールするパラメータ。経路計算がうまくいかない(障害物を突き抜ける経路が頻繁に得られる)場合、この値を小さくする(0.04)。
設定の方針は、以下のように考えるとよい: - epsilonは入力する地図の通路幅によって決める。最も細い通路の幅に対して、その半分以下に設定する必要がある。
resはエージェントの動作をコントロールしたい粒度に従って決める。例えば少なくとも10cm単位でコントロールしたい場合は0.1mに設定する。プログラムの使用メモリが足りない場合、resを大きくすることで対処する。
const_sigmaはとりあえずデフォルト値(0.04)を使い、障害物を突き抜けるケースが多い場合(出力に「経路計算に失敗。CMM経路を…」と表示される)0.03、0.02…と小さくする。障害物を突き抜けない範囲で大きくすると、より短い経路を求めることができるようになる。
その他agentrate, onesideなどのパラメータは、シミュレーションしたい内容・状況に即して選択する。leftdistは、epsilonと同程度かそれ以下に取るのがよい(経路が壊れる可能性があるので大きすぎる値を入れてはいけない)。
3つのうちのどの経路計算手法を選ぶべきかは、かけられる手間やシミュレーションしたい状況によって決まる。 以下、参考までに3つの手法の比較について述べる - 計算速度については、PGM, CMM, TIMの順に高速である。
PGMは経路地点・エッジの設定に依存(経路地点を経由して進んでいく)のに対してCMM, TIMは経路地点やエッジによらず、設定の手間が無い(エージェントの出現地点に経路地点を用いる場合は、経路地点のみ設定の必要がある)。
PGMは途中の経路地点を必ず経由し、CMMは移動可能領域の中間を通ろうとするため、不自然に見える経路を求めることがあるのに対し、TIMは最適化で経路を求めるため、人の目で見て自然な経路を選ぶ傾向がある。
TIMもしくはCMMの片側通行のオプションを用いると対行するエージェントがうまくすれ違い、混雑が生じにくくなる。
TIMは複数のパラメータを指定する必要があるのに対し、PGM/CMMはそのような必要が無い。
2 次元ユークリッド空間上のミクロ人流環境を作成する。引数modelに”sfm”を指定するとSFM、“ffm”を指定するとFFMを用いて歩行者をモデリングする。x \in [x0, x1], y \in [y0, y1] の範囲の空間となる。
各引数の意味は以下である。
(x0, y0)画面左下の座標
画面右上の座標
以下を引数に与えるときは、キーワード引数として指定する必要がある。
r0最大影響半径(m)
経路再探索間隔(s)
最適速度(m/s)
最高速度(m/s) ※FFMでは効果なし。FFMを選択した場合はlenEdge/エージェント集合のステップ間隔が最高速度となる
歩行者の半径(m)
※FFMでは効果なし。FFMを選択した場合はこの値ではなくlenEdge
の1/2として歩行者半径が描画される。
加速時間(s) ※FFMでは効果なし
体重(kg) ※FFMでは効果なし
外力の変動係数 ※FFMでは効果なし
視野制限距離(m)(0以下で制限なし)
視野仰角(degree)
歩行者半径表示
速度ベクトル表示
歩行者間外力表示 ※FFMでは効果なし
障害物外力表示 ※FFMでは効果なし
経路グラフ表示
Corridor Map 表示
背景画像表示
ユーザー定義領域表示
エージェント視野表示
経路探索手法の指定(“PGM”, “CMM”, “TIM”から選ぶ)
また、経路探索手法にTIMを選んだ場合は前項で述べた各パラメータを引数として与え、設定することができる。
res領域を離散化する際の粒度(0.1m)
滞留時の動作種類
「滞留時の動作種類」は次から選ぶことができる:
outシミュレーションから一時的に除外され、他エージェントと干渉しなくなる。
FFMの場合、エージェントによるセルの占有状況は変化しないため、SFMにおける”fix”のような動作になる点に注意が必要である。
他エージェントと干渉して動く。FFMでは非対応。
体重を一時的に増加させて他エージェントと干渉しても動かなくなる。FFMでは非対応。
他エージェントと干渉して動くが、常にもとの位置に戻ろうとする。
モデルとしてソーシャルフォースモデルを選択する場合は、以下のSFM用パラメータを引数として与え、設定することができる。
A相互作用の強さ(N)
相互作用の範囲(m)
弾性係数(kg/s2)
散逸係数(kg/ms)
非等方性のパラメータ
ソーシャルフォースの計算方法(“cs”,“ttc”)から選ぶ
モデルとしてフロアフィールドモデルを選択する場合は、以下のFFM用のパラメータを引数として与え、設定することができる。
k_D動的フロアフィールドとの結合定数。0以上の実数を指定する。0を指定すると動的フロアフィールドの拡散・減衰計算がスキップされ、計算時間が短くなる。
静的フロアフィールドとの結合定数。0以上の実数を指定する。
障害物フロアフィールドとの結合定数。0以上の実数を指定する。
摩擦係数。0以上1以下の実数を指定する。
動的フロアフィールドの拡散係数。0以上1以下の実数を指定する。
動的フロアフィールドの減衰係数。0以上1以下の実数を指定する。
セルの1辺の長さ
移動を考える近傍の種類を”Neumann”か”Moore”から選択する。“Neumann”のときは隣接4セル、“Moore”のときは隣接8セルを隣接セルとする。
斜め移動をする際の目的地フロアフィールドのマスク値。0以上1以下の実数を指定する。nbdに”Moore”を設定したときにのみ効果を持つ。
セルの障害物判定用の面積割合閾値。
障害物からの影響を受ける最大の距離。0を指定すると障害物に近づくことによる移動確率の軽減を受けない。
すべてのレイヤーを含むリストを返す。
名前が name であるレイヤーを追加する。name = None の場合、「レイヤーX」(Xは添え字)という名前が自動的に振られる。
レイヤー layer を取り除く。
正負が sign の真偽で、形状が (x, y) 座標のリスト points で表現され、属性が attrs であるユーザー定義領域を作成し、 layer に追加する。
ユーザー定義領域 uregions を削除する。
ユーザー定義領域のリストを受け取り、各領域を削除する。各ユーザー定義領域は所属レイヤーが異なっていてもよい。
ユーザー定義領域のリスト uregions をグループ化する。 attrs はグループの属性となる。 uregions の各要素が同一のレイヤーに属していない場合、エラーとなる。
ユーザー定義領域のグループ ugroup を解除する。
ユーザー定義領域のレイヤー layer に対応する属性テーブルを返す。
すべての経路地点を含むリストを返す。
x, y に半径 r の経路地点を加え、属性 attrs
を持たせる。経路地点番号を返す。経路エリアは障害物や他の経路エリアと重なってはいけない。重なった経路エリアは登録されずに、None
を返す。登録された場合は経路地点を返す。
modelとしてFFMを選択している場合、x,
y座標の代わりにセルの座標を整数値で指定することもできる。セルの座標として指定する場合は引数にcoord=“cell”と指定する必要がある。
NWEnviromentBaseではcoordのオプションは利用不可である。
経路地点 pathPoint を削除する。
経路地点のリスト pathPoints を受け取り、各経路地点を削除する。
経路地点の属性テーブルを返す。
属性 attr のついている経路点のリストを返す(これは属性名 attr に対する属性値が “1” であることを意味する)。存在しない場合は空リストを返す。
すべてのエッジを含むリストを返す。
u, v を接続する。お互いに可視でない場合は経路として登録されずに、 None を返す。d には u, v 間の距離を指定する。指定しなかった場合は、ユークリッド距離が設定される。r は可視を判定する半幅を意味する。指定しなかった場合は、歩行者の半径を利用する。あまり狭いエッジをつないでしまうと、エージェントがスタックする可能性があるので注意が必要である。
エッジ pathEdge を削除する。
エッジのリスト pathEdges を受け取り、各エッジを削除する。
エッジの属性テーブルを返す。
障害物を加える。輪郭((x, y) のリスト)もしくは Polygon オブジェクトを指定する。
Polygon オブジェクトとは、Polygon モジュールの Polygon オブジェクトである。
q = Polygon.Polygon(((0.0, 0.0), (10.0, 0.0),
(10.0, 5.0), (0.0, 5.0)))
t = Polygon.Polygon(((1.0, 1.0), (3.0, 1.0),
(2.0, 3.0)))
a = q - t
q は、(0.0, 0.0), (10.0, 0.0), (10.0, 5.0), (0.0, 5.0) を頂点とする長方形を作成する。
t は、(1.0, 1.0), (3.0, 1.0), (2.0, 3.0) を頂点とする三角形を作成する。
a は q から t を引いた形状を表す Polygon となる。つまり、長方形内に三角形の穴があいたような形状となる。
他の、Polygon オブジェクトに対する操作は、Polygon モジュールのマニュアルを参照の事。
例えば、a.isInside(x, y) は、座標 (x, y) が形状 a に含まれるか否かを検査する。 上記の例では、a.isInside(2, 1.5) は偽、a.isInside(5, 3) は真となる。
経路グラフを有向グラフに変換する。既に無向な経路が設定されていた場合は、双方向な経路に変換されるが、変換後に経路を加えた場合は、有向グラフとなる。
このメソッドを呼び出さなかった場合は、経路グラフは無向グラフとなる。
お互いに可視な経路地点間を自動的に接続する。r は可視を判定する半幅を意味する。指定しなかった場合は、歩行者の半径を利用する。あまり狭いエッジをつないでしまうと、エージェントがスタックする可能性があるので注意が必要である。
シミュレーション空間上に、8方格子で x 軸方向に nx 個、y 軸方向に ny 個、経路地点を配置する。経路エリアの半径は r となる。障害物と重なった経路エリアは登録されない。隣接する可視なエッジは自動的に接続される。登録された経路地点番号と、その座標で構成されるタプルのリスト [(v, x, y), …] を返す。s は可視を判定する半幅を意味する。指定しなかった場合は、歩行者の半径を利用する。あまり狭いエッジをつないでしまうと、エージェントがスタックする可能性があるので注意が必要である。
座標p=(x, y)に最も近い可視な経路地点番号を近い順にnum個返す(num>=2のときは返り値がリストになる)。 visible=Falseのとき可視化どうかによらず近くの経路地点を求めて返す。 pを座標値ではなく緯度経度として与える場合はprojに射影方法を指定する。 return_distance=Trueの場合経路地点と距離のタプルを返す。
長方形領域に含まれる経路地点のリストを返す。 x,yを座標値ではなく緯度経度として与える場合はprojに射影方法を指定する。
座標 p から経路地点 v が視野内にあるかどうかを判定する。 視野領域は p から v へ向かう幅 2 * r の長方形として、視野領域が、移動可能空間に完全に包含されるかどうかを判定する。
座標 p から座標 p2 が視野内にあるかどうかを判定する。 視野領域は p から p2 へ向かう幅 2 * r の長方形として、視野領域が、移動可能空間に完全に包含されるかどうかを判定する。 strict=False とすると障害物を格子に離散化した配列を用いて計算を行う。離散化に伴う誤差が生じるが、障害物の形状が複雑な場合はこちらのほうが高速に計算できる。
座標pからp2が視野(v方向を中心軸とする半角thetaの扇形)内にあるか判定する。strict = True だと厳密に判定し、False だと格子で粗く高速に判定する。
座標pから座標p2が視野内にあるかどうかの判定を、SDFを用いて粗く(格子幅ぶんの誤差を伴って)高速に判定する。
経路地点 v のエリア内にある点をサンプリングし、タプル(x,y)を返す。
最短距離を返す辞書Pを返す。P[u][v] が u, v 間の最短距離。
経路グラフを返す。NetworkX のグラフオブジェクトである。無向グラフの場合 networkx.Graph、有向グラフの場合 networkx.DiGraphのオブジェクトである。このオブジェクトは読み込み専用で、変更してはならない。
ノードの属性値は以下である。
“p”: 座標(numpy.array)
“r”: 半径
エッジの属性値は以下である。
この環境を panel 上に描画する。dispP の場合、経路グラフが表示される。
この環境上で、エージェントのリスト agents を panel 上に描画する。dispR なら、エージェントの半径を表示する。dispV なら速度ベクトルを表示する。dispW なら、歩行者間外力を表示する。dispF なら障害物外力を表示する。
SFM では利用不可である。
SFM では利用不可である。
SFM
では利用不可である。FFMの場合、posにはセル座標を整数値で設定することにより、そのセルにエージェントを再配置する。
NWEnvironmentBaseでも利用不可である。
agentの座標を返す。
FFMのみで利用可能である。agentの位置をセルインデックス(整数のタプル)で返す。
SFM では利用不可である。FFMの場合、移動領域中のセルの座標を整数のタプルで返す。
名称name, 容量capacityの施設を設定する。エージェントはこのnameを用いて メソッドsetStaying(t, facility=name)とすることで施設をt秒間利用するようになる。
OpenStreetMapが提供するpbfファイルを読みこんで経路グラフに設定する。image_providerを指定した場合同時に背景画像も設定する。
pbfファイルは例えば http://download.geofabrik.de/ から取得する。 pbfファイルのサイズが大きいため計算には数分程度の時間を要するが、計算結果を保存しておくため同じ設定で行った場合は次回以降の処理は高速化される。
得られた経路グラフのエッジは次の属性を持つ:
highway道路種別
制限速度(km/h)
車線数
通過予想時間(sec)(制限速度で移動した場合にかかる秒数)
車線数に関しては https://wiki.openstreetmap.org/wiki/JA:Key:lanes を、 一方通行に関しては https://wiki.openstreetmap.org/wiki/JA:Key:oneway をそれぞれ参照して自動で反映している。 ネットワークデータを細かく制御したい場合はGISソフトなどで編集した上でGeoJSON形式に変換し、後述のreadGeoJSONメソッドで読み込むことを推奨する。
各引数の意味は以下の通り:
fname : str 対象ファイルパス. プロジェクトの入力フォルダ(simulator.inputDirの値。通常はプロジェクトディレクトリのinputdefaultディレクトリ)からの相対パスで指定
lon0, lon1, lat0, lat1 : float 緯度経度のminmax
abs_path : bool Trueの場合、fnameを絶対パスで指定できるようになる。
r : float 経路地点の半径のデフォルト値 重なる場合は小さく調整される
proj : pyproj.Proj 緯度経度→座標の変換. Noneのとき恒等変換になる。地域ごとの設定種類については後述する。
margin : float 上下左右に設けるマージン[m]
highway: str 読み込む道路の種別を指定する。“car”で車道を、“walk”で人が歩ける道を、Noneを指定した場合は全ての道路を取得する。 具体的には、“car”においてはmotorway, trunk, primary, secondary, tertiary, motorway_link, trunk_link, primary_link, secondary_link, tertiary_link, unclassified, residential “walk”においてはtrunk, primary, secondary, tertiary, trunk_link, primary_link, secondary_link, tertiary_link, unclassified, residential, living_street, service, pedestrian, track, footway, steps, corridor, path の属性が付いた道路を取得する。 上記のようにカンマ区切りで取得する道路を列挙することでも指定できる。
maxspeed : str 制限速度(km/h)のデフォルト値。カンマ区切りで”motorway:60,trunk:50…“のように各道路種別ごとの値を指定する。
only_maximum_component : bool Trueにすると得られた道路ネットワークのうち最大の連結成分のみを抽出し、ネットワークが連結になるようにする。 (元々連結のときは何もしない)
weakly_connected : bool 上記連結性の判定の際、Trueであれば弱連結性、Falseのとき強連結性を基準にする
clear_cache : bool Trueのとき前回の計算結果ファイルが存在しても更新する
image_provider : str or None 文字列で背景種類を指定. “osm”, “std”, “pale”, “eng”, “photo”から選択できる. Noneの場合背景なし
zoomlevel : int 地図ズームレベル. 指定しない場合タイル数が20以内に収まる最大値に調整される(推奨)
平面直角座標の座標系は日本国内でも地域によって異なるため、projの値はシミュレーションしたい地域によって適切に指定する必要がある。 具体的には以下のように対応づけられる:
座標系 | EPSG表記 | 地域 |
---|---|---|
Japan Plane Rectangular CS I | EPSG:2443 | 長崎県 鹿児島県のうち北方北緯32度南方北緯27度西方東経128度18分東方東経130度を境界線とする区域内(奄美群島は東経130度13分までを含む。)にあるすべての島、小島、環礁及び岩礁 |
Japan Plane Rectangular CS II | EPSG:2444 | 福岡県 佐賀県 熊本県 大分県 宮崎県 鹿児島県(I系に規定する区域を除く。 |
Japan Plane Rectangular CS III | EPSG:2445 | 山口県 島根県 広島県 |
Japan Plane Rectangular CS IV | EPSG:2446 | 香川県 愛媛県 徳島県 高知県 |
Japan Plane Rectangular CS V | EPSG:2447 | 兵庫県 鳥取県 岡山県 |
Japan Plane Rectangular CS VI | EPSG:2448 | 京都府 大阪府 福井県 滋賀県 三重県 奈良県 和歌山県 |
Japan Plane Rectangular CS VII | EPSG:2449 | 石川県 富山県 岐阜県 愛知県 |
Japan Plane Rectangular CS VIII | EPSG:2450 | 新潟県 長野県 山梨県 静岡県 |
Japan Plane Rectangular CS IX | EPSG:2451 | 東京都(XIV系、XVIII系及びXIX系に規定する区域を除く。) 福島県 栃木県 茨城県 埼玉県 千葉県 群馬県 神奈川県 |
Japan Plane Rectangular CS X | EPSG:2452 | 青森県 秋田県 山形県 岩手県 宮城県 |
Japan Plane Rectangular CS XI | EPSG:2453 | 小樽市 函館市 伊達市 北斗市 北海道後志総合振興局の所管区域 北海道胆振総合振興局の所管区域のうち豊浦町、壮瞥町及び洞爺湖町 北海道渡島総合振興局の所管区域 北海道檜山振興局の所管区域 |
Japan Plane Rectangular CS XII | EPSG:2454 | 北海道(XI系及びXIII系に規定する区域を除く。) |
Japan Plane Rectangular CS XIII | EPSG:2455 | 北見市 帯広市 釧路市 網走市 根室市 北海道オホーツク総合振興局の所管区域のうち美幌町、津別町、斜里町、清里町、小清水町、訓子府町、置戸町、佐呂間町及び大空町 北海道十勝総合振興局の所管区域 北海道釧路総合振興局の所管区域 北海道根室振興局の所管区域 |
Japan Plane Rectangular CS XIV | EPSG:2456 | 東京都のうち北緯28度から南であり、かつ東経140度30分から東であり東経143度から西である区域 |
Japan Plane Rectangular CS XV | EPSG:2457 | 沖縄県のうち東経126度から東であり、かつ東経130度から西である区域 |
Japan Plane Rectangular CS XVI | EPSG:2458 | 沖縄県のうち東経126度から西である区域 |
Japan Plane Rectangular CS XVII | EPSG:2459 | 沖縄県のうち東経130度から東である区域 |
Japan Plane Rectangular CS XVIII | EPSG:2460 | 東京都のうち北緯28度から南であり、かつ東経140度30分から西である区域 |
Japan Plane Rectangular CS XIX | EPSG:2461 | 東京都のうち北緯28度から南であり、かつ東経143度から東である区域 |
※ 背景画像はOpenStreetMapや国土地理院からのデータを用いるため、これらを含んだ可視化を行う際は出典の表示が必要となる。 readOSM/readGeoJSONを行った場合は環境部品の「環境上のエージェントの可視化」においてデフォルトでこの表示を行うようになっている。 ユーザが可視化コードを書き換える場合、この部分を変更しないように注意すること。
microPedEnvironmentBase.readGeoJSONAsNetwork(self, fname, include_bb = False, abs_path=False, proj = “EPSG:2451”, encoding = “utf-8”, r = 0.5, margin = 1.0, epsilon = 1e-2, maxspeed=“motorway:60,trunk:50,primary:50,secondary:40,tertiary:30,motorway_link:40,trunk_link:40,primary_link:40,secondary_link:40,tertiary_link:30,residential:30,unclassfied:30,*:20”, only_maximum_component = True, weakly_connected=False, oneway_key=None, oneway_values=None, calc_connectivity=True **keys):
ローカルに保存してあるgeojsonファイルを読み込み、経路地点とエッジを抽出して経路グラフに設定する。
具体的には、geojsonファイルのPoint, LineStringタイプのオブジェクト(およびMultiPoint, MultiLineString)をそれぞれノード・エッジとするグラフを作る (必要に応じてLineStringオブジェクトの端点もノードに追加する)。 各オブジェクトの属性も経路グラフのノード・エッジの属性として保持する。
各引数の意味は以下の通り:
fname : str 対象ファイルパス. プロジェクトの入力フォルダ(simulator.inputDirの値。通常はプロジェクトディレクトリのinput/defaultディレクトリ)からの相対パスで指定
include_bb : bool Trueの場合、現在の移動可能領域のバウンディングボックスを含む形で新規の移動可能領域を形成する。基本的には readGeoJSONAsNetwork の呼び出し以前に set_bounding_box 等で空間設定を行っていた場合に、その設定を上書きしないためのスイッチである。
abs_path : bool Trueの場合、fnameを絶対パスで指定できるようになる。
proj : str or None 緯度経度の座標変換方式。pyproj.Projの初期化に渡る。Noneの場合恒等変換(座標変換しない)。具体的な指定方法についてはreadOSMメソッドの項を参照。
encoding : str geojsonファイルのエンコーディング
r : float 経路地点の半径のデフォルト値。重なる場合は小さく調整される
epsilon : float 座標値の許容誤差。epsilon以内の距離の点(point, lineの端点)はマージされる
margin : float 上下左右に設ける余白[m]
maxspeed : str 制限速度
only_maximum_component : bool Trueにすると得られた道路ネットワークのうち最大の連結成分のみを抽出し、ネットワークが連結になるようにする。 (元々連結のときは何もしない)
weakly_connected : bool 上記連結性の判定の際、Trueであれば弱連結性、Falseのとき強連結性を基準にする
oneway_key : str or None 片道通行のキー
oneway_values : str or list of str LineSringのattrにおいてoneway_keyの値がこの値(ないしこのリストに含まれる)場合に片道通行として扱う
calc_connectivity : bool Trueであれば連結性の処理を行い、Falseであればスキップする。
microPedEnvironmentBase.readGeoJSONAsUserDefinedRegion(self, fname, layername, abs_path=False, proj = “EPSG:2451”, encoding = “utf-8”, margin = 1.0 **keys):
ローカルに保存してあるgeojsonファイルを読み込み、ユーザー定義領域を抽出して経路グラフに設定する。
具体的には、geojsonファイルのPolygonタイプのオブジェクト(およびMultiPolygon)をユーザー定義領域とするグラフを作る。各オブジェクトの属性もユーザー定義領域の属性として保持する。
各引数の意味は以下の通り:
fname : str 対象ファイルパス. プロジェクトの入力フォルダ(simulator.inputDirの値。通常はプロジェクトディレクトリのinput/defaultディレクトリ)からの相対パスで指定
layername : str ユーザー定義領域を追加する新規レイヤー名を指定する。
abs_path : bool Trueの場合、fnameを絶対パスで指定できるようになる。
proj : str or None 緯度経度の座標変換方式。pyproj.Projの初期化に渡る。Noneの場合恒等変換(座標変換しない)。具体的な指定方法についてはreadOSMメソッドの項を参照。
encoding : str geojsonファイルのエンコーディング
margin : float 上下左右に設ける余白[m]
microPedEnvironmentBase.readGeoJSONAsActivityRegion(self, fname, as_obstacle = False, include_bb = False, abs_path=False, proj = “EPSG:2451”, encoding = “utf-8”, margin = 1.0 **keys):
ローカルに保存してあるgeojsonファイルを読み込み、移動可能領域を抽出して経路グラフに設定する。
具体的には、geojsonファイルのPolygonタイプのオブジェクト(およびMultiPolygon)を移動可能領域とするグラフを作る。各オブジェクトの属性も移動可能領域の属性として保持する。
各引数の意味は以下の通り:
fname : str 対象ファイルパス. プロジェクトの入力フォルダ(simulator.inputDirの値。通常はプロジェクトディレクトリのinput/defaultディレクトリ)からの相対パスで指定
as_obstacle : bool Trueの場合、壁として追加する。Falseの場合、空間として追加する。
include_bb : bool Trueの場合、現在の移動可能領域のバウンディングボックスを含む形で新規の移動可能領域を形成する。基本的には readGeoJSONAsActivityRegion の呼び出し以前に経路地点を追加していた場合に、それがエラー点にならないためのスイッチである。
abs_path : bool Trueの場合、fnameを絶対パスで指定できるようになる。
proj : str or None 緯度経度の座標変換方式。pyproj.Projの初期化に渡る。Noneの場合恒等変換(座標変換しない)。具体的な指定方法についてはreadOSMメソッドの項を参照。
encoding : str geojsonファイルのエンコーディング
margin : float 上下左右に設ける余白[m]
microPedEnvironmentBase.set_bounding_box(self, x0, x1, y0, y1, margin = 1.0, include_bb = False):
移動可能領域としてバウンディングボックスを設定する。 呼び出す以前の移動可能領域はリセットされる。
各引数の意味は以下の通り:
x0, x1, y0, y1 : float バウンディングボックスの座標値[m]
margin : float 上下左右に設けるマージン[m]
include_bb : bool Trueの場合、現在の移動可能領域のバウンディングボックスを含む形で新規の移動可能領域を形成する。
microPedEnvironmentBase.readGeoJSON(self, fname, abs_path=False, proj = “EPSG:2451”, encoding = “utf-8”, r = 0.5, margin = 1.0, epsilon = 1e-2, only_maximum_component = True, weakly_connected=False, oneway_key=None, oneway_values=None, image_provider=“osm”, **keys):
ローカルに保存してあるgeojsonファイルを読み込み、その道路ネットワーク情報を抽出して経路グラフに設定する。image_providerを指定した場合同時に背景画像も設定する。
具体的には、geojsonファイルのPoint, LineStringタイプのオブジェクト(およびMultiPoint, MultiLineString)をそれぞれノード・エッジとするグラフを作る (必要に応じてLineStringオブジェクトの端点もノードに追加する)。 各オブジェクトの属性も経路グラフのノード・エッジの属性として保持する。
各引数の意味は以下の通り:
fname : str 対象ファイルパス. プロジェクトの入力フォルダ(simulator.inputDirの値。通常はプロジェクトディレクトリのinput/defaultディレクトリ)からの相対パスで指定
abs_path : bool Trueの場合、fnameを絶対パスで指定できるようになる。
proj : str or None 緯度経度の座標変換方式。pyproj.Projの初期化に渡る。Noneの場合恒等変換(座標変換しない)。具体的な指定方法についてはreadOSMメソッドの項を参照。
encoding : str geojsonファイルのエンコーディング
r : float 経路地点の半径のデフォルト値。重なる場合は小さく調整される
epsilon : float 座標値の許容誤差。epsilon以内の距離の点(point, lineの端点)はマージされる
margin : float 上下左右に設ける余白[m]
only_maximum_component : bool Trueにすると得られた道路ネットワークのうち最大の連結成分のみを抽出し、ネットワークが連結になるようにする。 (元々連結のときは何もしない)
weakly_connected : bool 上記連結性の判定の際、Trueであれば弱連結性、Falseのとき強連結性を基準にする
oneway_key : str or None 片道通行のキー
oneway_values : str or list of str LineSringのattrにおいてoneway_keyの値がこの値(ないしこのリストに含まれる)場合に片道通行として扱う
image_provider : str or None 文字列で背景種類を指定. “osm”, “std”, “pale”, “eng”, “photo”から選択できる. Noneの場合背景なし
zoomlevel : int 地図ズームレベル. 指定しない場合タイル数が20以内に収まる最大値に自動調整される(推奨)
※ 背景画像はOpenStreetMapや国土地理院からのデータを用いるため、これらを含んだ可視化を行う際は出典の表示が必要となる。 readOSM/readGeoJSONを行った場合は環境部品の「環境上のエージェントの可視化」においてデフォルトでこの表示を行うようになっている。 ユーザが可視化コードを書き換える場合、この部分を変更しないように注意すること。
各種プロバイダからシミュレーション表示範囲の地図画像をダウンロードし、背景に設定する。 readGeoJSONやreadOSMから呼ばれるが、ユーザがこれを直接呼び出して背景画像を設定することも可能。
各引数の意味は以下の通り:
lon0, lat0, lon1, lat1 : float 緯度経度の上下限
zoomlevel : int 地図ズームレベル. 指定しない場合タイル数が20以内に収まる最大値に調整される
image_provider : str or None 文字列で背景種類を指定. “osm”, “std”, “pale”, “eng”, “photo”から選択できる. Noneの場合背景なし
※ 背景画像はOpenStreetMapや国土地理院からのデータを用いるため、これらを含んだ可視化を行う際は出典の表示が必要となる。 readOSM/readGeoJSONを行った場合は環境部品の「環境上のエージェントの可視化」においてデフォルトでこの表示を行うようになっている。 ユーザが可視化コードを書き換える場合、この部分を変更しないように注意すること。
レイヤー、ユーザー定義領域、経路地点、エッジ、属性テーブルはそれぞれクラス Layer, UserDefinedRegion, PathPoint, PathEdge, AttributeTable で表現される。 Layer は list を継承しており、各要素が UserDefinedRegion になっている。 PathPoint は int を継承しており、 sfmEnvironmentBase.pathgraph のノード番号として参照される。 PathEdge は tuple を継承しており、第一、第二要素がそれぞれ端点の PathPoint になっている。属性テーブルは dict を継承しており、属性名と属性値がそれぞれ key と value になっている。また、これらは下記に示す独自のメソッドも有している。下記以外の方法でこれらのオブジェクトを変更してはならない。
レイヤーの名前を返す。
レイヤーの名前を name にする。
領域の形状を表す多角形オブジェクトを返す。
領域の形状を表す多角形オブジェクトをセットする。
領域の属性辞書を返す。返り値は変更禁止。
既存の属性 attr に値 value をセットする。
領域が座標 (x, y) を含んでいれば True を、さもなくば False を返す。境界上の場合はどちらの値にもなりうる。
領域がグループなら True を、さもなくば False を返す。
グループを構成しているユーザー定義領域のリストを返す。
経路地点の座標をタプル形式 (x, y) で返す。
経路地点の座標をセットする。
経路地点の半径を返す。
経路地点の半径をセットする。
経路地点の属性辞書を返す。
既存の属性 attr に値 value をセットする。
エッジの両端の経路地点をタプル形式で返す。
エッジの属性辞書を返す。
既存の属性 attr に値 value をセットする。
属性 attr を追加し、デフォルト値を defaultValue とする。
既存の属性 attr にデフォルト値 defaultValue をセットする。
属性 attr を削除する。
ネットワークシミュレーションモデルは、ソーシャルフォースモデルよりも広範囲の人やモノ(=エージェント)の移動を大まかに再現するためのモデルある。 ネットワークはノードとそれらをつなぐエッジからなり、エージェントは出発地ノードから目的地ノードに向けてネットワークのエッジ上を移動する。
S4 では、エッジ密度(EdgeDensity)モデルと、Gipps モデルが実装されている。
ネットワークの作り方によってはノードは交差点を表す場合もあり、そのようなときはノードを通過するのに時間を要するのが自然である。 ノードに容量・通過時間を設けられており、エージェントはノードに到達すると次のノードに向かうまでに通過時間経過するまでそこで待機する。 また、ノード容量ぶんのエージェントがそのノードに存在する場合、エージェントはノードに入る前にその場で待機することになる。これは交差点が満員で侵入できない状況を表現できる。
通過時間・容量はNWAgentSetがパラメータとして持っており、NWAgentSetBase.setNodeInfo()から変更できるほか、NW環境部品からも編集可能。なお通過時間を0に設定すれば上記の処理は行われない。
ノードに信号を配置し、エッジからエッジへの移動を制限できる。上記のノード通過時間を経過したエージェントが次のエッジに移ろうとした時点で、信号が存在してかつ赤の場合は青になるまで停止する。 信号はSFMAgentSetのAPI(setSignalなど)から配置・設定できる。
施設の入り口が閉鎖されている状況を表現する。エッジに対して開・閉の時間を指定することができ、閉じているエッジにはエージェントは侵入できないようになり、境界のノードで停止する。 内部的には閉じているエッジは長さが十分大きいものとして扱われるので、通常は経路選択で回避されるが、そのエッジを通らないと目的地に到達できないような場合(施設の中に入りたい、等)は その手前のノードで停止することになる。設定はSFMAgentSetBase.setGateなどから行える。
目的地に到達したエージェントが、容量の決まった施設を一定時間利用することを表現する。 あらかじめノードに施設を配置しておき、利用したいエージェントがノードに到達すると、容量が空いていれば一定時間専有したのち開放し、空いていなければ空くまで待機する。 飲食店に並んで利用するような状況を表現できる。SFMEnvironmentBase.setFacility(name, capacity)で配置し、SFMAgentBase.setStaying(facility=name)として利用する。
上記の設定を行うAPIは環境・エージェント集合に定義されている。 なお信号・ゲート・施設利用に関してはSFM環境でも同様に利用することができる(そのためAPIはSFMEnvironmentやSFMAgentSetに定義されている)。
エッジ密度モデルは、自然なエージェントの移動・渋滞を表現するために以下の機能が備わっている:
速度計算エージェントの移動速度を周辺の人口密度から算出する。人口密度から移動速度の計算はデフォルトでは歩行者の移動速度モデルであるGreenbergの式によって行われるが、 NWエージェント部品の「エージェント速度の計算処理」から変更可能。
上記の人口密度は自身がいるサブエッジ(=エッジを数メートル単位で細かく分けたもの。分ける単位はパラメータで指定可能。 に存在するエージェント数とサブエッジの長さ・エッジ幅から算出される。この際、エージェントの移動方向ごとに別々に人口密度を求めるか、双方向を足し合わせて求めるかを指定できる。 このパラメータはNWAgentSetが持っており、NWAgentSetBase.setEdgeInfo()から変更できるほか、NW環境部品からも編集可能。例えば道路の車を考えるときは前者で、一本の歩道上の歩行者を考えるときは後者の設定を使うことになる。
前述したサブエッジごとに上限の人口密度が設けられており、上限に達しているサブエッジには後から来たエージェントは侵入できず、サブエッジ境界で停止する。 これが連鎖することで各サブエッジ境界にエージェントが溜まっていき、渋滞が実現する。 サブエッジの人口密度上限はNWAgentSetがパラメータとして持っており、NWAgentSetBase.setEdgeInfo()から変更できるほか、NW環境部品からも編集可能。
Gipps モデルは、車間が十分ある場合は加速し、先行車が近づくと減速するように定式化される。
定数 | 説明 | デフォルト値 |
---|---|---|
l | 車長(m) | 5m |
b | 減速加速度(m/s^2) | -3m/s^2 |
a_{{\tiny max}} | 最大加速度(m/s^2) | 1.5m/s^2 |
g_{{\tiny min}} | 最小車間距離(m) | 4m |
変数 | 説明 |
---|---|
x(t) | 車線上の車の位置(m) |
x_l(t) | 前車の位置(m) |
v_{{\tiny max}} | 最大速度(m/s) |
v(t) | 車速(m/s) |
v_l(t) | 前車の車速(m/s) |
車間が十分ある場合は、車速は v_{{\tiny max}} に漸近していく。
\begin{align} v^+(t+\Delta t) = v(t) + 2.5 \, a_{{\tiny max}} \Delta t \biggl(1 - \frac{v(t)}{v_{{\tiny max}}}\biggr) \sqrt{0.025 + \frac{v(t)}{v_{{\tiny max}}}} \nonumber \end{align}
一方で、車間が十分でない場合は、衝突を避けるため、前車との車間距離を g_{{\tiny min}} 以上を保つ。その時、追従車の速度は以下となる。
\begin{align} v^-(t+\Delta t) = b \Delta t + \sqrt{ (b \Delta t)^2 - b \bigl(x_l(t) - l - g_{{\tiny min}} - x(t)\bigr) - v(t) \Delta t - \frac{v_l(t)^ 2}{b}} \nonumber \end{align}
以上から、追従車の速度は、以下となる。
\begin{align} v(t+\Delta t) = \min \bigl\{ v^+(t+\Delta t), v^-(t+\Delta t) \bigr\} \nonumber \end{align}
ネットワークシミュレーション環境を生成する。引数はSFMと同様だが、ネットワークシミュレーション特有のものは以下である。
maxNum はエージェント最大同時出現数、 micromodel が 0 ならエッジ密度モデル、1 なら Gipps モデル、 subnodeIntval はサブエッジ長(m)、 edgeWidth はエッジ幅(m)、 isDirected が真のとき逆向きエッジで人口を足し合わせない、 nodeCapacity はノード容量、 nodeTime はノード通過時間(s)、 edgeThred はエッジ人口密度上限、 l は車長(m)、 b は減速加速度(m/s^2)、 amax は最大加速度(m/s^2)、 gmin は最小車間距離(m)である。
エージェントシミュレーションの中でも大規模交通シミュレーションは以下のような点で特殊性が高いため独立した機能として存在している。
以下にマクロ交通流モデルの機能概要を記載する。
以下の情報を csv 形式で読み込む。 道路ネットワーク情報は地図エディタで作成することも可能。
OD
start_time
: 発生開始時刻 (シミュレーション時刻)end_time
: 発生終了時刻 (シミュレーション時刻)src_link
: 出発リンクIDdst_link
: 目的リンクIDpopulation
: 期間中の合計発生台数の期待値via_link
: 経由リンク (|
区切りで指定した順に経由する)kind
: 車種
車種情報
kind
: 車種weight
: 密度計算時に使用される重みtheta
: selectNextNode
におけるパラメータ(大きいほど最短経路を嗜好)道路ネットワークのノード情報
lon
/ lat
: 経度 / 緯度道路ネットワークのリンク情報
from
/ to
: 上流ノード / 下流ノードlength
: リンク長 [km]
Kj
: ジャム密度 [台/km] (全車線合計)Qc
: 交通容量 [台/h] (全車線合計)Vf
: 自由流速度 [km/h]weight
: 合流比率
goal
: 目的地 or 経由地として設定されうるかどうか
道路ネットワークの進入禁止情報
from_link
/ to_link
: 上流リンク /
下流リンク
入力パラメータに従ってエージェントの生成・経路選択・移動処理を行う。
エージェントの生成
経路選択
エージェントの移動
出力として以下のファイルが得られる:
リンク単位の一定時間ごとの交通量を車種ごとに出力する。 network_log, network_sublink_log の2種類がある。
network_log は以下の列を持つ。
t
: シミュレーション時刻ID
: リンクIDinflow
: 流入量inflow
: 流出量travel_time
: 移動時間small_inflow_num
: 小型車流入量small_outflow_num
: 小型車流出量large_inflow_num
: 大型車流入量large_outflow_num
: 大型車流出量MOVE_count
: 移動中カウントWAIT_count
: 一時停止カウントSTAY_count
: 滞留カウントSTOP_count
: サブエッジ混雑による一時停止カウントSIGNAL_count
: 信号待ちカウントGATE_count
: 閉じたゲート待ちカウントnetwork_sublink_log は以下の列を持つ。 inflow 以降の列はサブリンク分割された表示となる。
t
: シミュレーション時刻ID
: リンクIDinflow
: 流入量inflow
: 流出量travel_time
: 移動時間small_inflow_num
: 小型車流入量small_outflow_num
: 小型車流出量large_inflow_num
: 大型車流入量large_outflow_num
: 大型車流出量inflow_demand
: 流入需要各リンク上の速度を出力する。 speed_log がある。
speed_log は以下の列を持つ。
t
: シミュレーション時刻ID
: リンクIDpresent
: 速度free
: 自由流速度各エージェントの出発時刻、到着時刻、通過リンク、通過時刻等を出力する。 movement_log がある。
movement_log は以下の列を持つ。
idx
: 添え字agent_id
: エージェントIDorigin_id
: 出発点IDorigin_time
: 出発時刻destination_id
: 到着点IDdestination_time
: 到着時刻route_time
: 途中の通過時刻route_edge
: 途中のリンクvia
: 中継is_reached
: 到着フラグエージェント集合を作成する。
このエージェント集合は、generateAgents が作成する複数のエージェントを管理する。
各エージェントは、環境 env に属す。
エージェント集合が属す環境を返す。
エージェント集合を構成するエージェントのリストを返す。
エージェント集合の作成後にこのメソッドが呼ばれる。
エージェント集合固有の初期化を行う。
もし、エージェント集合で固有の属性(エージェント全体で共有したい属性)がある場合は、このメソッド内で初期化を行う。
通常は、この処理の最後に、generateAgents メソッドを使って、エージェントの生成を行う。
エージェントを、n 個作成する。
*args, **keys は、各エージェントのコンストラクタに渡される。
エージェント agent を削除する。
エージェント集合に属すエージェントの中で、agent からの距離が、d 以内のエージェントのリストを返す。
widthDistance が True の場合は、距離とエージェントタプルのリストを返す。
agentの視野(位置pから方向visDirを向いた半角visThetaの扇形範囲)内に存在するエージェントidのリストを返す。pを与えない場合はagentの現在位置(agent.p)を用いる。withDistanceをTrueにすると距離とエージェントidのタプルのリストを返す。agent, withDistance以外の引数はagent.inSightSector()メソッドに渡される。
エージェント集合の動作を開始する。
エージェントを描画するスクリーンを返す。interval は描画間隔を指定する。xlim, ylim には、それぞれ x 軸と y 軸の表示範囲をタプルで指定する。title にはフレームの名前を指定する。size にはフレームのサイズをタプルで指定する。
エージェントの描画を開始する。
通常は以下のようなコードになる。
def view(self):
interval = 1 (表示間隔)
screen = self.getAgentScreen(interval = interval,
xlim = None, ylim = None)
screen.addAgentSet(self)
screen.start()
もし、表示を行いたくない場合は、以下のように空のメソッドにする。
同期エージェント集合を作成する。
このエージェント集合は、generateAgents が作成する複数のエージェントを管理する。
各エージェントは、環境 env に属す。
エージェント集合のステップ処理を行う。
非同期エージェント集合を作成する。
このエージェント集合は、generateAgents が作成する複数のエージェントを管理する。
各エージェントは、環境 env に属す。
注意 ソーシャルフォースモデルエージェント集合はミクロ人流エージェント集合に統合されました。 SFMAgentSetEnvironmentBaseクラスの機能はすべてMicroPedAgentSetBaseクラスを用いてご利用いただけますので、新たに作成されるモデルではMicroPedAgentSetBaseクラスをご利用ください。
Social Force Model エージェント集合を作成する。同期エージェント集合を継承している。
このエージェント集合は、generateAgents が作成する複数のエージェントを管理する。
各エージェントは、環境 env に属す。必ず env は、SFMEnvironmentBase のオブジェクトを指定しなくてはならない。
各ミクロ人流エージェントを、ミクロ人流環境のルール(SFMまたはFFM)に従って動かす。動かした後、各ミクロ人流エージェントのstep 関数を呼び出す。
エージェント集合に属すエージェントの中で、agent からの距離が、d 以内の可視なエージェントのリストを返す。weight は無視される。widthDistance が True の場合は、距離とエージェントタプルのリストを返す。
u->vのエッジを通行止めにする。dを指定した場合、内部的にエッジをその長さとして扱う。 既に閉じている場合は何もしない。
u->vのエッジの通行止めを解除する。dを指定した場合、内部的にエッジをその長さとして扱う。 既に開いている場合は何もしない。
エッジu->vのopen/closeGate()を計画的に実行する。 patternは辞書で{“open”: [t,..], “close”: [t,…]}のように指定することで、開/閉の時間を一括で指定できる。
エッジu->vからエッジv->wに遷移するときの信号を設定する。 green, yello, redで指定した秒数だけ信号が切り替わる。startで指定した時刻に青になったとする。 既に同じ箇所に信号が置かれている場合、上書きする。
上記で設定した信号を削除する。
次数4の頂点vに対してvを交差点とみなし、反対向き、交差する向きにまとめて設定する。 startに指定した時刻で(u,v)から(v,w)への信号が青になる。intervalで両方向とも赤の時間を設定する。
交差点を囲む4辺(u,v,w,z)に対して歩行者用信号を設定する。 startに指定した時刻で(u,v)に侵入する箇所の信号が青になる。intervalで両方向とも赤の時間を設定する。
辺(u,v)(uからvへの移動)を制限する信号を設定する。startに指定した時刻で(u,v)が渡れるようになる。directed=Falseだと双方向とも制限される
辺(u,v)から(v,w)に設置された信号のシミュレーション時刻tにおける色(“green”, “yellow”, “red”)を返す。t=Noneの場合現在時刻が使われる。
現在時刻tに対し、枝(u,v)から枝(v,w)に行くときの次の青信号までの待ち時間を返す。
座席をseats, 入口をentrances, 座席の容量をdefault_capacity, capacityで設定した待合室オブジェクトをnameの名前で作成する。 nameは文字列型である。seatsは座席にしたい経路地点のリストのリストである。entrancesは待合室の入口にしたい経路地点のリストである。 entrancesは経路地点のリストなのに対して、seatsは経路地点の2次元のリストであることに注意する。 default_capacityはint型であり正の整数である。この数値がseatsで指定した各座席経路地点に座席の容量として与えられる。指定しないとdefault_capacity=1で待合室を作成する。 capacityは辞書型である。キーは座席経路地点、値はint型であり正の整数である。default_capacityで座席経路地点の容量を一律の値で設定したのち、個別にcapacityで指定の座席経路地点の容量を設定する。
待合室オブジェクトは以下の変数を持つ。
seats座席経路地点のリストのリスト。
入口経路地点のリスト。
各座席の最大容量の辞書。キーが座席経路地点、値が容量。
各座席を利用している人数の辞書。キーが座席経路地点、値が利用人数。
エージェント集合がもっている待合室をキーが待合室名、値が待合室の辞書で返す。
3Dアニメーション表示の際のエージェントのプロファイル(見た目)を設定する。
各引数はつぎの項目を指定する。
agentidプロファイルを指定したいエージェントの固有ID
エージェントの3Dモデル種別を指定する。現行は 1 のみが指定できる。
見た目の性別を指定する。“m”(男性)または “f”(女性)を選ぶことができる。
エージェントの肌と髪の色を指定する。指定できる選択肢については後述する。
エージェントの服装を指定する。指定できる選択肢については後述する。
エージェントのプロファイルはappearance 引数の値に対して、指定できる skin および clothes の組み合わせが決まっている。組み合わせのリストをつぎに挙げる。
appearance = “m” の場合。
skin - “BrnSkin_BaldGoatee”
“DkBrnSkin_Beard”
“DkSkin_HairGoatee”
“FairSkin_Bald”
“FairSkin_BaldGoatee”
“FairSkin_GryHairBeard”
“FairSkin_HairDkBrn”
“LightTan_Bald”
“LightTan_BaldGoatee”
“LightTan_Hair”
“LightTan_HairBeard”
“Sallow_HairDkBrn”
“Tan_HairTash_Brown”
clothes - “Suit_Beige_Full”
“Suit_Beige_Open”
“Suit_Beige_ShirtOnly”
“Suit_BeigeBlue_Open”
“Suit_Black_Full”
“Suit_Blue_ShirtOnly”
“Suit_BlueRed_Casual”
“Suit_Brown_Full”
“Suit_LtGreenBlack_WaistcoatTie”
“Suit_Navy_NoTie”
“Suit_Navy_Open”
“Suit_PurpleBlack_WaistcoatTie”
“Suit_RedBlue_ShirtTie”
appearance = “f” の場合、clothes のタイプとして Skirt と Trouser があり、それぞれについて対応できる skin が決まっている。
Skirt タイプ
skin - “DarkBlack”
“DarkBlackShort”
“DkTanBlackBobbed”
“SoftTanLtBrown”
“TanBlack”
“WhiteBlonde”
clothes - “SkirtCasual_BeigeCream”
“SkirtCasual_BluePurple”
“SkirtCasual_Greens”
“SkirtSuit_BlackPink”
“SkirtSuit_LtBlueRed”
Trouser タイプ
skin - “BlackBobbed”
“CreamBrown”
“DarkTanBlackShort”
“LtTanBlonde”
“TanBrown”
“WhiteBlack”
clothes - “TrouserCasual_Beige”
“TrouserCasual_BlueBlack”
“TrouserCasual_Purple”
“TrouserSuit_BlueBalck”
“TrouserSuit_BlueWhite”
“TrouserSuit_GreenBlue”
“TrouserSuit_PinkBeige”
“TrouserSuit_RedBeige”
引数の文字列に誤りがあると3Dアニメーションへプロファイル設定が適切に反映されないので注意すること。
ネットワーク上を移動するエージェントをまとめるクラス。ミクロ人流エージェントの各メソッドを同じように使うことができる。
ネットワークエージェント集合の初期化を行う。
このエージェント集合は、generateAgents が作成する複数のエージェントを管理する。
各エージェントは、環境 env に属す。env は、NWEnvironmentBase のオブジェクトを指定しなくてはならない。
NWAgentSetBaseはSFMAgentSetBaseを継承しており、各メソッドを同じように使うことができるが、追加として以下のメソッドを持つ:
ノードnodeに容量capacityと通過時間timeを設定する。
エッジ(u,v)に幅・人口密度計算時の方向の有無・人口密度上限を設定する。
粒子フィルタエージェント集合を作成する。同期エージェント集合を継承している。
このエージェント集合は、generateAgentsが作成する複数のエージェントを管理する。
各エージェントは、環境envに属す。
monitorには、フィッティング対象となるデータをモニタまたは時系列モニタで指定する。データは時間列に関して昇順に並んでいる必要がある。 timecolumnには、monitorの時間列を列名または列番号で指定する。monitorに時系列モニタを指定した場合には無視される。
save_particle_historyがTrueの場合は、particleHistoryのモニタに粒子の状態が記録される。 save_associaton_historyがTrueの場合は、associateHistoryのモニタに対応付けの結果が記録される。 save_stats_historyがTrueの場合は、statsHistoryのモニタに粒子の状態の統計量が記録される。 各モニタを出力する際には、キーワード引数simulatorを初期化の際に与える必要がある。
エージェントが作成され、environment.initAttributeの呼出し後に、このメソッドが呼ばれる。
もし、エージェントごとに固有の属性がある場合は、このメソッド内で初期化を行う。
初期観測値はkeys[“observations”]に格納されている。
エージェントをn個作成する。また、各エージェントに対応する粒子群を作成する。
*args, **keysは、各エージェントのコンストラクタに渡される。
具体的には、次の処理が行われる。 1. n個のエージェントを生成して、エージェント集合に追加する。
n個のエージェントそれぞれについてmakeParticlesを呼び出し、粒子群particlesを作成する。作成の際には、キーワード引数observationに設定された初期観測値を使用する。
得られたparticlesについて次の状態を計算し、particles.nextStatesを更新する。
得られたparticlesをfilterに追加する。
エージェントagentを削除する。同時に、対応する粒子群もfilterから削除される。 既に粒子群が削除されていた場合には、エージェントの削除のみを行う。
粒子フィルタを表すssm.ParticleFilterのオブジェクトを返す。
フィッティング対象のデータを表すモニタまたは時系列モニタを返す。
粒子の状態を記録したモニタを返す。
初期化の際にsave_paritcle_historyをFalseとした場合にはNoneを返す。
モニタの形式は、8.3節 particleFilter.particleHistoryと同様である。
対応付けの結果を記録したモニタを返す。
初期化の際にsave_association_historyをFalseとした場合にはNoneを返す。
モニタの形式は、8.3節 particleFilter.associateHistoryと同様である。
粒子の状態の各統計量を記録したモニタを返す。
初期化の際にsave_stats_historyをFalseとした場合にはNoneを返す。
モニタの形式は、8.3節 particleFilter.statsHistoryと同様である。
エージェントを作成する。
このエージェントは、エージェント集合 agentset に属す。
ただし、通常はこのコンストラクタは呼ばれずに、エージェント集合の generateAgents メソッド経由で作成される。
エージェントの属すエージェント集合を返す。
エージェントが作成され、environmentBase.initAttribute の呼び出し後に、このメソッドが呼ばれる。
もし、エージェントごとに固有の属性がある場合は、このメソッド内で初期化を行う。
エージェントの環境上の位置属性を変更する場合は、このメソッドを呼ぶ。
通常は、environmentBase.setPosition が呼ばれる。
エージェントの環境上の位置属性を返す。
通常は、environmentBase.getPosition が呼ばれる。
エージェントの環境上のランダムな位置属性を返す。
通常は、environmentBase.getRandomPosition が呼ばれる。
エージェント集合に属すエージェントの中で、自身からの距離が、d 以内のエージェントのリストを返す。
widthDistance が True の場合は、距離とエージェントタプルのリストを返す。
通常は、environmentBase.findNeighborAgents が呼ばれる。
シミュレーション内でユニークなエージェント番号
エージェントスクリーンにこのエージェントが表示される時の色
エージェントスクリーンにこのエージェントが表示される時のサイズ
エージェントスクリーンにこのエージェントが表示される時のマーカー
エージェントスクリーンにこのエージェントが表示される時の不透明度
同期エージェントを作成する。
このエージェントは、エージェント集合 agentset に属す。
ただし、通常はこのコンストラクタは呼ばれずに、エージェント集合の generateAgents メソッド経由で作成される。
エージェントのステップ処理を行う。
非同期エージェントを作成する。
このエージェントは、エージェント集合 agentset に属す。
ただし、通常はこのコンストラクタは呼ばれずに、エージェント集合の generateAgents メソッド経由で作成される。
エージェントのプロセス処理を行う。
注意 ソーシャルフォースモデルエージェントはミクロ人流エージェントに統合されました。 SFMAgentBaseクラスの機能はすべてMicroPedAgentBaseクラスを用いてご利用いただけますので、新たに作成されるモデルではMicroPedAgentBaseクラスをご利用ください。
ミクロ人流エージェントを作成する。同期エージェントを継承している。
このエージェントは、エージェント集合 agentset に属す。
ただし、通常はこのコンストラクタは呼ばれずに、エージェント集合の generateAgents メソッド経由で作成される。
以下のキーワード引数が有効である。
p現在地
相互作用の強さ(N)
相互作用の範囲(m)
最適速度(m/s)
最高速度(m/s) ※FFMでは効果なし。FFMを選択した場合はlenEdge/エージェント集合のステップ間隔が最高速度となる
歩行者の半径(m)
※FFMでは効果なし。FFMを選択した場合はこの値ではなくlenEdge
の1/2として歩行者半径が描画される。
加速時間(s) ※FFMでは効果なし
体重(kg) ※FFMでは効果なし
外力の変動係数 ※FFMでは効果なし
視野制限距離(m) (0以下で制限なし)
視野仰角(degree)
経路計算方法(「TIM」「CMM」「PGM」から選ぶ)
滞留時の動作(“out”, “float”, “fix”, “return”から選ぶ。詳細はSFM環境の引数リストを参照)
上記引数はそのまま属性として保持される。
v速度ベクトル
視線方向
いずれの引数も、指定されなかった場合は環境オブジェクト(MicroPedEnvironmentBase)の値が利用される。
経路計算方法にTIMを選んだ場合、その他TIM経路計算時に用いられるパラメータ(後述)も指定できる。 指定できる経路探索手法およびそれらの概要は次のとおりである(節のSFM環境の項も参照)。
PGM (Path Graph Method)従来の経路グラフを用いた経路計算。高速だがエージェントの次の経路地点が不可視になった場合に再探索する必要がある。また、経路グラフの枝を設定する必要がある。
移動可能領域のボロノイ図を作り、領域中に得られる中線に沿って移動する経路を求める。エージェント自身の直径よりも狭い通路幅の通路は除いて経路計算を行う。経路地点に頼らず、任意の2点間の経路を求めることができる。経路グラフの枝を設定する必要がない。
CMMで経路を求めたうえで、最適化計算によって経路長の短いパスを求める(CMMは領域の中心を経路の基本とするため、不自然な大回りをする傾向がある)。 あらかじめ領域を離散化した各点と障害物までの距離を求めておいて、最適化の各ステップで障害物に近すぎない範囲で経路長が短くなるように更新が行われる。 CMM同様任意の2点間の経路を求めることができ、経路グラフの枝を必要としない。 また、経路計算後に左側通行/右側通行を指向する後処理を加えることができる。
経路計算法にTIMを用いた場合、MicroPedAgentBaseの初期化時に以下のパラメータを追加で与えることができる(カッコ内はデフォルト値を与える):
epsilonエージェントが障害物から保とうとする距離(1.0m)
領域を離散化する際の粒度(0.1m)
エージェントごとに経路をばらつかせるかどうかのフラグ(bool値)。デフォルトではFalse。Trueの場合経路長の短さ重視の解/もとのCMMの解の間でランダムに経路を選択するようになる。
片側通行するかどうか(False)。(片側通行に関するパラメータは、経路計算手法にCMMを選んだ場合も適用される。)
片側通行する際にどちらにずらすかのフラグ。True:左側通行、False:右側通行(True)。
片側通行を指向する際に、元の経路からその向きにずらす最大距離(1.0m)。デフォルトでは上記のepsilonと同じ値に設定される。
最適化計算時に経路長を短くする/障害物を回避する、のどちらを重視するかをコントロールするパラメータ。経路計算がうまくいかない(障害物を突き抜ける経路が頻繁に得られる)場合、この値を小さくする。
なお、これらの値はエージェントの他のパラメータと同様、MicrfoPedAgentBaseの初期化時に与えられていない場合は環境オブジェクトの値が利用される。
目的地を経路地点 v に設定する。methodの指定によって経路探索手法を切り替える。 methodが指定されない場合、エージェントの初期化時に指定された値を用いる(初期化時にも与えていない場合は、環境部品の値を用いる)。 座標pを指定した場合その点を起点として動作する。 delayedをTrueに設定した場合、現在までにdelayed=Trueで指定したsetStaying, setDestinaionの動作を全て終えたあとに今回指定する目的地設定が行われる。 delayedをFalseに設定した場合、今回指定する目的地設定が直ちに行われる(過去の指定はクリアされる)。
エージェントをその場でt秒間滞留させる。座標pを指定した場合エージェントをその点に移して停止させる。 facilityを指定した場合、その名前の資源をt秒間利用しおえるまでの間その場で待機する。 stayTypeは”out”, “float”, “fix”, “return”から指定できる(詳細はsfm環境の項を参照)。指定しない場合はエージェントに設定されたデフォルト値が用いられる。 delayedをTrueに設定した場合、現在までにdelayed=Trueで指定したsetStaying, setDestinaionの動作を全て終えたあとに今回指定する滞留が実行される。 delayedをFalseに設定した場合、今回指定する滞留が直ちに行われる(過去の指定はクリアされる)。
現在の目標経路地点を返す。設定されていない場合は None を返す。
transitListで与えた経路地点をmethodで指定した方法でエージェントを巡回させる。 巡回の際、stayTimeで指定した時間だけ各経路地点で滞留する。 transitListは経路地点のリストである必要がある。 stayTimeはint型かつ非負である。 methodは”ordered”, “random”から指定できる。 “ordered”を指定した場合、transitListで指定した経路地点の順番にエージェントを巡回させる。 “random”を指定した場合、transitListで指定した経路地点をランダムな順番で巡回させる。 methodはsetDestinationのキーワード引数であるmethodに相当する。 stayTypeはsetStayingのキーワード引数であるstayTypeに相当する。 stayingKwargsはキーが経路地点で値がsetStayingに渡すキーワード引数の辞書である。 エージェントが到達した経路地点ごとに滞留時間を変えたい場合や環境部品のsetFacilityで設定した資源を使いたい場合などに用いる。 stayTimeやstayTypeなど滞留に関するキーワード引数はstayingKwargsで指定したものが優先される。 delayedをTrueに設定した場合、現在までにdelayed=Trueで指定した動作を全て終えたあとに今回指定する巡回が実行される。 delayedをFalseに設定した場合、今回指定する巡回が直ちに行われる(過去の指定はクリアされる)。
patternで与えた経路地点間の遷移確率に従ってをエージェントをランダムに移動させる。 ある経路地点に到達した際にはstayTimeで指定した時間だけその経路地点で滞留する。 エージェントがgoalPointsを指定した経路地点に到達する、もしくはuntilで指定した時間が経過するとランダムな遷移を終える。 patternはキーが経路地点または経路地点のタプルで値が「キーが経路地点または経路地点のタプルで値がfloat型の辞書」の辞書である。 タプルを与えた場合、遷移が起こるたびにタプルのうちランダムな経路地点を選択してそこへ移動する。 startPointはpatternのキーのうちの1つである。 startPointが指定された場合、エージェントはstartPointまで移動してから遷移を開始する。 startPointが指定されない場合、エージェントの現在地がpatternのキーの経路地点のどこかに含まれる場合はその地点から遷移を開始する。 startPointが指定されていないかつ、エージェントの現在地がpatternのキーの経路地点のどれにも含まれない場合、patternのキーのうちランダムな地点まで移動してから遷移を開始する。 goalPointsはpatternのキーのリストである。 untilは数値型かつ非負である。 stayTimeはint型かつ非負である。 methodはsetDestinationのキーワード引数であるmethodに相当する。 stayTypeはsetStayingのキーワード引数であるstayTypeに相当する。 stayingKwargsはキーが経路地点で値がsetStayingに渡すキーワード引数の辞書である。 エージェントが到達した経路地点ごとに滞留時間を変えたい場合や環境部品のsetFacilityで設定した資源を使いたい場合などに用いる。 stayTimeやstayTypeなど滞留に関するキーワード引数はstayingKwargsで指定したものが優先される。 delayedをTrueに設定した場合、現在までにdelayed=Trueで指定した動作を全て終えたあとに今回指定する巡回が実行される。 delayedをFalseに設定した場合、今回指定する巡回が直ちに行われる(過去の指定はクリアされる)。
roomで指定した名前の待合室の座席に向かいそこでtで指定した秒数待機する動作を繰り返す。 roomは文字列型である。tはリスト型であり、各要素はint型かつ非負である。 entrance_howは文字列型であり、“nearest”, “random” のいずれかが指定できる。指定しないと”nearest”となる。 full_howはリスト型であり各要素は文字列型である。空き座席を見つける際に空き座席がなかった場合の動きを指定するオプション。リストの要素として”wait”, “forgo”, “error”が指定できる。“wait”とすると次の空き座席が見つかるまで現在いる入口または座席で待機、“forgo”とすると次の空き座席が見つからなかった場合待合室の移動を終了する。“error”とすると次の空き座席が見つからなかった場合エラー状態を返す。full_howに何も指定しないと”wait”が指定される。 seat_howはリスト型であり各要素は文字列型である。空き座席が見つかった後その空き座席をどのように決めるかを指定するオプション。リストの各要素として”nearest”, “random”, “custom”が指定できる。“nearest”とすると今いる場所から一番近い空き座席を選ぶ。“random”とすると空き座席の中からランダムに一つ選ぶ。“custom”とすると、seat_select_funcに与えた関数が呼び出されそれによって空き座席を一つ選ぶ。そのためseat_select_funcに与える関数は経路地点のリストを入力とし、その中の1つの経路地点を返す関数である必要がある。
この関数を実行した際の具体的なエージェントの動きを説明する。 待合室は主に入口を表す経路地点のリスト、経路地点を座席としてその座席のリストのリストである座席群、各座席の容量からなることに注意する。 この関数を実行するとまず、entrance_howで指定した方法でroomで指定した待合室の入口経路地点のリストから一つ入口経路地点を選びそこに向かう。 入口到着後その場で座席群の1番目の座席リストの各座席に対して空き容量を確認、空きがあればseat_howの1番目の要素で指定した方法で空き座席から一つ選びそこに向かう。空きがなければfull_howの1番目の要素で指定した方法で空きがない状態に対処する。その後空き座席に到着したらtの1番目の要素で指定した時間その座席で待機する。 待機終了後は座席群に2番目の座席のリストがあればその場で2番目の座席のリストの空き座席を確認し、空きがあればseat_howの2番目の要素で指定した方法で座席を選び向かう。空きがなければwait_howの2番目で指定した方法で空きがない状態に対処する。座席到着後はtの2番目の要素で指定した時間その座席で待機する。待機終了後は同様に座席群の座席リストに応じて空き座席確認、空き座席に向かい待機の動作を繰り返す。 したがってt, full_how, seat_howのリストの長さはroomで指定した待合室の座席リストの数に等しく指定する必要がある。
delayedをTrueに設定した場合、現在までにdelayed=Trueで指定した動作を全て終えたあとに今回指定する待合室への移動と座席での待機の動作が実行される。 delayedをFalseに設定した場合、今回指定する待合室への移動と座席での待機の動作が直ちに行われる(過去の指定はクリアされる)。
障害物上にいるかどうかを調べる。
座標p=(x, y)に最も近い可視な経路地点番号を近い順にnum個返す(num>=2のときは返り値がリストになる)。 座標値を指定しない場合、エージェントの現在地が使用される。visible=Falseのとき可視化どうかによらず近くの経路地点を求めて返す。 pを座標値ではなく緯度経度として与える場合はprojに射影方法を指定する。具体的な指定方法についてはreadOSMメソッドの項を参照。 return_distance=Trueの場合経路地点と距離のタプルを返す。
自身が経路地点 v の中かどうかを判定する。 p を指定した場合は、その座標点で判定する。
自身から経路地点 v が視野内にあるかどうかを判定する。 p を指定した場合は、その座標点で判定する。
自身から座標 p0 が視野内にあるかどうかを判定する。 p を指定した場合は、その座標点で判定する。 strict=False とすると障害物を格子に離散化した配列を用いて計算を行う。離散化に伴う誤差が生じるが、障害物の形状が複雑な場合はこちらのほうが高速に計算できる。
座標p0からpが視野(v方向を中心軸とする半角thetaの扇形)内にあるか判定する。strict = True だと厳密に判定し、False だと格子で粗く高速に判定する。
視野(位置pから方向visDirを向いた半角visThetaの扇形範囲)内部のエージェントidのリストを返す。withDistanceをTrueにすると距離とエージェントidのタプルのリストを返す。agent以外の引数はmicroPedAgentBase.inSightSector()メソッドに渡される。
経路地点 G へ向かうための次の経路地点を返す。 次の経路地点は視野内になくてはならない。 p が指定されている場合は、その座標点を起点とする。
デフォルトの実装では、p が経路地点 v 内である場合、以下の確率で次の経路地点 k を選択する。
P_k = \frac{\text{exp} \Bigl\{- \mu (d_{vk} + D_{kG}) \Bigr\}} {\sum_{(v, k') \in E}{\text{exp} \Bigl\{- \mu (d_{vk'} + D_{k'G}) \Bigr\} }}
ここで、E は経路グラフのエッジ集合、d_{uv} は経路地点 u から v の距離、D_{uv} は経路地点 u から v の最短距離、\mu はスケールパラメータである。\mu が大きくなると、ほぼ最適解を選ぶようになり、\mu が 0 に近づくと、最適でない解を選ぶ確率が増大する。
p がどの経路地点 v の内部点でない場合、以下の確率で次の経路地点 k を選択する。
P_k = \frac{\text{exp} \Bigl\{- \mu (||p_k - p|| + D_{kG}) \Bigr\}} {\sum_{k' \in S(p)}{\text{exp} \Bigl\{- \mu (||p_k' - p|| + D_{k'G}) \Bigr\} }}
ここで、S(p) は p から直線視野内にある経路地点の集合で、p_k は経路地点 k の座標である。
エージェントが停止状態か否かを返す。
エージェントがエラー状態か否かを返す。目的地に到達不能だった場合などに発生する。
自分からの距離が、d 以内の可視なエージェントのリストを返す。weight は無視される。widthDistance が True の場合は、距離とエージェントタプルのリストを返す。
SFM
では利用不可である。FFMの場合、posにはセル座標を整数値で設定することにより、そのセルにエージェントを再配置する。
NWEnvironmentBaseでも利用不可である。
agentの座標を返す。
FFMのみで利用可能である。agentの位置をセルインデックス(整数のタプル)で返す。
SFM では利用不可である。
3Dアニメーション表示の際のエージェントのプロファイル(見た目)を設定する。
各引数の詳細については、microPedAgentSetBase の項を参照。
ネットワーク上を移動するエージェントを表すクラス。ミクロ人流エージェントの基本的な属性・メソッドを共有している。 ただし、次の点が異なる:
加速時間tauは考慮しない(速度が不連続に変化する)。
ネットワーク上の移動状態を現す情報として以下の属性を持つ:
移動中エッジの経路地点(u,v)のペア
現在座標
現在座標を返す。
残りノード通過待ち時間
残り信号待ち時間
残り信号待ち時間
経路地点vに存在するかどうかを返す。
目的地を経路地点 v に設定する。 pとして経路地点番号を与えた場合、。 delayedをTrueに設定した場合、現在までにdelayed=Trueで指定したsetStaying, setDestinaionの動作を全て終えたあとに今回指定する目的地設定が行われる。 delayedをFalseに設定した場合、今回指定する目的地設定が直ちに行われる(過去の指定はクリアされる)。
なお、setStayingメソッドの引数p(滞留位置)についてはSFM同様に座標値で指定する:
エージェントをその場でt秒間滞留させる。座標pを指定した場合エージェントをその点に移して停止させる。 facilityを指定した場合、その名前の資源をt秒間利用しおえるまでの間その場で待機する。 stayTypeは”out”, “float”, “fix”, “return”から指定できる(詳細はsfm環境の項を参照)。指定しない場合はエージェントに設定されたデフォルト値が用いられる。 delayedをTrueに設定した場合、現在までにdelayed=Trueで指定したsetStaying, setDestinaionの動作を全て終えたあとに今回指定する滞留が実行される。 delayedをFalseに設定した場合、今回指定する滞留が直ちに行われる(過去の指定はクリアされる)。
粒子フィルタエージェントを作成する。同期エージェントを継承している。
このエージェントは、エージェント集合agentsetに属す。
ただし、通常はこのコンストラクタは呼ばれずに、エージェント集合のgenerateAgentsメソッド経由で作成される。
粒子群を生成する。
本メソッドは初期化処理initAfterの後に呼び出される。
observationには、生成に使用する観測値を1行からなるモニタで指定する。モニタの各列が観測値の各次元を表す。
返り値として、粒子群をあらわすクラスのオブジェクトを返すとする。このクラスを取得するためには、自身のエージェント集合がもつ_defParticlesメソッドを使用すればよい。
通常は以下のようなコードになる。
def makeParticles(self, observation):
AgentParticles = self.agentset._defParticles()
initial_states = ... (初期状態の生成)
return AgentParticles(initial_states, observation)
エージェントに対応した粒子群を表すssm.Particlesのオブジェクトを返す。
子スクリーンを追加する。rectOrScreen には、(left, bottom, right, top) の形式で指定する。各数値は 0 から 1 の間に正規化された値で、(0, 0, 1, 1) は全範囲を示す。zorder は描画順序を示す。数値が高い方が上に描画される。draw_once が True なら、ステップごとに再描画されない。
全てのスクリーンをクリアする。
全てのスクリーンを描画する。
スクリーンをクリアする。
軸を表示しない。
軸を表示する。
タイトル label を表示する。
x 軸のラベル label を表示する。
y 軸のラベル label を表示する。
x軸の範囲を xlim に設定する。xlim = (xmin, xmax) である。None を指定した場合は自動スケーリングになる。
y軸の範囲を ylim に設定する。ylim = (ymin, ymax) である。None を指定した場合は自動スケーリングになる。
名前 name のカラーマップを返す。
左下(left, bottom) から、幅 width, 高さ height の領域に、カラーマップ cmap のカラーバーを表示する。座標系は、左下が (0, 0)、右上が (1, 1) である。最小値が vmin で、最大値が vmax になる。向きは orientation で “vertical”/“horizontal” を指定する。カラーバーの最小値が vmin、最大値が vmax になる。
配列 data をスクリーン上にプロットする。cmap が指定された場合、data[x][y] は float(0 から 1) であり、cmap(data[x][y]) の色で描画される。cmap が None なら、data[x][y] は、(R, G, B) である。
(x0, y0) から (x1, y1) に線を描画する。 linewidth は線の太さ、color は色、linestyle は線種、cmap はカラーマップ, alpha は不透明度、zorder は描画順序を指定する。
points = [(x0, y0), (x1, y1), …, (xn, yn)] に線を描画する。 linewidth は線の太さ、color は色、linestyle は線種、cmap はカラーマップ, alpha は不透明度、zorder は描画順序を指定する。
(x, y) に marker を描画する。 size はサイズ、color は色、edgecolor はエッジの色、linewidth はエッジの太さ、cmap はカラーマップ, alpha は不透明度、zorder は描画順序を指定する。
(x, y) に文字列 s を描画する。 fontsize はフォントのサイズ、color は色、zorder は描画順序を指定する。
(x, y) を起点とする矢印を描画する。(dx, dy) は、向きと長さを示す。width は矢印の太さを示す。 edgecolor はエッジの色、color は中身の色、linewidth は線の太さ、cmap はカラーマップ、alpha は不透明度、zorder は描画順序を指定する。
(x, y) を中心とする楕円を描画する。width は水平方向の直径、height は垂直方向の直径、angle は回転角(反時計回り)を度で示す。 edgecolor はエッジの色、color は中身の色、linewidth は線の太さ、cmap はカラーマップ、alpha は不透明度、zorder は描画順序を指定する。
points で構成される多角形を描画する。closed が真なら、points の最後と最初の点をつなぐ。 edgecolor はエッジの色、color は中身の色、linewidth は線の太さ、cmap はカラーマップ、alpha は不透明度、zorder は描画順序を指定する。
左下が (x, y) の長方形を描画する。width は幅、height は高さを示す。 edgecolor はエッジの色、color は中身の色、linewidth は線の太さ、cmap はカラーマップ、alpha は不透明度、zorder は描画順序を指定する。
スクリーンを描画する。
color には以下が指定できる。
“b”: blue
“g”: green
“r”: red
“c”: cyan
“m”: magenta
“y”: yellow
“k”: black
“w”: white
“#RRGGBB”
(R, G, B): (float, float, float)
linestyle には、以下が指定できる。
“solid”/“dashed”/“dashdot”/“dotted”
“-”/“–”/“-.”/“:”
marker には以下が指定できる。
“8”: octagon
“d”: thin_diamond
“<
”: triangle_left
“h”: hexagon1
“+”: plus
“o”: circle
“p”: pentagon
“s”: square
“v”: triangle_down
“x”: x
“`^’”: triangle_up
“>
”: triangle_right
S4 Simulation System にてエージェントベースモデリングをする際に、同期エージェントを記述時に、状態遷移が複雑であったり、状態の遷移に複数ステップかかる場合、ロジックの記述が非常に難しくなる。そのような際に、エージェントプラナーが利用可能である。
planner は、同期型のエージェントの行動計画スケジューラである。
基本的には、プラナー、プロセス、タスク、状態 の 4 階層で表わされる。
プラナー
概要: エージェントの行動計画スケジューラ。
内容: 優先順位のつけられた複数のプロセスを持つ。
動作: 実行すると、保持する全てのプロセスを優先順位順に実行する。
操作: プロセスを動的に追加、削除できる。
プロセス
概要: エージェントの目標を達成するために必要なタスクをスケジューリングする。それぞれのプロセスは独立に並行実行可能である。
内容: 優先順位のつけられた複数のタスクを持つ。
動作: 実行すると、保持するタスクを優先順位順に実行する。あるタスクにて、現ステップでの実行を終了する特殊な状態(TICK(skip=True))が実行されたら、実行を停止する。
操作: タスクを動的に追加、削除できる。
タスク
概要: プロセスを構成する、個々の行動単位を表す。
内容: 現在実行中の継続状態を持つ。
動作: 実行すると、保持している継続状態を実行する。その結果によって、自身の継続状態が差し替えられる。時間経過を示す特殊な状態(TICK)が実行されるまで、実行を繰り返す。
操作: 継続状態は、実行結果によって自動的に差し替えられる。
状態
概要: タスクの状態を表す。
内容: 優先順位のつけられた複数の「条件とアクションと継続状態」の組を持つ。
動作: 条件が成立すればアクションを実行し、タスクに継続状態を返す。
操作: 状態の定義は、Python の関数の形式で行う。
非同期型のプロセススケジューラは、以下のように動作する。
各プロセスは、非同期に発生する可能性のあるイベントを待ち受ける。イベントが発生するまでは何もしない。
例: (非同期版) event を待ち受け、evnet が発生したら ``event fired’’ を表示する。
一方で、同期型のプロセススケジューラは、以下のように動作する。
各プロセスは、各ステップごとにイベントが発生しているかどうかをポーリングする。
例: (同期版) event を待ち受け、evnet が発生したら ``event fired’’ を表示する。
def proc():
if len(events) > 0:
event.pop(0)
print("event fired")
process = planner.add()
process.add(proc)()
while True:
planner.step()
ステップが進む
プラナーはエージェントの行動計画スケジューラである。優先順位のつけられた複数のプロセスを持つ。実行すると、保持する全てのプロセスを優先順位順に実行する。プロセスを動的に追加、削除できる。
プラナーを作成する。名前は name となる。
プラナー上にプロセスを作成し、プロセスを返す。プロセスの名前は name、優先度は priority となる。
プラナーから、名前が name のプロセスを削除する。存在しない場合は何もしない。
プラナーが保持しているプロセスのイテレータを返す。順番は保証されない。
プラナー上の全てのプロセスをステップ実行する。実行順は、優先度に従う。
プロセスは、エージェントの目標を達成するために必要なタスクをスケジューリングする。それぞれのプロセスは独立に並行実行可能である。優先順位のつけられた複数のタスクを持つ。実行すると、保持するタスクを優先順位順に実行する。あるタスクにて、現ステップでの実行を終了する特殊な状態(TICK(skip=True))が実行されたら、実行を停止する。タスクを動的に追加、削除できる。
プロセス上に、タスクを追加し、タスクを返す。func には、初期状態定義関数名を指定する。タスクの名前は、name、優先度は priority となる。args, keys は、func の引数に渡される。
プロセスから、名前が name のタスクを削除する。存在しない場合は何もしない。
プロセスが保持しているタスクのイテレータを返す。順番は保証されない。
プロセスの名前を返す。
プロセスの優先度を返す。
プロセス上の全てのタスクをステップ実行する。実行順は、優先度に従う。ただし、特殊な継続状態 tick が呼ばれたら、残りのタスクは実行されない事もある。
タスクは、プロセスを構成する、個々の行動単位を表す。現在実行中の継続状態を持つ。実行すると、保持している継続状態を実行する。その結果によって、自身の継続状態が差し替えられる。時間経過を示す特殊な状態(TICK)が実行されるまで、実行を繰り返す。継続状態は、実行結果によって自動的に差し替えられる。
タスクの名前を返す。
タスクの優先度を返す。
タスクの保持する状態を実行する。
状態は、タスクの状態を表す。優先順位のつけられた複数の「条件とアクションと継続状態」の組を持つ。条件が成立すればアクションを実行し、タスクに継続状態を返す。状態の定義は、Python の関数の形式で行う。
状態は Python の関数として、以下のように定義する。
def 状態(...):
if 条件1():
アクション1()
return 継続状態1()
elif 条件2():
アクション2()
return 継続状態2()
...
else:
アクションn()
return 継続状態n()
状態は、「条件とアクションと継続状態」の組を、Python の構文に従って定義される。
継続状態は、次に実行すべき状態を示し、以下のような形式で指定する事ができる。
STATE(状態定義関数名)(*args, **keys)
単一の継続状態を作成する。状態を実行するタイミングで実体化される。
(継続状態_1, 継続状態_2, …, 継続状態_n)
逐次実行する継続状態の列。
最初に、継続状態_1 が実体化される。その時、継続状態_n (n > 1) は実体化されていない。
継続状態_i が完了すると、継続状態_{i+1} が実体化される。
None
継続状態が無い事を示す。状態定義関数で None を返した場合、そのタスクは完了した事を示す。
REPEAT()
特殊な継続状態で、自身を示す継続状態を示す。
TICK(step = 1, skip = False)
特殊な継続状態で、step 時間後に完了する。現ステップでのこのタスクの実行を停止する。skip が True の場合は、このタスクを実行したプロセスの残りのタスクの実行も停止する。skip が False の場合は、遺りのタスクの実行を行う。step 時間後まで、このタスクはブロックする。
空間
ランダムに作成されたグラフ空間。
5 つのエリアがある。
それぞれのエリアは、50 ノード、100エッジの連結ランダムグラフ。
各エリアにはひとつの入口ノードがあり、各入口ノードは、必ず接続されている。(つまり、全体でも連結グラフになる)
エリア内には施設がランダムに配置される。
願望、エリア、施設
エージェントはランダムな複数の願望を持つ。
エージェントが施設に訪れる事で、ある願望を満す。
空間には、幾つか地図があり、地図では、以下の情報が得られる。
エリアの位置とエリア内の施設情報(及び、どのような願望を満す施設かであるかの情報
エリア内の各施設の位置情報
エージェントの行動
基本動作
エージェントは次に満すべき願望を選択する。
願望を満すためのエリアを知っているなら、そのエリアに向かって移動する。(知らないなら、ランダムウォークする)
エリアに到着したら、願望を満す施設を探す。
願望を満すための施設を知っているなら、その施設に向かって移動する。(知らないなら、エリア内をランダムウォークする)
施設に到着したら、次の願望を選択する。
観測動作
エージェントは移動するごとに、空間に設定された施設情報を学習する。
スケジュールされた動作
プロセスがふたつある。
メインプロセス
観測プロセス
メインプロセスには、ふたつのタスクがある。
基本タスク
予定実行タスク
基本タスクは、エージェントが願望を満すように行動するルールが定められている。
予定実行タスクは、指定時間に帰宅動作に切り換えるようなルールが定められている。
予定実行タスクの優先度が高い。予定実行タスクが開始したら、基本タスクは実行されない。
観測タスクは、メインプロセスとは独立な観測プロセスにて実行される。
def __init__(self):
self.planner = Planner()
self.proc1 = self.planner.add("main")
self.proc1.add(self.choosing_next_desire)()
self.proc1.add(self.going_to_node, priority = 10)(
50, goal_node)
self.proc2 = self.planner.add("observing")
self.proc2.add(self.observing)()
サブ状態
def walking_around(self):
self.position = random.choice(graph.neighbors(self.position))
return TICK()
def walking_around_in_area(self):
self.position = random.choice(graph.neighbors(self.position))
while True:
self.position = random.choice(graph.neighbors(
self.position))
if graph.node[self.position]["area"] == self.goal_area:
break
return TICK()
def walking_to_position(self, dest):
path = networkx.shortest_path(graph, self.position, dest)
self.position = path[1]
return TICK()
基本タスク
def choosing_next_desire(self):
self.goal_desire = random.choice(self.desire_list)
self.goal_area = None
self.goal_facility = None
return STATE(self.archiving_desire)()
def archiving_desire(self):
areas = self.known_areas.get(self.goal_desire, [])
if len(areas) > 0:
self.goal_area = random.choice(list(areas))
return STATE(self.going_to_area)()
else:
return STATE(self.walking_around)(), REPEAT()
def going_to_area(self):
if graph.node[self.position]["area"] == self.goal_area:
return STATE(self.looking_for_facility)()
else:
return STATE(self.walking_to_position)(
area_entrance[self.goal_area]), REPEAT()
def looking_for_facility(self):
try:
vs = self.known_facilities[self.goal_area][
self.goal_desire]
except:
vs = []
if len(vs) > 0:
self.goal_facility = random.choice(list(vs))
return STATE(self.going_to_facility)()
else:
return STATE(self.walking_around_in_area)(), REPEAT()
def going_to_facility(self):
if self.position == self.goal_facility:
return STATE(self.using_facility)(), STATE(
self.choosing_next_desire)()
else:
return STATE(self.walking_to_position)(
self.goal_facility), REPEAT()
return TICK(10)
予定実行タスク
def going_to_node(self, time, dest):
if now[0] < time:
return TICK(), REPEAT(priority = 10)
else:
if self.position == dest:
self.planner.remove("main")
self.planner.remove("observing")
return None
else:
path = networkx.shortest_path(
graph, self.position, dest)
self.position = path[1]
return TICK(skip = True), REPEAT()
観測タスク
def observing(self):
print("goal (desire: %s, area: %s, facility: %s), %s" % (
self.goal_desire, self.goal_area, self.goal_facility,
self.position))
if "facility-ad" in graph.node[self.position]:
area, facilities = graph.node[self.position][
"facility-ad"]
for v, desire in facilities:
self.known_facilities.setdefault(area, {})
self.known_facilities[area].setdefault(
desire, set())
self.known_facilities[area][desire].add(v)
if "area-ad" in graph.node[self.position]:
for desire, areas in desire2areas.iteritems():
self.known_areas.setdefault(desire, set())
for area in areas:
self.known_areas[desire].add(area)
return TICK(), REPEAT()
state1 に入ると、action を実行し、state2 に遷移する。
もし、この遷移に時間を要する場合は、以下のように TICK() を入れる必要がある。
TICK() があると、このタスクのこのステップでの実行は完了する。(他のタスクがある場合は、それぞれ実行される)
ある条件が成立するまで待ち受けるようなパターンは、このように書く。自分に戻る時は、通常、TICK() が入る。これがないと、無限ループになる。
次に遷移する状態がない、つまり、タスクが完了する場合、None を返す。python の仕様上、何も返さなければ return None と同一の意味を持つ。
サブ状態は、別の状態から再帰的に呼び出される状態の事である。コンテキストが違うだけで、サブ状態も状態である。
上の substate は、subaction を実行した後に完了するサブ状態である。
サブ状態もまた、複数の状態を持っても構わない。TICK() のように時間経過をするような処理が入る場合もある。
サブ状態は、複数の状態から呼び出される可能性がある場合に、非常に便利である。通常、メインの状態遷移は複数の状態の有向グラフの形で表現される。サブ状態もまた、入口と出口の定義された有向グラフであるが、入口と出口は他の状態と動的に結合される。
def substate():
subaction()
return None
def state1():
action()
return STATE(substate)(), STATE(state2)()
サブ状態は、別の状態から再帰的に呼び出される状態の事である。
上の例では、state1 に入ると、substate 状態の実行後に、state2 に遷移する。
サブ状態もまた、複数の状態を持っても構わない。TICK() のように時間経過をするような処理が入る場合もある。
一般的には、サブ状態のリストを指定する事で、より複雑な手順を指定する事も出来る。
サブ状態のリストを指定する事で、複雑な手順も指定できるが、より複雑な場合は、別タスクを起動し、イベントドリブン(毎ステップ監視)式に記述したり、動的にタスクを起動する必要がある。
この例では、ある条件 condition() が成立するまで待ち受け、成立したら state2 に遷移するタスクを登録している。
condition の中では、時間や環境などを観測したり、自分、あるいは、他のエージェントからのインタラクションなどを観測する。
同一プロセス内に複数のタスクを起動する場合、優先度が重要になる。優先度の低いタスクの実行をキャンセルしたい場合は、TICK(skip = True) とする。skip が真なら、このタスクを実行したプロセスの残りのタスクの実行も停止する。skip はデフォルトでは 偽である。
並行に動作するタスクが複数ある場合、
ひとつのプロセスに複数のタスクを走らせる
複数のプロセスで各タスクを走らせる
の選択肢がある。
タスクに優先度があり、各ステップにて、優先度の高いタスクのみを実行したい場合、前者のような設計にするのが良い。
完全に独立に動作するタスクの場合は、後者のような設計にするのが良い。
2 章のシミュレーション記述を用いれば様々なシミュレーションを記述する事が出来るが、より大規模で複雑なシミュレーションをフローベースで記述するためのフレームワークが用意されている。このフレームワークは、部品、ポート、リンク、フローアイテムなどを組み合わせる事で簡単にシミュレーションを記述出来るような仕組みを提供する。S4 Simulation System で自動生成されるコードはこのフレームワークを利用している。
シミュレーションパラメータ param のシミュレーターを作成する。入力フォルダを inputDir、出力フォルダを outputDir に指定する。until には until(self) がシミュレーション終了時間になるような lambda 式を指定する。SimulatorBase は基底クラスであり必ず継承して使う。
シミュレーションを開始する。
登録されている全てのモニターを出力する。
様々なパラメータでシミュレーションを行う一括実行シミュレーターを作成する。simcls にはシミュレータークラス名を指定し、paramcls にはパラメータクラス名を指定する。inputDir, outputDir にはそれぞれ、入力フォルダ、出力フォルダを指定する。iters は、各要素がパラメータ名、列の型、動かす範囲(g)で構成されるリストである。g(simulator)はジェネレータであり、そのジェネレータの生成する値の組み合わせを全て実行する。ただし実行回数は最大で maxcount(simulator) 回までとなる。outputs は、各要素が列名、列の型、式(expression)で構成されるリストである。expression(simulator) で求まる結果が指定した列に記録される。各シミュレーションの終了時間は until(simulator)となる。一括実行を行うと、出力フォルダに「一括実行結果」という名前のモニターが出力される。
シミュレーションで使うパラメータを作成する。シミュレーションパラメータは任意個のメンバーを持ち、シミュレーター内の部品はそれらのメンバーをシミュレーションパラメータとして参照する。一括実行する時は、指定したパラメータを指定した範囲動かしシミュレーションを行うが、指定しなかったパラメータは毎回初期化される。
部品の作成する。parent にはシミュレーターを指定する。Widget は基底クラスであり必ず継承して使う。
モニターを登録する。
部品の動作定義。
部品の起動する。
名前が name のフローアイテムを作成する。param にはシミュレーションパラメータを指定する。keys に指定した任意個の属性名と属性値を持つ。
フローアイテムの属性名のリストを返す。
フローアイテムにタグ tag で記録された時間を取得する
フローアイテムにタグ tag の時間に time を設定する。
フローアイテムのリスト items から構成されるフローアイテムリストを作成する。name には名前を指定する。keys に指定した任意個の属性名と属性値を持つ。フローアイテムと Python の list オブジェクトを継承しており、フローアイテムの操作と list に対する全ての操作を行う事が出来る。
出力ポート outport と入力ポート inport をリンクで結ぶ。
部品 parent に名前 name の出力ポートを作成する。キューサイズは size となり、セレクタは selector となる。save が真ならキューの変化を記録し、シミュレーション終了後に出力される。
出力ポートからフローアイテム item を出力する。出力ポートにキューがない場合は、セレクタによってリンクが選ばれ、リンクの先の入力ポートキューに追加するような名前 name の待ち受けを行う。出力ポートにキューがある場合は、出力ポートキューに追加するような待ち受けを行う。
部品 parent に名前 name の入力ポートを作成する。キューサイズは size となり、セレクタは selector となる。save が真ならキューの変化を記録し、シミュレーション終了後に出力される。init 引数には値と優先度からなるタプルのリスト [(値1, 優先度1), (値2, 優先度2), …] を指定する事が出来る。空リストでない場合、シミュレーション開始時に各要素に対し、入力ポートのキューに対し store.put1(値, priority = 優先度) が実行される。キューサイズ以上の要素を指定した場合、追加キューに並ぶ。
入力ポートからフローアイテムを入力する。入力ポートと出力ポートにキューがない場合は、入力ポートキューからフローアイテムを取得するような名前 name の待ち受けを行う。入力ポートにキューがなく、出力ポートにキューがある場合は、セレクタによってリンクを選び、リンクの先の出力ポートからフローアイテムを取得するような名前 name の待ち受けを行う。入力ポートにキューがない場合は、入力ポートのキューからフローアイテムを取得するような名前 name の待ち受けを行う。
入力ポートのセレクタの場合、その入力ポートに入力する複数のリンク\{L_i\}\quad(1 \le i \le n)から、セレクタはひとつのL_kを選択し、そのリンクの先の出力ポートからフローアイテムを入力する。
出力ポートのセレクタの場合、その出力ポートから出力する複数のリンク\{L_i\}\quad(1 \le i \le n)から、セレクタはひとつのL_kを選択し、そのリンクの先の入力ポートへフローアイテムを出力する。
確率P(L_i)=1/nでリンクL_iを選ぶセレクタ。
確率的にリンクを選ぶセレクタ。weights には重みリストを指定する。重みは 0 以上でなくてはならない。重みを \{w_i\}とすると、確率P(L_i)=w_i/\sum{w_i}でリンクL_iを選ぶ。
順番にリンクを選択するセレクタ。セレクタが呼ばれた回数を k ($ )とすると k 番目にリンクL_j, j = ((k-1) n) + 1$ を選ぶ。
常に指定されたリンクを選ぶセレクタ。
リンクの先のポートのキューが最も少ないリンクを選ぶセレクタ。最小キューサイズのリンクが複数ある場合は、セレクタが呼ばれた回数を k ($ $)とし、最小キューサイズのリンクのインデックス集合を \{a_i\}とすると、リンク L_{a_m}, m = \text{arg}\,\min_{i}{((k - a_i + 1) \bmod n)} を選択する。
強化学習によりリンクを選ぶセレクタ。model には利用する強化学習モデルに対応する RLModelSet のオブジェクトを指定する。 linklist は行動とリンクの対応をあらわすリストである。 linklist[i] に i 番目の行動に対応するリンクの番号(0 以上 n-1 以下)が格納されているとする。 idfunc はフローアイテムを引数にとり、強化学習におけるエピソードを区別する文字列を返す関数である。 async_reward は即時報酬計算のタイミングをずらすかどうかをあらわす真偽値である。 reward_func_nameは即時報酬計算のタイミングをずらす際に報酬決定関数をフローアイテムの属性に設定する際の属性名をあらわす名前である。
シミュレーション内での様々な変数を観測するために、モニターと時系列モニターがある。モニターは、任意の観測結果を記録するために用いる。時系列モニターは、任意の時間変動するパラメータの時系列変動を記録するために用いる事が出来る。
モニターは、任意の観測結果を記録するために用いる。複数のパラメータを同時に記録する事が出来る。m 個のパラメータセットを、n 回観測した結果は以下のようになる。
text{パラメータ}_0 | text{パラメータ}_1 | \cdots | text{パラメータ}_{m-1} | |
---|---|---|---|---|
text{観測}_0 | X_{0,0} | X_{0,1} | \cdots | X_{0,m-1} |
text{観測}_1 | X_{1,0} | X_{1,1} | \cdots | X_{1,m-1} |
\vdots | \vdots | \vdots | \ddots | \vdots |
text{観測}_{n-1} | X_{n-1,0} | X_{n-1,1} | \cdots | X_{n-1,m-1} |
モニターを作成する。cols にはパラメータ名のリストを指定する。types には、各パラメータの型名のリストを指定する。型名には “f”, “i”, “o” を指定する事が出来る。types が省略された場合、全てのパラメータは “f” 型である事を意味する。types を明示的に指定する場合は、指定個数はパラメータ数と一致しなくてはならない。name はモニターの名前を指定する。basedir を指定した場合、ディレクトリ basedir から名前 nameのモニターをロードする。その場合、cols, types は指定しない。
モニターに観測結果を追加する。values の個数は、モニターのパラメータ数と一致しなくてはならない。
時系列モニター は、時間変動するパラメータの時系列変動を記録する事が出来る。現時刻と、複数のパラメータを同時に記録する事が出来る。m 個のパラメータセットを、n 回観測した結果は以下のようになる。
時刻 | text{パラメータ}_0 | text{パラメータ}_1 | \cdots | text{パラメータ}_{m-1} | |
---|---|---|---|---|---|
text{観測}_0 | t_0 | X_{0,0} | X_{0,1} | \cdots | X_{0,m-1} |
text{観測}_1 | t_1 | X_{1,0} | X_{1,1} | \cdots | X_{1,m-1} |
\vdots | \vdots | \vdots | \vdots | \ddots | \vdots |
text{観測}_{n-1} | t_{n-1} | X_{n-1,0} | X_{n-1,1} | \cdots | X_{n-1,m-1} |
時系列モニターを作成する。cols にはパラメータ名のリストを指定する。types には、各パラメータの型名のリストを指定する。型名には “f”, “i”,“o” を指定する事が出来る。types が省略された場合、全てのパラメータは”f” 型である事を意味する。types を明示的に指定する場合は、指定個数はパラメータ数と一致しなくてはならない。name は時系列モニターの名前を指定する。basedir を指定した場合、ディレクトリ basedir から名前 nameの 時系列モニターをロードする。その場合、cols, types は指定しない。
時系列モニターに観測結果を追加する。time は時刻を指定する。必ず昇順でなくてはならない。通常は now() を指定する。values の個数は、時系列モニターのパラメータ数と一致しなくてはならない。
モニター,時系列モニターは、複数の観測列で構成されるが、各観測列の型には、以下が用意されている。型名はモニター,時系列モニターで指定する型名である。
型名 | 要素の型 |
---|---|
“f” | 浮動小数点型 |
“i” | 整数型 |
“o” | 文字列型 |
モニターからパラメータ名で示される観測列を取得する。存在しないパラメータの場合はエラーとなる。複数存在するパラメーター名の場合、列番号の小さなものとなる。取得した観測列は、モニターの観測列のコピーである。
モニターから i 番目の観測列を取得する。存在しない列番号の場合はエラーとなる。負の数が指定された場合は(観測列数 + i) 列を意味する。取得した観測列は、モニターの観測列のコピーである。
いずれの方法で取得しても、取得した観測列は、モニターの観測列のコピーである。つまり、取得した観測列に変更を加えても、元のモニターは変更されない。ただし、取得した時点で全要素がコピーされるわけではない。何らかの観測列の更新が発生するまで、全要素のコピーは遅延する。更新がない場合は、全要素のコピーは発生しない。
時系列モニターからパラメータ名で示される観測列を取得する。観測列は時系列データであり、観測列と時刻列の組で構成される。存在しないパラメータの場合はエラーとなる。複数存在するパラメーター名の場合、列番号の小さなものとなる。取得した観測列は、時系列モニターの観測列のコピーである。時刻列もコピーされる。
時系列モニターから i 番目の観測列を取得する。観測列は時系列データであり、観測列と時刻列の組で構成される。存在しない列番号の場合はエラーとなる。負の数が指定された場合は(観測列数 + i) 列を意味する。取得した観測列は、時系列モニターの観測列のコピーである。時刻列もコピーされる。
モニターの場合と同じく、取得した観測列は、時系列モニターの観測列のコピーである。つまり、取得した観測列、時刻列に変更を加えても、元の時系列モニターは変更されない。
時系列モニターの時刻列のコピーを返す。
モニターの複数の観測列を指定するために、列指定子がある。ここで、モニターの列数は C とする。列指定子においては負の列は最後の列からのインデックスを示す。つまり、列指定子における列 i は、実際の列 M_C(i) を示す。
M_C(i) = \left\{ \begin{array}{ll} 0 & (i < -C) \\ C + i & (-C \le i < 0) \\ i & (0 \le i < C) \\ C & (C \le i) \\ \end{array} \right.
intVector整数型観測列 \{I_k\} に対し、\{M_C(I_k)\} が列番号列を示す。 ただし、-C \le I_j < C 以外の要素があった場合は無効な列指定子 である。
リストの各要素に対し、\{M_C(I_k)\} が列番号列を示す。 ただし、-C \le I_j < C 以外の要素があった場合は無効な列指定子である。
\{k \,|\, M_C(\text{start}) \le k < M_C(\text{end})\} の列番号列を示す。
\{k \,|\, M_C(\text{start}) \le k < C\} の列番号列を示す。
\{k \,|\, 0 \le k < M_C(\text{end})\} の列番号列を示す。
\{k = M_C(\text{start}) + i\:\text{step} \,|\, M_C(\text{start}) \le k < M_C(\text{end}),\, i \ge 0\} の列番号列を示す。
全ての列を示す。
全ての列を示す。
モニターの複数の観測行を指定するために、行指定子がある。ここで、モニターの行数は R とする。行指定子においては負の行は最後の行からのインデックスを示す。つまり、行指定子における行 i は、実際の行 M_R(i) を示す。
M_R(i) = \left\{ \begin{array}{ll} 0 & (i < -R) \\ R + i & (-R \le i < 0) \\ i & (0 \le i < R) \\ R & (R \le i) \\ \end{array} \right.
I整数 I に対し、M_R(I) の行を示す。 ただし、-R \le I < R でない場合は無効な行指定子である。
整数型観測列 \{I_k\} に対し、\{M_R(I_k)\} が行番号列を示す。 ただし、-R \le I_j < R 以外の要素があった場合は無効な行指定子 である。
リストの各要素に対し、\{M_R(I_k)\} が行番号列を示す。 ただし、-R \le I_j < R 以外の要素があった場合は無効な行指定子である。
\{k \,|\, M_R(\text{start}) \le k < M_R(\text{end})\} の行番号列を示す。
\{k \,|\, M_R(\text{start}) \le k < R\} の行番号列を示す。
\{k \,|\, 0 \le k < M_R(\text{end})\} の行番号列を示す。
\{k = M_R(\text{start}) + i\:\text{step} \,|\, M_R(\text{start}) \le k < M_R(\text{end}),\, i \ge 0\} の行番号列を示す。
全ての行を示す。
全ての行を示す。
ブール型観測列 \{B_i\} に対し、\{k \,|\, B_k = T\} の 行番号列を示す。\Vert\{B_i\}\Vert \neq R の場合は 無効な行指定子である。
列indexの値がminval以上、maxval以下の行を示す。ただし、モニターは列indexに関して昇順にソート済みであることを要求する。 オプションとしてexclude_min=Trueを与えると、列indexの値がminvalより大きい行を示す。 また、exclude_max=Trueを与えると、列indexの値がmaxval未満の行を示す。
単一の観測列を取得したい場合は、6.1.6 章 章の方法が利用出来るが、複数の観測列を取得したい場合は以下を利用 する。
monitor の列指定子で示される列を抽出し、新規のモニターを返す。列指定子としては6.1.9 章章の指定方法が利用出来る。各列はコピーされる。無効な指定子の場合はエラーとなる。
timeMonitor の列指定子で示される列を抽出し、新規の時系列モニターを返す。列指定子としては6.1.9 章章の指定方法が利用出来る。各列および時刻列はコピーされる。無効な指定子の場合はエラーとなる。
モニターから一部の列のみを抽出したい場合は、6.1.11 章 章の方法が利用出来るが、更に行番号を指定した抽出を行いたい場合は、以下を利用する。
monitor の列指定子及び行指定子で示される部分を抽出し、新規のモニターを返す。列指定子としては6.1.9 章章の指定方法が利用出来る。行指定子としては6.1.10 章章の指定方法が利用出来る。指定された部分はコピーされる。無効な列指定子あるいは行指定子の場合はエラーとなる。
なお、6.1.6 章章の方法は、観測列を返すが、以上の方法による行指定も可能である。ただし、その場合の結果は、モニターでなく、観測列が返る。更に例外として、monitor[row, パラメータ名]、monitor[row, col] の場合は、指定された観測値が返る。
timeMonitor の列指定子及び行指定子で示される部分を抽出し、新規の時系列モニターを返す。列指定子としては6.1.9 章章の指定方法が利用出来る。行指定子としては6.1.10 章章の指定方法が利用出来る。指定された部分はコピーされる。時刻列も指定された行のみがコピーされる。無効な列指定子あるいは行指定子の場合はエラーとなる。
timeMonitor の列指定子で指定される列の開始時刻から終了時刻までの間の部分を抽出し、 新規の時系列モニターを返す。 列指定子としては 6.1.9 章 章の指定方法が利用できる。 指定された部分はコピーされる。 時刻列は開始時刻から終了時刻までの時刻列が作成される。 ただし、開始時刻が timeMonitor の最初の時刻より前の場合は、 開始時刻は最初の時刻に置き換えられる。 無効な列指定子や、終了時刻が開始時刻より前であるような場合はエラーとなる。
monitor の列指定子で指定された部分を monitor_2 で置き換える。列指定子としては6.1.9 章章の指定方法が利用出来る。無効な列指定子の場合はエラーとなる。monitor と monitor_2 の列数あるいは行数が違う場合はエラーとなる。
monitor の列指定子で指定された部分を指定したリストで置き換える。列指定子としては6.1.9 章章の指定方法が利用出来る。リストは、k 列を表現するリスト [val_{0,k}, val_{1,k}, \cdots, val_{n-1, k}]のリストである。無効な列指定子の場合はエラーとなる。monitor と monitor_2 の列数あるいは行数が違う場合はエラーとなる。
monitor の列指定子で指定された列の中身を全て val にする。列指定子としては6.1.9 章章の指定方法が利用出来る。無効な列指定子の場合はエラーとなる。
6.1.15 章章と同様の方法が利用出来る。
モニターの一部の列のみを更新したい場合は、6.1.15 章 章の方法が利用出来るが、更に行番号を指定した更新を行いたい場合は、以下を利用する。
monitor の列指定子及び行指定子で指定された部分を monitor_2 で置き換える。列指定子としては6.1.9 章章の指定方法が利用出来る。行指定子としては6.1.10 章章の指定方法が利用出来る。無効な列指定子あるいは行指定子の場合はエラーとなる。monitor と monitor_2 の列数あるいは行数が違う場合はエラーとなる。
monitor の列指定子及び行指定子で指定された部分を monitor_2 で置き換える。列指定子としては6.1.9 章章の指定方法が利用出来る。行指定子としては6.1.10 章章の指定方法が利用出来る。リストは、k 列を表現するリスト [val_{0,k}, val_{1,k}, \cdots, val_{n-1, k}]のリストである。無効な列指定子あるいは行指定子の場合はエラーとなる。monitor と指定されたリストの列数あるいは行数が違う場合はエラーとなる。
monitor の列指定子及び行指定子で指定された部分を val で置き換える。列指定子としては6.1.9 章章の指定方法が利用出来る。行指定子としては6.1.10 章章の指定方法が利用出来る。無効な列指定子あるいは行指定子の場合はエラーとなる。
6.1.17 章章と同様の方法が利用出来る。時刻列は変化しない。
monitor の列指定子で指定された部分を削除する。列指定子としては6.1.9 章章の指定方法が利用出来る。無効な列指定子の場合はエラーとなる。
6.1.19 章章と同様の方法が利用出来る。時刻列は変化しない。
monitor の行指定子で指定された部分を削除する。行指定子としては6.1.10 章章の指定方法が利用出来る。無効な行指定子の場合はエラーとなる。
monitor の行指定子で指定された部分を削除する。行指定子としては6.1.10 章章の指定方法が利用出来る。無効な行指定子の場合はエラーとなる。
6.1.21 章章と同様の方法が利用出来る。指定された行の時刻列も削除される。
monitor をディレクトリ basedirに保存する。名前は monitor の名前になる。
monitor をディレクトリ basedirに保存する。名前は monitor の名前になる。
monitor の観測列数を返す。
monitor の観測数を返す。
monitor の観測列数と観測数をタプルの形で返す。
monitor の観測列の名前のリストを返す。
monitor の i 番目の観測列の名前を name に変更する。
monitor のリスト表現 [[val_{0,0}, val_{1,0}, \cdots, val_{n-1, 0}], [val_{0,1}, val_{1,1}, \cdots, val_{n-1, 1}], \cdots, [val_{0,m-1}, val_{1,m-1}, \cdots, val_{n-1, m-1}]] を返す。
通常、観測列は、6.1.6 章章、6.1.7 章の方法で、モニターあるいは時系列モニターから取得する。
観測列には、
FloatVector
IntVector
ObjectVector
BoolVector
がある。時系列観測列には、
TimeFloatVector
TimeIntVector
TimeObjectVector
TimeBoolVector
がある。特殊な時系列観測列として、
がある。TimeVector は時刻列の型であるが、TimeFloatVector の特殊な場合で、自分の時刻列が自分自身であるような観測列である。
浮動小数点型観測列を作成する。init が指定された場合は、そのリストの内容で初期化される。
整数型観測列を作成する。init が指定された場合は、そのリストの内容で初期化される。
文字列型観測列を作成する。init が指定された場合は、そのリストの内容で初期化される。
それぞれ、浮動小数点型観測列の最小値(min)、最大値(max)、範囲(range)、観測数(count)、平均(mean)、分散(var)、標準偏差(sd)、変動係数(cv) を返す。
観測列を \{x_i\}、観測数を n とすると、以下のように定義される。
\begin{aligned} \text{range} &= \max_{0 \le i \le n-1}(x_i) - \min_{0 \le i \le n-1}(x_i) \nonumber\\ \text{mean} &= \frac{1}{n}\sum_{i=0}^{n-1}x_i \nonumber\\ \text{var} &= \frac{1}{n-1}\sum_{i=0}^{n-1}(x_i-\text{mean})^2 \nonumber\\ \text{sd} &= \sqrt{\text{var}} \nonumber\\ \text{cv} &= \frac{\text{sd}}{\text{mean}} \nonumber \end{aligned}
浮動小数点型観測列の母平均の p * 100% 信頼区間をタプル (v1, v2) の形で返す。($ 0 < p < 1$)
t_{\nu, \alpha/2} は自由度 \nu の t 分布の、片側確率が \alpha/2*100 %となる t 値とすると、信頼区間は以下となる。
\begin{aligned} \text{confInterval}(p) &= \text{mean} \pm t_{\text{count}-1,(1-p)/2}\sqrt{\frac{\text{var}}{\text{count}}}\nonumber \end{aligned}
それぞれ、整数型観測列の最小値(min)、最大値(max)、範囲(range)、観測数(count)、平均(mean)、分散(var)、標準偏差(sd)、変動係数(cv)を返す。
計算式は浮動小数点型観測列の場合と同じである。
整数型観測列の母平均の p % 信頼区間をタプル (v1, v2) の形で返す。($ 0 < p < 1$)
計算式は浮動小数点型観測列の場合と同じである。
それぞれ、文字列型観測列の最頻値(mode)、最頻値の頻度(modefreq)、観測数(count)を返す。
それぞれ、浮動小数点型時系列観測列の最小値(min)、最大値(max)、範囲(range)、有効観測数(count)、平均(mean)、分散(var)、標準偏差(sd)、変動係数(cv)を返す。
観測列を \{x_i\}、時間列を \{t_i\}、観測数を n とすると、有効観測数は n-1 となり、以下のように定義される。
\begin{aligned} \text{count} &= n-1 \nonumber\\ \text{range} &= \max_{0 \le i \le n-2}(x_i) - \min_{0 \le i \le n-2}(x_i) \nonumber\\ \text{mean} &= \frac{1}{t_{n-1}-t_0}\sum_{i=0}^{n-2}(t_{j+1}-t_j)x_i \nonumber\\ \text{var} &= \frac{t_{n-1}-t_0} {(t_{n-1}-t_0)^2-\sum_{i=0}^{n-2}(t_{i+1}-t_i)^2} \sum_{i=0}^{n-2}{(t_{i+1}-t_i)(x_i-\text{mean})^2} \nonumber\\ \text{sd} &= \sqrt{\text{var}} \nonumber\\ \text{cv} &= \frac{\text{sd}}{\text{mean}} \nonumber \end{aligned}
浮動小数点型時系列観測列の母平均の p % 信頼区間をタプル (v1, v2) の形で返す。($ 0 < p < 1$)
計算式は、浮動小数点型観測列の場合と同様であるが、前述の基本統計量を用いる。
それぞれ、整数型時系列観測列の最小値(min)、最大値(max)、範囲(range)、観測数(count)、平均(mean)、分散(var)、標準偏差(sd)、変動係数(cv)を返す。
計算式は浮動小数点型時系列観測列の場合と同じである。
整数型時系列観測列の母平均の p% 信頼区間をタプル (v1, v2) の形で返す。($ 0 < p < 1$)
計算式は浮動小数点型時系列観測列の場合と同じである。
それぞれ、文字列型時系列観測列の最頻値(mode)、最頻値の頻度(modefreq)、観測数(count)を返す。
観測列の基本統計量の結果は可能な限りキャッシュされる。観測列をコピーしても基本統計量に変化はないので、キャッシュ結果が利用される。観測列に変更があった場合は、再度計算を行う。また、最小値、最大値、平均は同時に求められるので、最小値を取得した後に、最大値を取得した場合はキャッシュ結果が利用される。
浮動小数点型観測列の基本統計量のサマリを文字列で返す。
整数型観測列の基本統計量のサマリを文字列で返す。
文字列型観測列の基本統計量のサマリを文字列で返す。
浮動小数点型時系列観測列の基本統計量のサマリを文字列で返す。
整数型時系列観測列の基本統計量のサマリを文字列で返す。
文字列型時系列観測列の基本統計量のサマリを文字列で返す。
浮動小数点型と、整数型の場合、最小値、最大値、範囲、観測数、平均、分散、標準偏差、変動係数、信頼区間が含まれる。
文字列型の場合、観測数、種別数、最頻値、最頻値の頻度が含まれる。
時系列型の基本統計量は、出現頻度ではなく、観測列に含まれる値をとった時間を元に算出される。
浮動小数点型観測列の最小階級値 frm から 最大階級数 to までを nbin 個に分割したヒストグラムオブジェクトを返す。nbin が省略された場合は \lfloor 1+\log_2(n) \rfloor となる。frm が省略された場合は観測列の最小値、to が省略された場合は観測列の最大値となる。
整数型観測列の最小階級値 frm から 最大階級数 to までを nbin 個に分割したヒストグラムオブジェクトを返す。nbin が省略された場合は \lfloor1+\log_2(n) \rfloor となる。frm が省略された場合は観測列の最小値、to が省略された場合は観測列の最大値となる。
文字列型観測列の出現頻度の多い順に並び換えたヒストグラムオブジェクトを返す。maxfactors は最大数を指定する。指定されなかった場合は全てのオブジェクトを対象とする。
浮動小数点型時系列観測列の最小階級値 frm から 最大階級数 to までを nbin 個に分割した滞在時間のヒストグラムオブジェクトを返す。nbin が省略された場合は \lfloor 1+\log_2(n) \rfloor となる。frm が省略された場合は観測列の最小値、to が省略された場合は観測列の最大値となる。
整数型時系列観測列の最小階級値 frm から 最大階級数 to までを nbin 個に分割した滞在時間のヒストグラムオブジェクトを返す。nbin が省略された場合は \lfloor 1+\log_2(n) \rfloor となる。frm が省略された場合は観測列の最小値、to が省略された場合は観測列の最大値となる。
文字列型時系列観測列の滞在時間の長い順に並び換た滞在時間のヒストグラムオブジェクトを返す。maxfactors は最大数を指定する。指定されなかった場合は全てのカテゴリー文字列を対象とする。
時系列型の観測列のヒストグラムは、出現頻度ではなく、観測列に含まれる値をとった時間を元に算出される。
ヒストグラムオブジェクトを print すればヒストグラムが表示される。
時系列観測列の時刻列のコピーを返す。
観測列の各要素を2 項演算子 \cdot で演算し、その結果の観測列を返す。2 項演算子には、+, –, *, /, %,**, &, |, ^, >>, << がある。結果の観測列の型は vec_1の型となる。
観測列 vec_1 と、リスト [val_1, val_2, \cdots, val_n] の各要素を2 項演算子 \cdot で演算し、その結果の観測列を返す。2 項演算子には、+, –, *, /, %, **, &, |, ^, >>, << がある。結果の観測列の型は vec_1 の型となる。
観測列 vec_1 の各要素と val を2 項演算子 \cdot で演算し、その結果の観測列を返す。2 項演算子には、+, –,*, /, %, **, &, |, ^, >>, << がある。結果の観測列の型は vec_1 の型となる。
リスト [val_1, val_2, \cdots, val_n] と、観測列 vec_1 の各要素を2 項演算子 \cdot で演算し、その結果の観測列を返す。2 項演算子には、+, –, *, /, %, **, &, |, ^, >>, << がある。結果の観測列の型は vec_1 の型となる。
val と 観測列 vec_1 の各要素を2 項演算子 \cdot で演算し、その結果の観測列を返す。2 項演算子には、+, –,*, /, %, **, &, |, ^, >>, << がある。結果の観測列の型は vec_1 の型となる。
時系列観測列は、観測列と時刻列の組、すなわち、
(\{x_i\}, \{t_i\}) で表わされるが、
x(t) = x_i \quad (i = \max_{t_{k} \le t}k) のような関数としても表記する事が出来る。
ここで、時系列観測列同士の2項演算子 \cdot を以下のように定義する。
任意の (\{x_i\}, \{t_i\})、(\{y_i\}, \{u_i\}) に対し、 (\{x_i\}, \{t_i\}) \cdot (\{y_i\}, \{u_i\}) = (\{z_i\}, \{w_i\}) とすると、(\{z_i\}, \{w_i\}) は以下を満たす。
\begin{aligned} x(t) \cdot y(t) &= x_j \cdot y_l \quad (j = \max_{t_k \le t}k, l = \max_{u_k \le t}k) \nonumber \\ &= z_i \quad (i = \max_{w_k \le t}k) \nonumber \end{aligned}
必ず、\Vert \{w_i\} \Vert = \Vert \{z_i\} \Vert \le \Vert \{t_i\} \cup \{u_i\} \Vert となる。
この定義の下、時系列観測列に対して、6.2.6 章章と同様の2項演算が可能である。
時系列観測列 \cdot 観測列、あるいは、観測列 \cdot 時系列観測列の場合は、双方を同じ時刻列のものとして演算を行う。
観測列の vec_1 と vec_2の各要素を2 項演算子 \cdot で演算し、その結果をvec_1に反映する。2 項演算子に=をつなげたものを累積演算子と呼ぶ。累積演算子には、+=,–=, *=, /=, &=, |=, ^, >>=, <<= がある。結果の観測列の型は vec_1 の型となる。
観測列の vec_1 とリスト [val_1, val_2, \cdots, val_n] の各要素を2 項演算子 \cdot で演算し、その結果をvec_1に反映する。2 項演算子に=をつなげたものを累積演算子と呼ぶ。累積演算子には、+=,–=, *=, /=, &=, |=, ^, >>=, <<= がある。結果の観測列の型は vec_1 の型となる。
観測列の vec_1 の各要素 と val を2 項演算子 \cdot で演算し、その結果をvec_1に反映する。2 項演算子に=をつなげたものを累積演算子と呼ぶ。累積演算子には、+=, –=,*=, /=, &=, |=, ^, >>=, <<= がある。結果の観測列の型は vec_1 の型となる。
6.2.8 章章と同様の方法が利用出来る。時系列は変化しない。
観測列 vec を返す。
観測列 vec の各要素の符号を反転した観測列を返す。
観測列 vec の各要素のビットを符号を反転した観測列を返す。
観測列 vec の各要素の絶対値で構成される観測列を返す。
時系列観測列に対しても、6.2.10 章章の演算が可能である。
観測列 vec の各要素 x_i に対し、op(x_i) の演算を行った観測列を返す。op には、ceil, fabs, floor, exp, log10,sqrt, acos, atan, cos, sin, tan, degrees, raidans, cosh, sinh, tanh がある。
観測列 vec_1 の各要素 x_i と観測列 vec_2 の各要素 y_i に対し、op2(x_i, y_i) の演算を行った観測列を返す。op には、log, fmod, atan2, hypot がある。
時系列観測列に対しても、6.2.12 章章の演算が可能である。
2 項演算の場合の演算方法は6.2.7 章 章と同様である。時系列観測列と観測列の組み合わせの場合は、双方を同じ時刻列のものとして演算を行う。
観測列には比較演算を行う事が出来る。結果は BoolVector である。BoolVector を用いて、モニターや観測列の抽出を行う事が出来る。
観測列の各要素を比較演算子 \cdot で比較し、その結果の BoolVector を返す。比較演算子には、>, >=, <,<=, ==, != がある。
観測列 vec_1 と、リスト [val_1, val_2, \cdots, val_n] の各要素を比較演算子 \cdot で比較し、その結果の BoolVector を返す。比較演算子には、>, >=, <, <=, ==, != がある。
観測列 vec_1 の各要素と val を比較演算子 \cdot で比較し、その結果の BoolVector を返す。比較演算子には、>, >=, <, <=, ==, != がある。
リスト [val_1, val_2, \cdots, val_n] と、観測列 vec_1 の各要素を比較演算子 \cdot で比較し、その結果の BoolVector を返す。比較演算子には、>, >=, <, <=, ==, != がある。
val と 観測列 vec_1 の各要素を比較演算子 \cdot で比較し、その結果の BoolVector を返す。比較演算子には、>, >=, <, <=, ==, != がある。
時系列観測列に対しても、6.2.14 章章の方法が利用出来る。ただし、結果は BoolVector に時刻列を付加された TimeBoolVector が返る。
時系列観測列同士の比較の場合は、2 項演算と同様に、行拡張が発生する。
時系列観測列 \cdot 観測列、あるいは、観測列 \cdot 時系列観測列の場合は、双方を同じ時刻列のものとして比較を行う。
vector の行指定子で示される部分を抽出し、新規の Vector を返す。行指定子としては6.1.10 章章の指定方法が利用出来る。指定された部分はコピーされる。無効な行指定子の場合はエラーとなる。
6.2.16 章章と同様の方法が利用出来る。時系列も抽出される。 その他に次の方法も使用できる。
timeVector の開始時刻から終了時刻までの間の部分を抽出し、 新規の時系列観測列を返す。指定された部分はコピーされる。 時刻列は開始時刻から終了時刻までの時刻列が作成される。 ただし、開始時刻が timeVector の最初の時刻より前の場合は、 開始時刻は最初の時刻に置き換えられる。終了時刻が開始時刻より前であるような場合はエラーとなる。
vector の行指定子で指定された部分を vector_2 で置き換える。行指定子としては6.1.10 章章の指定方法が利用出来る。無効な行指定子の場合はエラーとなる。vector とvector_2 の行数が違う場合はエラーとなる。
vector の行指定子で指定された部分を指定したリストで置き換える。行指定子としては6.1.10 章章の指定方法が利用出来る。無効な行指定子の場合はエラーとなる。vector とリストの行数が違う場合はエラーとなる。
vector の行指定子で指定された行の中身を全て val にする。行指定子としては6.1.10 章章の指定方法が利用出来る。無効な行指定子の場合はエラーとなる。
6.2.18 章章と同様の方法が利用出来る。 時系列は変化しない。
vector の行指定子で指定された部分を削除する。行指定子としては6.1.10 章章の指定方法が利用出来る。無効な行指定子の場合はエラーとなる。
6.2.20 章章と同様の方法が利用出来る。時系列は変化しない。指定された行の時刻列も削除される。
vector の階差数列を返す。lag は階差を取る間隔、difference は何回階差を取るかを指定する。lag と difference は 1 以上の整数でなくてはならない。なお、文字列型観測列については、この処理は行えない。
元の vector を a_i^{(0)}\,(0 \le i < n) とし、lag を l,difference を d とすると、
a_i^{(d)} = a_{i+l}^{(d-1)} - a_i^{(d-1)}
になる。
vector の部分和の数列を返す。なお、文字列型観測列については、この処理は行えない。
元の vector を a_i\,(0 \le i < n) とすると、
a_i' = \sum_{k=0}^{i}{a_k}
になる。
vector の単純移動平均(直近のn 個の平均)の列を返す。なお、文字列型観測列については、この処理は行えない。
元の vector を a_i\,(0 \le i < n) とすると、
a_i' = \frac{\sum_{k=i-n+1}^{i}{a_k}}{n}
になる。
vector の分位値のリストを返す。qs は 0 以上 1 以下の確率のリストを指定する。なお、文字列型観測列については、この処理は行えない。
q 分位値は、分布を q:(1-q) に分割する値である。(0 \le q \le 1)
\begin{aligned} Q_q &= \left\{ \begin{array}{ll} x_{k} & (k_0 = k_1) \\ (k_1 - k)x_{k_0} + (k - k_0)x_{k_1} & (k_0 \neq k_1) \\ \end{array} \right. \nonumber\\ k &= q(n-1) \nonumber\\ k_0 &= \lfloor k \rfloor \nonumber\\ k_1 &= \lceil k \rceil \nonumber \end{aligned}
最も近い 2 点の値から、線形補完で内挿する。
例えば、\{1, 2, 3, 4\} の中央値 Q_{0.5} = 2.5 となる。
vector の n 番目に、val を加える。この操作は破壊的である。
vector の末尾に、val を加える。この操作は破壊的である。
vector の末尾に、vector あるいはリストを加える。この操作は破壊的である。
vector の順番を反転する。この操作は破壊的である。
vector の順番を並び換える。cmp が指定されなかった場合、昇順に並び換える。cmp に-1, 0,1を返す関数が指定された場合、その順番に並び換えられる。reverse がTrue の場合、順序は反転される。この操作は破壊的である。
vector と vector_2の共分散を返す。vector と vector_2 の長さは同じでなくてはならない。なお、文字列型観測列については、この処理は行えない。
vector を x_i\,(0 \le i < n)、vector_2 を y_i\,(0 \le i < n) とすると、
\frac1{n-1}\sum_{i=0}^{n-1}(x_i-\bar{x})(y_i-\bar{y}) になる。
vector と vector_2の積率相関係数を返す。vector と vector_2 の長さは同じでなくてはならない。なお、文字列型観測列については、この処理は行えない。
vector を x_i\,(0 \le i < n)、vector_2 を y_i\,(0 \le i < n) とすると、
\frac{\sum_{i=0}^{n-1}(x_i-\bar{x})(y_i-\bar{y})} {\sqrt{\sum_{i=0}^{n-1}(x_i-\bar{x})^2} \sqrt{\sum_{i=0}^{n-1}(y_i-\bar{y})^2}} になる。
timeVector の階差モニターを返す。階差モニタは値列と重み列からなる。weightFirst が False なら、モニターの列は(値、重み) となり、True なら、モニターの列は(重み、値) となる。なお、文字列型時系列観測列については、この処理は行えない。
元の timeVector を (\{x_i\}, \{t_i\})\,(0 \le i < n) とし、重みをw_i, 値を v_i とすると、
\begin{aligned} w_i &= \Delta t_i = t_{i+1} - t_i \nonumber\\ v_i &= x_i \nonumber \end{aligned}
となるような、モニターを返す。
timeVector の移動平均を返す。なお、文字列型時系列観測列については、この処理は行えない。
元の timeVector を (\{x_i\}, \{t_i\})\,(0 \le i < n) とし、time をs とすると、
\begin{aligned} x(t) &= x_i \quad (i = \max_{t_{k} \le t}k) \nonumber\\ T &= \max_{t_k \le t_0 + s}k \nonumber\\ x_i' &= \frac{1}{s}\int_{t_{i+t}-s}^{t_{i+t}}{xdt} \nonumber\\ t_i' &= t_{i + T} \nonumber \end{aligned} となるような、timeVector (x_i', t_i') を返す。
timeVector の分位値のリストを返す。qs は 0 以上 1 以下の確率のリストを指定する。なお、文字列型観測列については、この処理は行えない。
timeVector の順番を並び換える。cmp が指定されなかった場合、昇順に並び換える。cmp に-1, 0,1を返す関数が指定された場合、その順番に並び換えられる。reverse がTrue の場合、順序は反転される。この操作は破壊的である。
元の timeVector を (\{x_i\}, \{t_i\})\,(0 \le i < n) とする。
ここで、x_i を昇順に並びかえる。つまり、
x_{S_i} \le x_{S_j} \quad (0 \le i \le j \le n - 2)
を見たすような、\{S_i\} を求める。
\begin{aligned} x_i' &= x_{S_i} \nonumber\\ u_i &= t_{S_{i+1}} - t_{S_i} \nonumber\\ t_i' &= \sum_{k=0}^{i}u_i \nonumber \end{aligned} となるような、timeVector (x_i', t_i') になる。
timeVector とtimeVector_2の共分散を返す。なお、文字列型観測列については、この処理は行えない。
timeVector を (\{x_i\}, \{t_i\})\,(0 \le i < n)、timeVector_2 を(\{y_i\}, \{u_i\})\,(0 \le i < n) とする。
(\{x_i\}, \{t_i\}) と (\{y_i\}, \{u_i\}) を結合し、時間\max(\min_i{t_i}, \min_i{u_i}) から \min(\max_i{t_i}, \max_i{u_i})までの区間のみを取り出し (\{x'_i\}, \{y'_i\}, \{t'_i\})\,(0 \le i < n') とする。その上で、以下を共分散とする。
\frac{t'_{n-1}-t'_0} {(t'_{n-1}-t'_0)^2-\sum_{i=0}^{n'-2}(t'_{i+1}-t'_i)^2} \sum_{i=0}^{n-2}{(t'_{i+1}-t'_i)(x'_i-\bar{x'})(y'_i-\bar{y'})}
timeVector と timeVector_2の積率相関係数を返す。なお、文字列型観測列については、この処理は行えない。
timeVector を (\{x_i\}, \{t_i\})\,(0 \le i < n)、timeVector_2 を(\{y_i\}, \{u_i\})\,(0 \le i < n) とする。
(\{x_i\}, \{t_i\}) と (\{y_i\}, \{u_i\}) を結合し、時間\max(\min_i{t_i}, \min_i{u_i}) から \min(\max_i{t_i}, \max_i{u_i})までの区間のみを取り出し (\{x'_i\}, \{y'_i\}, \{t'_i\})\,(0 \le i < n') とする。
その上で、以下を相関係数とする。
\frac {\sum_{i=0}^{n'-2}{(t'_{i+1}-t'_i)(x'_i-\bar{x'})(y'_i-\bar{y'})}} {\sqrt{\sum_{i=0}^{n'-2}{(t'_{i+1}-t'_i)(x'_i-\bar{x'})^2}} \sqrt{\sum_{i=0}^{n'-2}{(t'_{i+1}-t'_i)(y'_i-\bar{y'})^2}}}
時系列観測列を階段関数とみて、次の積分を計算する。
\int \exp(- \beta t) v(t) dt
ここで、積分区間は [start, end] である。 また、 \beta は引数の beta で非負とする。v は timeVector をあらわす。 start と end が None の場合は、時系列観測列の時刻の最小値と最大値が使用される
疑似乱数の系列には、
グローバル系列
個別系列
がある。
グローバル系列の乱数の種は、setGlobalSeed で指定する事が出来る。
a が None の場合、現在のシステム時間によって種が初期化される。a が None でない場合、その値によって定められる乱数系列が設定される。同じ種の場合、同じ乱数系列を返す。
個別系列の乱数の種は各乱数生成器で指定する事が出来るが、
グローバル系列を利用
独自系列を利用
を指定する事が出来る。グローバル系列を利用した場合、グローバル系列を用いて各個別乱数を生成する。そのため、複数の並列するプロセスから乱数を生成した場合、呼出し順番によって、個々の乱数系列は変わってしまう。
独自系列を利用した場合、グローバル系列とは独立な、指定した値によって定められる一意な独自系列から乱数が生成される。同一の値を指定した場合同一の系列から乱数が生成される。
乱数生成器は全て Python のジェネレータ関数である。next() を呼ぶ事で次の乱数を取得する事が出来る。
指定した乱数生成器の次の乱数を返す。
常に同じ値 val を返すジェネレータを返す。
平均 meanの指数分布に従う乱数ジェネレータを返す。
平均を \muとすると、確率密度関数は以下になる。
f(x;\mu) = \frac{e^{-\frac{x}{\mu}}}{\mu} \quad (x \ge 0, \mu > 0)
平均mean、標準偏差 sd の正規分布に従う乱数ジェネレータを返す。
平均を \mu、標準偏差を \sigma とすると、確率密度関数は以下になる。
f(x;\mu,\sigma)=\frac{1}{\sqrt{2\pi}\sigma}e^{-\frac{(x-\mu)^2}{2\sigma^2}} \quad \quad (\sigma > 0)
平均 mean, 標準偏差 sd の対数正規分布に従う乱数ジェネレータを返す。
平均を \mu、標準偏差を \sigma とすると、確率密度関数は以下になる。
f(x;\mu,\sigma)=\frac{1}{\sqrt{2\pi}\sigma{x}}e^{-\frac{(\log{x}-\mu)^2}{2\sigma^2}} \quad (\sigma > 0)
a から bまでの一様分布に従う乱数ジェネレータを返す。
最小を a、最大を b とすると、確率密度関数は以下になる。
f(x;a,b) = \frac{1}{b - a} \quad (a \le x < b)
alpha,beta を形状とするβ分布に従う乱数ジェネレータを返す。
形状1を \alpha、形状2を \beta とすると、確率密度関数は以下になる。
f(x;\alpha,\beta)=\frac{1}{B(\alpha,\beta)}x^{\alpha-1}(1-x)^{\beta-1} \quad (0 \le x \le 1, \alpha > 0, \beta > 0)
形状 alpha, 尺度 beta のガンマ分布に従う乱数ジェネレータを返す。
形状を \alpha、尺度を \beta とすると、確率密度関数は以下になる。
f(x;\alpha,\beta) = x^{\alpha-1} \frac{e^{-x/\beta}}{\Gamma(\alpha)\,\beta^\alpha} \quad (x \ge 0, \alpha > 0, \beta > 0)
形状 alpha, 尺度 beta のアーラン分布に従う乱数ジェネレータを返す。
形状を \alpha、尺度を \beta とすると、確率密度関数は以下になる。
f(x;\alpha,\beta) = x^{\alpha-1} \frac{e^{-x/\beta}}{(\alpha - 1)!\,\beta^\alpha} \quad (x \ge 0, \alpha > 0, \alpha \in {\bf N}, \beta > 0)
形状 a,最小値 b のパレート分布に従う乱数ジェネレータを返す。
形状を a、最小値を b とすると、確率密度関数は以下になる。
f(x;a,b) = \frac{a b^a}{x^{a+1}} \quad (x \ge b, a > 0, b > 0)
形状 alpha, 尺度 beta のワイブル分布に従う乱数ジェネレータを返す。
形状を \alpha、尺度を \beta とすると、確率密度関数は以下になる。
f(x;\alpha,\beta)=\frac{\alpha}{\beta}\left(\frac{x}{\beta}\right)^{\alpha-1} e^{-\left(\frac{x}{\beta}\right)^\alpha} \quad (x \ge 0, \alpha >0, \beta > 0)
自由度 df のカイ二乗分布に従う乱数ジェネレータを返す。
自由度を m とすると、確率密度関数は以下になる。
f(x;m)=\frac{(1/2)^{m/2}}{\Gamma(m/2)} x^{m/2 - 1} e^{-x/2} \quad (m > 0)
分子の自由度 dfnum、分母の自由度 dfden のF分布に従う乱数ジェネレータを返す。
分子の自由度を m_1、分母の自由度を m_2 とすると、確率密度関数は以下になる。
f(x;m_1,m_2)=\frac {\Gamma(\frac{m_1 + m_2}{2}) {(\frac{m_1}{m_2})}^{\frac{m_1}{2}} x^{\frac{m_1}{2}-1}} {\Gamma(\frac{m_1}2)\Gamma(\frac{m_2}2){(1+\frac{m_1}{m_2}x)}^{\frac{m_1+m_2}2}} \quad (m_1 > 0, m_2 > 0)
位置 loc、尺度 scale のロジスティック分布に従う乱数ジェネレータを返す。
位置を \mu、尺度を s とすると、確率密度関数は以下になる。
f(x;\mu,s) = \frac{e^{-(x-\mu)/s}}{s(1+e^{-(x-\mu)/s})^2}
自由度 df、非心度 nonc の非心カイ二乗分布に従う乱数ジェネレータを返す。
自由度を m、非心度を \delta とすると、確率密度関数は以下になる。
f(x;m,\delta) = \frac{e^{-\frac{x + \delta}{2}}}{2^{\frac{m}{2}}}\sum_{j=0}^{\infty}{(\frac{\delta}{4})}j\frac{x^{\frac{m}{2} + j - 1}}{j!\Gamma(\frac{m}{2}+j)} \quad (m > 0, \delta \ge 0)
分子の自由度 dfnum、分母の自由度 dfden、非心度 nonc の非心F分布に従う乱数ジェネレータを返す。
分子の自由度を m_1、分母の自由度を m_2、非心度を \delta とすると、確率密度関数は以下になる。
f(x;m_1,m_2,\delta)=\sum_{j=0}^{\infty}\frac{e^{-\frac{\delta}{2}}(\frac{\delta}{2})^j}{j!}\frac{(m_1+2j)^{\frac{m_1+2j}{2}}m_2^{\frac{m_2}{2}}}{B(\frac{m_1+2j}{2},\frac{m_2}{2})}x^{\frac{m_1+2j}{2}-1}(m_2+(m_1+2j)x)^{-\frac{(m_1+2j)+m_2}{2}}
標準コーシー分布に従う乱数ジェネレータを返す。
確率密度関数は以下になる。
f(x) = \frac{1}{\pi(1+x^2)}
尺度 scale のレイリー分布に従う乱数ジェネレータを返す。
尺度を \theta とすると、確率密度関数は以下になる。
f(x;\theta) = \frac{x}{\theta^2}e^{-\frac{x^2}{2\theta^2}}
自由度 df の t 分布に従う乱数ジェネレータを返す。
自由度を m とすると、確率密度関数は以下になる。
f(x;m) = \frac{\Gamma((m+1)/2)}{\sqrt{m\pi\,}\,\Gamma(m/2)} (1+x^2/m)^{-(m+1)/2}
最小値 left、最頻値 mode、最大値 right の三角分布に従う乱数ジェネレータを返す。
最小値を \alpha、最頻値を \gamma、最大値を \betaとすると、確率密度関数は以下になる。
\begin{aligned} f(x;\alpha, \gamma, \beta) = \left\{ \begin{array}{ll} \frac{2(x-\alpha)}{(\beta-\alpha)(\gamma-\alpha)} & (\alpha \le x \le \gamma) \\ \frac{2(\beta-x)}{(\beta-\alpha)(\beta-\gamma)} & (\gamma \le x \le \beta) \\ \end{array} \right. \nonumber \end{aligned}
試行回数 n, 確率 p の二項分布に従う乱数ジェネレータを返す。
試行回数を n、確率を p とすると、確率関数は以下になる。
f(k;n,p)=\binom{n}{k} p^k(1-p)^{n-k} \quad (n > 0, 0 \le p \le 1)
確率 p の幾何分布に従う乱数ジェネレータを返す。
確率を p とすると、確率関数は以下になる。
f(k;p) = (1 - p)^{k - 1} p \quad (0 \le \le 1)
ある属性を持つ要素数 ngood、それ以外の要素数 nbad、サンプル数 nsample の超幾何分布に従う乱数ジェネレータを返す。
ある属性を持つ要素数 m、それ以外の要素数を n、サンプル数を N とすると、確率関数は以下になる。
f(x;n,m,N) = \frac{\binom{m}{x} \binom{n}{N-x}}{\binom{m+n}{N}} \quad (0 \le x \le m, n + m - N \le x \le n)
試行回数 n, 確率 p の負の二項分布に従う乱数ジェネレータを返す。
試行回数を n、確率を p とすると、確率関数は以下になる。
f(x;n,p) = \binom{n+x-1}{n-1}p^n(1-p)^x \quad (n > 0, 0 \le p \le 1)
平均 lmd のポアソン分布に従う乱数ジェネレータを返す。
平均を \lambda とすると、確率関数は以下になる。
f(x;\lambda) = \frac{\lambda^xe^{-\lambda}}{x!}
確率 w_i/\sum{w_i} で v_i を返すような乱数ジェネレータを返す。
重み列を \{w_i\}、値列を \{v_i\} とすると、確率関数は以下になります。
f(v_i;\{w_j\}) = \frac{w_i}{\sum_j{w_j}} \quad (w_i \ge 0)
確率 w_i/\sum{w_i} で v_i を中心とした width をもつ kernel 関数に従う乱数ジェネレータを返す。
重み列を \{w_i\}、値列を \{v_i\} とすると、確率関数は以下になります。 カーネル関数をKとすると、カーネル密度推定では以下の式により密度を推定します。 f(x)=\sum_{i=1}^{N} \frac{w_i}{\sum_j{w_j}} K(\frac{x-v_{i}}{\omega})
ここで\omegaは間隔幅(width)です。
カーネル関数は、それぞれ以下で定義されます。
ガウス関数f(x;\mu,\omega)=\frac{1}{\sqrt{2\pi}\omega}e^{-\frac{(x-\mu)^2}{2\omega^2}} \quad \quad (\omega > 0)
f(x;\mu,\omega)=\frac{1}{\omega^2}(x-\mu)+\frac{1}{\omega} \quad \quad (\omega > 0,\mu-\omega \leq x \leq \mu+\omega)
f(x;\mu,\omega)=\frac{1}{2\omega} \quad \quad (\omega > 0,\mu-\omega \leq x \leq \mu+\omega)
f(x;\mu,\omega)=\frac{1}{2\omega} [1+\cos(\frac{\pi(x-\mu)}{\omega})] \quad \quad (\omega > 0,\mu-\omega \leq x \leq \mu+\omega)
均一な確率でv_i を返すような乱数ジェネレータを返す。
vec の順番でv_i を返すようなジェネレータを返す。repeat が True なら繰り返す。
begin から end 未満までを step おきに返すようなジェネレータを返す。repeat が True なら繰り返す。
次の値を返すジェネレータを返す:baseValue(1+\frac{minPer}{100}),baseValue(1+\frac{step + minPer}{100}), baseValue(1+\frac{2step + minPer}{100}), \dots, baseValue(1+\frac{maxPer}{100})。ただし、各値はtypeFunで指定した関数で変換されて返される。repeat が True なら繰り返す。
S4 Simulation System で強化学習を利用する際は、 強化学習モデルを定義する必要がある。 強化学習モデルは強化学習に関する設定をまとめたものである。
強化学習モデルは具体的には RLModel クラスを継承したクラスとして定義される。 RLModel クラスを継承した上で、次のクラス変数とメソッドを定義する必要がある。
観測値集合を定めるクラス変数である。 観測値集合は 整数・実数値の閉区間または文字列の有限集合の、 積集合としてあらわされるものとする。 OBS_SPEC は、観測値集合の各次元をあらわすタプルのリストである。 タプルは次の 3 つの要素を持つ。
次元名である。
型を表す文字列であり、次のいずれかである。実数は “f” であり、整数は “i” であり、文字列は “o” である。
取りうる値をあらわすリスト・タプルである。 第二要素が “f”, “i” の場合は最小値と最大値のタプルで、 “o” の場合は取りうる文字列のリストとする。 なお、与えられる文字列はアルファベット文字からなる文字列のみとする。
観測値集合を定めるクラス変数である。 形式は OBS_SPEC と同様である。
semi-Markov Decision Process でモデル化するかどうかをあらわすブール値のクラス変数である。 真ならば、 semi-Markov Decision Process でモデル化し、学習することを意味する。 偽ならば、通常の Markov Decision Process でモデル化される。
観測値を計算するメソッドである。各引数の意味は次の通りである。
simulatorシミュレータ本体であり、 simulator を通して 現在のシミュレーション状況を観測し、観測値を計算する。
後述する getAction における item が渡される。 フローアイテムのリンク選択で selectRL () を使用した場合は、対象のフローアイテムが item に格納される。
返り値として、観測値集合の各次元の名前がキーであり、 値が次元の値である辞書を返すとする。
即時報酬値を計算するメソッドである。各引数の意味は次の通りである。
simulatorシミュレータ本体であり、 simulator を通して、 現在のシミュレーション状況を観測し、即時報酬値を計算する。
後述する getAction における item が渡される。 フローアイテムのリンク選択で selectRL () を使用した場合は、対象のフローアイテムが item に格納される。
即時報酬計算のタイミングを次回の行動決定時点とする際(後述するgetActionにおけるasync_rewardがFalse)には、直前の行動を決定してから今回の行動を決定するまでの経過時間である。 このタイミングをずらす際(getActionにおけるasync_rewardがTrue)には、行動を決定してから即時報酬を確定させるまでの経過時間となる。
返り値は即時報酬値である。
強化学習によって提案された行動に問題がある場合に、 このメソッドで修正する。 各引数の意味は次の通りである。
simulatorシミュレータ本体である。
観測値である。
強化学習によって提案された行動値である。
後述する getAction における item が渡される。 フローアイテムのリンク選択で selectRL () を使用した場合は、対象のフローアイテムが item に格納される。
引数の act があらわす行動に問題がある場合は、 act の各次元の値を修正した上で、 act を返すとする。 問題が無ければ act をそのまま返すとする。
__init__ メソッドでは次を行う。
RLModel.__init__(self, simulator) を呼び出し
強化学習の学習対象(行動価値関数など)の作成
前者は親クラスの __init__ の呼び出しである。引数の simulator はシミュレータ本体である。 後者は行動価値関数などの学習対象の作成や、更新手法の作成を行うことに対応する。 メンバ変数として次の名称のオブジェクトを定義する必要がある。 オブジェクトの具体的な作成の仕方は 8.3 章 を参照のこと。
vector状態価値関数をあらわす。 状態価値関数を使用する手法の場合にのみ定義する必要がある。 シミュレーション終了後に学習結果として保存される。 状態価値関数の作成方法については 8.3.3 章 を参照のこと。
行動価値関数をあらわす。 行動価値関数を使用する手法の場合にのみ定義する必要がある。 シミュレーション終了後に学習結果として保存される。 行動価値関数の作成方法については 8.3.4 章 を参照のこと。
Actor Critic における preference をあらわす。 Actor Critic 法の場合にのみ定義する必要がある。 シミュレーション終了後に学習結果として保存される。 preference の作成方法については 8.3.4 章 を参照のこと。
Monte Calro 法における numerator をあらわす。 Monte Carlo 法の場合にのみ定義する必要がある。 シミュレーション終了後に学習結果として保存される。 numerator の作成方法については 8.3.4 章 を参照のこと。
Monte Carlo 法における denominator をあらわす。 Monte Carlo 法の場合にのみ定義する必要がある。 シミュレーション終了後に学習結果として保存される。 denominator の作成方法については 8.3.4 章 を参照のこと。
Actor Critic における critic をあらわす。 Actor Critic 法の場合にのみ定義する必要がある。 critic の作成方法については 8.3.6 章 を参照のこと。
方策・Actorをあらわす。 方策・Actor の作成方法については 8.3.5 章 を参照のこと。
学習対象の更新手法をあらわすオブジェクトを返す関数である。 返すのは 8.3.7 章 のオブジェクトとする。
RLModel.__init__ の実行後には、以下のメンバ変数が定義される。
観測値集合をあらわす。
行動値集合をあらわす。
定義された強化学習モデル(RLModel クラスを継承したクラス) は通常は直接使用せず、 RLModelSet というクラスを通して利用する。 RLModelSet は次のメソッドを持つ。
RLModelSet を作成する。各引数の意味は次の通り。
simulatorシミュレータ本体である。
強化学習モデルをあらわす RLModel クラスを継承したクラスである。
強化学習モデルの名前である。 後述する履歴やモデルの出力の際に、ファイル名の一部として使用される。
真ならば、シミュレーション終了後に強化学習の観測値・行動値などの履歴をまとめたモニタを出力する。 モニタは「name - 履歴」という名前で出力される。 ここで、name は引数で与える name である。 偽ならば出力されない。
真ならば、シミュレーション終了後に強化学習の学習結果を出力する。 学習結果は「name - 学習モデル」という名前で出力される。 ここで、name は引数で与える name である。 偽ならば出力されない。
強化学習モデルを用いて行動を取得する。 各引数の意味は次の通り。
model_id行動を提示するモデルを表す文字列である。 以前に同一の model_id で getAction を呼び出していれば、 その際と同一のモデルが使用される。 以前に同一の model_id で getAction が呼び出されていなければ RLModelSet の作成時に与えられた cls を元に強化学習モデルが作成され、 そのモデルを使用して行動が提示される。
強化学習におけるエピソードIDをあらわす文字列である。
RLModel クラスの observation 、 action 、 reward メソッドの引数に item として渡される。
偽ならば、返り値の行動に対する即時報酬値を次回の行動の取得時点で確定する。 真ならば、報酬決定関数(8.3.9 章)の呼び出し時点で確定する。
即時報酬計算のタイミングを、次回の行動の取得時点からずらさない際には、返り値は行動である。
行動の各次元の値には 行動['次元名']
でアクセスできる。
ずらす際には、返り値は行動と報酬決定関数(8.3.9 章)のタプルである。
なお、getAction を呼び出した後で、必ず setActualAction も呼び出すこと。
getAction で行動を取得した後で、実際に取られた行動を 強化学習モデルに通知する。各引数の意味は次の通り。
model_id行動を提示したモデルを表す文字列である。 引数の act を取得した際の getAction と同一の文字列を与えること。
強化学習におけるエピソードIDをあらわす文字列である。 引数の act を取得した際の getAction と同一の文字列を与えること。
実際に取った行動に対応する行動値である。
返り値は無い。
強化学習関連の各種オブジェクトの作成方法や、 オブジェクトの持つメソッドについて順に説明する。
観測値・行動値集合は、整数・実数値の閉区間または アルファベット文字列の有限集合の積集合として構成される。
整数・実数の閉区間と、アルファベット文字列の有限集合は 次で作成されるオブジェクトであらわされる。
整数値の閉区間をあらわす。引数の意味は次の通りである。
name次元の名前
取りうる値の下限
取りうる値の上限
実数値の閉区間をあらわす。引数の意味は次の通りである。
name次元の名前
取りうる値の下限
取りうる値の上限
アルファベット文字列値をとる集合をあらわす。 引数の意味は次の通りである。
name次元の名前
取りうる値(文字列)のリスト
上記で作成したオブジェクトを *
演算子により
結合したものが観測値・行動値集合となる。 なお、観測値・行動値集合が 1
次元の場合は、 以下を用いて作成する。
dim があらわす次元からなる観測値・行動値集合を作成する。
観測値、行動値は次で作成される。
valuset が表す集合の元をあらわす。観測値や行動値に対応する。
観測値、行動値の値は次で得る。
次元名に対応する値が返される。
観測値、行動値の値は次で設定する。
次元名に対応する次元に値が設定される。
状態価値関数の作成方法やメソッドについて、 状態価値関数の種別毎に順に説明する。 また、種別に関わらず備わっている共通の機能について本説の最後に述べる。
近似表現を使用しない状態価値関数は次の関数により作成できる。
引数の意味は次の通りである。
valueset状態価値関数が定義される観測値集合を表す。 実数値をとる次元の無い集合を与えること。
初期値である。全ての値はこれで初期化される。
近似表現を使用しない場合にのみ、次の関数で明示的に値を設定できる。
指定した観測値に価値を設定する。
index観測値
設定する値
近似関数として Neural Net を使用した状態価値関数は次の関数により作成できる。
引数の意味は次の通りである。
valueset状態価値関数が定義される観測値集合をあらわす。
隠れ層のニューロン数のリストである。
重みの初期値の最小値である
重みの初期値の最大値である
重みは最小値から最大値までの範囲でランダムに設定される。
近似関数として Hashtiling を使用した状態価値関数は次の関数により作成できる。
引数の意味は次の通りである。
num_tiling1 度の計算でアクティブになるタイルの個数である。
タイルの総数である。
パラメータベクトルを正規化する方法をあらわす。 の定数が指定できる。
真ならばバイアス項を持ち。偽ならば持たないことになる。
いずれの形式の状態価値関数でも価値は次で得られる。
vector は状態価値関数で、 obs は観測値である。 観測値に対応する価値が返される。
行動価値関数や preference, numerator, denominator の作成方法やメソッドについて、 種別毎に順に説明する。 また、種別に関わらず備わっている共通の機能について本説の最後に述べる。
近似表現を使用しない場合は次の関数により作成できる。
引数の意味は次の通りである。
row_valueset定義される観測値集合を表す。実数値をとる次元の無い集合を与えること。
定義される行動値集合を表す。実数値をとる次元の無い集合を与えること。
初期値である。全ての値はこれで初期化される。
近似表現を使用しない場合にのみ、次の関数で明示的に値を設定できる。
指定した観測値・行動値に対応する値を設定する。
row観測値
行動値
設定する値
近似関数として Neural Net を使用する場合は次の関数により作成できる。
引数の意味は次の通りである。
row_valueset定義される観測値集合を表す。
定義される行動値集合を表す。
隠れ層のニューロン数のリストである。
重みの初期値の最小値である
重みの初期値の最大値である
重みは最小値から最大値までの範囲でランダムに設定される。
近似関数として Hashtiling を使用した状態価値関数は次の関数により作成できる。
引数の意味は次の通りである。
row_valueset定義される観測値集合を表す。実数値をとる次元の無い集合を与えること。
定義される行動値集合を表す。実数値をとる次元の無い集合を与えること。
1 度の計算でアクティブになるタイルの個数である。
タイルの総数である。
パラメータベクトルを正規化する方法をあらわす。 の定数が指定できる。
真ならばバイアス項を持ち。偽ならば持たないことになる。
いずれの形式でも値は次で得られる。
table は行動価値関数(または preference, numerator, denominator)で、 obs は観測値、act は行動値である。対応する値が返される。
方策・Actorの作成方法やメソッドについて、種別毎に順に説明する。 また、種別に関わらず備わっている共通の機能について本節の最後に述べる。
\varepsilon-greedy な方策は次の関数により作成できる。
引数の意味は次の通りである。
table観測値と行動から、その行動の好ましさが定まるテーブルである。 必ずしも行動価値関数である必要はない。
8.3.4 章 で作成されるオブジェクトが指定できる。
\varepsilon である。 0 以上 1 以下の実数とする。 確率 \varepsilon で最適な行動を選択し、 1 - \varepsilon でランダムに行動を選択する。
生成後に、 \varepsilon の値は次のプロパティから設定・変更できる。
control は生成された \varepsilon-greedy な方策である。
Softmax 方策は次の関数により作成できる。
引数の意味は次の通りである。
table観測値と行動から、その行動の好ましさが定まるテーブルである。 必ずしも行動価値関数である必要はない。
8.3.4 章 で作成されるオブジェクトが指定できる。
温度である。正の実数とする。
観測値を o 、行動を a とすると、 各行動は \exp(table[o, a]/temperature) の比率で確率的に選択される。
生成後に、 温度 temperature の値は次のプロパティから設定・変更できる。
control は生成された Softmax な方策である。
Neural Net を使用したガウス型の方策とは 平均ベクトルがニューラルネットであるガウス分布による方策である。 観測値 s における行動値 a の選択確率がガウス分布 $ (s,a) = exp((a - (s))^T ^{-1} (a - (s)) $ により定まる。 ただし、 平均 $ (s) $ は(フィードフォワード)ニューラルネットにより定まる。
次の関数により作成できる。
引数の意味は次の通りである。
observation_valueset定義される観測値集合を表す。
定義される行動値集合を表す。
隠れ層のニューロン数のリストである。
重みの初期値の最小値である
重みの初期値の最大値である
ガウス分布の分散共分散行列を表す。 スカラー値を指定すると、\sigma^2 I が初期値として指定される。 スカラー値のリストを指定すると リストの成分を \sigma_1, \dots , \sigma_n として、 対角成分が \sigma_1^2, \dots, \sigma_n^2) である対角行列が初期値として指定される。 リストのリストを指定するとそのまま初期分散共分散行列として指定される。
重みは最小値から最大値までの範囲でランダムに設定される。
Hashtiling を使用したガウス型の方策は次の関数により作成できる。
引数の意味は次の通りである。
observation_valueset定義される観測値集合を表す。
定義される行動値集合を表す。
1 度の計算でアクティブになるタイルの個数である。
タイルの総数である。
ガウス分布の分散共分散行列を表す。 スカラー値を指定すると、\sigma^2 I が初期値として指定される。 スカラー値のリストを指定すると リストの成分を \sigma_1, \dots , \sigma_n として、 対角成分が \sigma_1^2, \dots, \sigma_n^2) である対角行列が初期値として指定される。 リストのリストを指定するとそのまま初期分散共分散行列として指定される。
いずれの形式でも、行動の選択確率が次で得られる。
control は方策である。引数の意味は次の通りである。
observation観測値である。
行動値である。
返り値として observation を観測した時に、 行動 action を取る確率密度または質量が返される。 行動集合が連続的である場合は確率密度であり、 有限離散集合である場合は確率質量となる。
Criticの作成方法やメソッドについて、種別毎に順に説明する。 また、種別に関わらず備わっている共通の機能について本説の最後に述べる。
TD(\lambda) による Critic は次で作成できる。
引数の意味は次の通りである。
statevalue状態価値関数である
即時報酬の割引率である
トレース(8.3.8 章)である
状態価値の更新に関する学習率である
Average Reward TD(\lambda) による Critic は次で作成できる。
引数の意味は次の通りである。
statevalue状態価値関数である
トレース(8.3.8 章)である
状態価値の更新に関する学習率である
即時報酬の時間平均の推定に関する学習率である
また、 Average Reward TD(\lambda) による Critic は 次のプロパティを持つ。
即時報酬の時間平均の推定に関する学習率をあらわす。 参照・設定の両方が可能である。
即時報酬の時間平均の推定値をあらわす。 参照・設定の両方が可能である。
いずれの形式でも、以下のプロパティを持つ。
状態価値の更新に関する学習率である。 参照・設定の両方が可能である。
各種更新手法を表すオブジェクトの作成方法やメソッドについて、種別ごとに説明する。 また、種別にかかわらず備わっている共通の機能について本節の最後に述べる。
Q学習をあらわすオブジェクトは次の関数により作成できる。
引数の意味は次の通りである。
value_function行動価値関数
即時報酬の割引率。0 以上 1 以下の実数値。
学習率。0 以上 1 以下の実数値。
Q学習をあらわすオブジェクトは次のプロパティを持つ。
学習率をあらわす。参照・設定の両方が可能である。
TD(\lambda) ( または Sarsa(\lambda) ) をあらわすオブジェクトは次の関数により作成できる。
引数の意味は次の通りである。
value_function行動価値関数
即時報酬の割引率。0 以上 1 以下の実数値。
トレース(8.3.8 章)である
学習率。0 以上 1 以下の実数値。
TD(\lambda) ( または Sarsa(\lambda) ) をあらわすオブジェクトは次のプロパティを持つ。
学習率をあらわす。参照・設定の両方が可能である。
Monte Carlo法をあらわすオブジェクトは次の関数により作成できる。
引数の意味は次の通りである。
value_function行動価値関数
即時報酬の割引率である。 0 以上 1 以下の実数値とする。
真偽値をとる。真ならば every-visit Monte Carlo になり、 偽なら first-visit Monte Carlo により更新される。
評価対象の方策である。省略することもできる。 省略された場合は行動価値関数から定まる greedy な方策が与えられたとみなす。
エピソードを生成している方策である。省略することも出来る。 省略された場合は evaluate_policy と control_policy が一致すると見なされる。
numerator である。指定しなくとも良い。指定しない場合は全成分が 0 で初期化される。
denominator である。指定しなくとも良い。指定しない場合は全成分が 0 で初期化される。
Monte Carlo法をあらわすオブジェクトは次のプロパティを持つ。
numerator をあらわす。取得のみが可能である。
denominator をあらわす。取得のみが可能である。
GQ(\lambda) 法をあらわすオブジェクトは次の関数によりさくせいできる。
引数の意味は次の通りである。
value_function行動価値関数
即時報酬の割引率である。 0 以上 1 以下の実数値とする。
トレースである
学習率である。0 以上 1 以下の実数値とする。
relative step size である。 0 以上 1 以下の実数値とする。
評価対象の方策である。省略することもできる。 省略された場合は行動価値関数から定まる greedy な方策が与えられたとみなす。
行動を決定している方策である。省略することも出来る。 省略された場合は evaluate_policy と control_policy が一致すると見なされる。
GQ(\lambda) をあらわすオブジェクトは次のプロパティを持つ。
学習率をあらわす。参照・設定の両方が可能である。
relative step size をあらわす。参照・設定の両方が可能である。
Actor Critic 法をあらわすオブジェクトは次の関数により作成できる。
Actor Critic をあらわすオブジェクトは次のプロパティを持つ。
actor の学習率をあらわす。参照・設定の両方が可能である。
Natural Actor Critic 法をあらわすオブジェクトは次の関数により作成できる。
actor (8.3.5 章) である。
critic (8.3.6 章) である。
actor の学習率である
アドバンテージパラメータの学習率である
Natural Actor Critic をあらわすオブジェクトは次のプロパティを持つ。
actor の学習率をあらわす。参照・設定の両方が可能である。
アドバンテージパラメータの学習率をあらわす。参照・設定の両方が可能である。
なお、具体的なアルゴリズムの形については の Algorithm 3 を参照のこと。
Eligibility Trace ( または Accumulate Trace) は次で作成できる。
引数の意味は次の通りである。
decay_rateトレースの減衰率。0 以上 1 以下の実数値。
Replacing Trace は次で作成できる。
引数の意味は次の通りである。
decay_rateトレースの減衰率。0 以上 1 以下の実数値。
報酬決定関数は、前述のgetActionを引数async_rewardをTrueとして 呼び出した際に作成される。 同時に得られた行動と紐づいており、呼び出すことで行動に対する即時報酬値を確定し、 学習モデルに通知する。
即時報酬の計算を行い、得られた値を強化学習モデルへ通知する。 ただし、既に通知済みの場合はエラーとなる。
報酬決定関数が既に即時報酬値を強化学習モデルへ通知したかどうか の真偽値を取得する。
返り値として、真偽値が返される。
いくつかの手法でベクトルの正規化手法を選択でき、 各種法をあらわす定数が次のように定められている。
正規化しない
L1ノルムで正規化する
L2ノルムで正規化する
RLModelSet を save_model = True で作成した場合、学習結果のモデルが 出力フォルダに出力される。出力されたモデルは 以下の RLModelDir クラスを通して利用する。
出力されたモデルのフォルダからモデルを読み込む。 各引数の意味は次の通り。
nameモデルのフォルダ名である。ただし「.mon」は除く。
モデルが格納されているフォルダへのパスである。
モデルを区別する id である。
RLModelDirには以下のプロパティがある。 それぞれ保存されたモデルに含まれるオブジェクトが得られる。 modeldir は RLModelDir のオブジェクトをあらわす。
観測値集合である
行動値集合である
行動価値関数である
preferenceである
numeratorである
denominatorである
状態価値関数である
方策・Actorである
S4 Simulation System Simulation Systemで粒子フィルタを使用する場合は以下の形で各クラスを利用する。 - 粒子フィルタのみを利用する場合
1. Particlesクラスを継承して粒子群を表すクラスを定義する。
2. ParticleFilterクラスを通して、粒子フィルタの各処理を実行する。
粒子フィルタを用いたエージェントシミュレーションを行う場合
Particlesクラスを継承して粒子群をあらわすクラスを定義する。
ParticleFilterAgentSetBase、ParticleFilterAgentBaseを継承した クラスを用いてエージェント集合、エージェントを定義する。各クラスの 中でParticlesまたはParticleFilterの各機能を利用する。
本章では、粒子群を表すクラスの定義に必要なParticlesクラスと、粒子フィ ルタの処理を提供するParticleFilterクラスについて説明する。なお、 ParticleFilterAgentSetBase、ParticleFilterAgentBaseについては3.3.5節、3.4.5節に詳細が記載されている。
粒子群をあらわすクラスは具体的にはssm.Particlesクラスを継承したクラスとして定義される。 以下、Particlesクラスが持つメソッドについて順に説明する。
粒子群オブジェクトを作成する。
initial_statesには、粒子群の初期状態をnumpyの行列またはモニターで指定する。各行が1つの状態を表す。
observationには、初期状態を生成する際に使用した観測値を指定する。observationは初期状態の粒子群を記録する場合に使用される。初期状態を記録しない場合には、observationを指定する必要はない。
対数尤度を計算する。継承先で必ず実装しなければならい。
statesには、粒子群の状態をnumpyの行列またはモニターで指定する。各行が1つの状態を表す。
observationsには、観測値の集合をnumpyの行列またはモニターで指定する。各行が1つの観測値を表す。 返り値として、各状態と各観測値の対数尤度を表した行列を返すとする。このとき、行列の各行は粒子の状態、各列は観測値に対応する。行列の行数はstatesの行数と一致し、列数はobservationsの行数と一致しなければならない。基本的には、観測値を\{O_1, O_2, ..., O_n\}とし、X_1, X_2, ..., X_mの粒子群の状態があれば、返り値の(i,j)成分は\log(Pr(O_j|X_i))となる。また、1要素でも有限でない値(Inf、 -Inf、 NaN)を含む列があれば、その列に対応する観測値には対応付けされない。
リサンプリング処理を行う。デフォルトでは、対数尤度loglikelihoodsの値に応じてstatesをリサンプリングする。
statesには、粒子群の状態をnumpyの行列またはモニターで指定する。各行が1つの状態を表す。
loglikelihoodsには、粒子群の状態に対応する対数尤度をnumpyのベクトルで指定する。各要素が粒子の対数尤度に対応する。
返り値として、リサンプリング結果を表すnumpyの行列またはモニターを返すとする。各行が1つの状態を表す。
直接挿入法などの別の方法を使用する場合はオーバーライドする。
粒子群の次の状態を計算する。継承先で必ず実装しなければならない。
statesには、粒子群の状態をnumpyの行列またはモニターで指定する。各行が1つの状態を表す。
返り値として、粒子群の次の状態を表す行列を返すとする。各行が1つの状態を表す。Noneを返した場合は、粒子が消滅したことを意味する。
粒子群の状態の統計量を、各次元ごとに計算する。計算の際には対数尤度に応じた重みがつけられる。
loglikelihoodsが与えられていない場合には、全ての重みを1/nとして計算する。 また、粒子群の状態がモニターで与えられており、特に文字列型の列を持つ場合には、その列に対応する位置にNanが挿入される。
stat_nameには計算する統計量を表す文字列を指定する。指定できる文字列には、mean(平均)、max(最大値)、min(最小値)、median(中央値)、sd(標準偏差)、percentile(パーセンタイル)がある。パーセンタイルの場合は、パーセンテージpを0\leqp\leq 100で指定する。
各種統計量は以下のように定義される。 \begin{aligned} \text{mean} &= \frac{\sum^{n-1}_{i=0}w_ix_i}{\sum^{n-1}_{i=0}w_i} \nonumber\\ \text{sd} &= \sqrt{\frac{m\sum^{n-1}_{i=0}w_i(x_i-\text{mean})^2}{(m-1)\sum^{n-1}_{i=0}w_i}} \nonumber\\ \text{percentile}(p) &= x_k + \frac{p-p_k}{p_{k+1}-p_k(x_{k+1}-x_k)} \nonumber\\ \text{median} &= \text{percentile}(50)\nonumber \end{aligned} ここで、状態の1つの列を\{x_i\}、観測数をn、状態に対する対数尤度を\{w_i\}、\{w_i\}に含まれる非零要素数をmとする。 また、kは、 \begin{aligned} p_k = \frac{100}{\sum^{n-1}_{i=0}w_i}(\sum^{k}_{i=0}w_i-\frac{w_k}{2}) \nonumber \end{aligned} に対して、p_k \leq p < p_{k+1} を満たすkである。
現在の状態を返す。numpyの行列またはモニターであり、各行が1つの状態を表す。
現在対応している観測値に対する対数尤度である。numpyのベクトルであり、各要素が1つの状態に対する対数尤度を表す。観測値が対応していない場合はNoneとなる。
対応する観測値を返す。
観測値による対応付けが行われる前の粒子群の状態を返す。numpyの行列またはモニターであり、各行が1つの状態を表す。
粒子が存在していればTrue、消滅していればFalseを返す。
粒子フィルタの各処理はssm.ParticleFilterクラス内に定義されている。 基本的には、次の流れでParticleFilterは使用される。
ParticleFilterを利用する側で粒子群をあらわすオブジェクトを生成し、addを通してParticleFilterに登録する。
calcNextで登録した各粒子群の次の状態を生成する。
以下を繰り返す。
消滅した(次の状態がNone)である粒子群をremoveで削除する。
filtrateを呼び出して尤度計算と対応付けを行う。
notAssociatedObservationsとnotAssociatedParticlesを確認し、必要なら以下の処置をとる。
対応が付かなかった観測値に対して粒子群を生成しaddにより登録する。
対応が付かなかった粒子群をremoveで削除する。
calcNextでリサンプリング処理と次の状態の生成を行う。
以下、ParticleFilterが持つメソッドについて順に説明する。
粒子フィルタオブジェクトを作成する。
nameには履歴を記録するモニターの接頭辞を指定する。
intervalには履歴を記録する際の時間間隔を指定する。
save_particle_historyがTrueの場合は、particleHistoryのモニターに粒子の状態が記録される。
save_associaton_historyがTrueの場合は、associateHistoryのモニターに対応付けの結果が記録される。
save_stats_historyがTrueの場合は、statsHistoryのモニターに粒子の状態の統計量が記録される。
粒子フィルタに粒子群particlesを追加する。
particlesはssm.Particlesクラスを継承したものである必要がある。
idには、particlesを区別するユニークな番号を指定する。Noneを指定した場合には自動的に決められる。
追加した粒子群に観測値observationが与えられていた場合、particleHistory、associateHistory、statsHistoryに初期状態を記録する。
粒子フィルタからparticlesを削除する。
particlesはssm.Particlesクラスを継承したものである必要がある。
フィルタリング処理を行う。 observationsには、対応付けを行う観測値をnumpyの行列またはモニターで指定する。各行が1つの観測値を表す。
具体的には、次の処理が行われる。 1. 各粒子群の状態statesをnextStatesで更新する。
全ての観測値・粒子の組に対して対数尤度計算を行う。対数尤度計算には各粒子のcalcLoglikelihoodsが使用される。
観測値と粒子の対応付けを行う。対応付け後には、各粒子のloglikelihoodsとobservationが更新される。また、対応づけされなかった観測値はnotAssociatedObservationに、対応付けされなかった粒子群はnotAssociatedParticlesに追加される。
各粒子群の次の状態を計算する。 具体的には、次の処理が行われる。
観測値と対応が付いている粒子群について、リサンプリング処理を行う。ただし、直前に生成された粒子群についてはリサンプリング処理を行わない。リサンプリング処理には各粒子のresampleが使用される。処理後は各粒子のstatesが更新される。
各粒子の次の状態を計算する。次の状態の計算には各粒子のcalcNextが使用される。処理後は各粒子のnextStatesが更新される。
粒子フィルタに登録された粒子群を表す。粒子群のIDがキーであり、値が粒子群ssm.Particlesのオブジェクトである辞書を返す。
評価時点の全体の対数尤度を返す。
対応付けされなかった観測値のリストを返す。
対応付けされなかった粒子群のリストを返す。
粒子の状態を記録したモニターを返す。
初期化の際にsave_paritcle_historyをFlaseとした場合はNoneが設定されている。以下の項目が時刻ごとに記録される。
時刻
シミュレーション時刻である。
ID
粒子群のIDである。
尤度
対応付けされた観測値との尤度である。
粒子の状態
各粒子群における粒子の状態である。状態がモニターで与えられた場合、列名はモニターの列名と一致する。 そうでない場合、列名は「状態の次元1」、「状態の次元2」、…となる。
対応付けの結果を記録したモニターを返す。
初期化の際にsave_association_historyをFlaseとした場合はNoneが設定されている。以下の項目が時刻ごとに記録される。
時刻
シミュレーション時刻である。
ID
粒子群のIDである。
観測値
粒子群に対応付けられた観測値である。観測値がモニターで与えらた場合、列名はモニターの列名と一致する。 そうでない場合、列名は「観測値次元1」、「観測値次元2」、…となる。
粒子の状態の各統計量を記録したモニターを返す。
初期化の際にsave_stats_historyをFlaseとした場合にはNoneが設定されている。以下の項目が時刻ごとに記録される。
時刻シミュレーション時刻である。
粒子群のIDである。
粒子群の状態の数である。
粒子群の状態の次元ごとの統計量である。統計量には、以下のものがある。
平均
標準偏差
95%信頼区間下限
95%信頼区間上限
変動係数
最小値
25%値
中央値
75%値
最大値
レンジ
各統計量には各粒子の尤度loglikelihoodsに応じた重みがつけられる。観測値が対応付かない場合には、尤度はすべて1/n(nは粒子数)として計算される。
状態がモニターで与えられた場合、列名はモニターの列名と統計量の名称で設定される。そうでない場合、列名は「状態の次元1の平均」、「状態の次元2の平均」、…となる。
平均、標準偏差、各分位値の定義については、8.2節 calcStatsと同様である。また、状態の1つの列を\{x_i\} 、平均をmean、標準偏差をsdとすると、変動係数cv、p * 100%信頼区間confInterval(p)、レンジrangeは以下となる。 \begin{aligned} \text{cv} &= \frac{\text{sd}}{\text{mean}} \nonumber\\ \text{range} &= \max_{0 \leq i \leq n-1}(x_i) - \min_{0 \leq i \leq n-1}(x_i) \nonumber\\ \text{confInterval}(p) &= \text{mean} \pm t_{n-1,(1-p)/2}\frac{\text{sd}}{\sqrt{n}} \nonumber \end{aligned} ここで、t_{\nu,\alpha/2}は自由度\nuのt分布の、片側確率が\alpha/2*100%となるt値を表す。
環境アイコンの一つであるSFM地図には地図編集機能があり、地図エディタを開いてシミュレーション時に用いる地図をグラフィカルに編集することができる。地図エディタには Python コンソールも付随しており、プログラム的な操作も可能になっている。
本章では、この Python コンソールから呼び出せるAPIについて説明する。
注意:下記以外の方法でこれらのオブジェクトを変更してはならない。
すべてのレイヤーを含むリストを返す。
名前が name であるレイヤーを追加する。 name = None の場合、「レイヤーX」(Xは添え字)という名前が自動的に振られる。
レイヤー layer を取り除く。
添え字 i のレイヤーと添え字 j のレイヤーを入れ替える。
正負が sign の真偽で、形状が (x, y) 座標のリスト points で表現され、属性が attrs であるユーザー定義領域を作成し、layer に追加する。
ユーザー定義領域 uregion を削除する。
ユーザー定義領域のリスト uregions を受け取り、各領域を削除する。各ユーザー定義領域は所属レイヤーが異なっていてもよい。
ユーザー定義領域のリスト uregions をグループ化する。 attrs はグループの属性となる。 uregions の各要素が同一のレイヤーに属していない場合、エラーとなる。
ユーザー定義領域のグループ ugroup を解除する。
ユーザー定義領域のレイヤー layer に対応する属性テーブルを返す。
すべての経路地点を含むリストを返す。
位置 (x, y) に半径 r の、属性が attrs である経路地点を作成する。
経路地点 pathPoint を削除する。
経路地点のリスト pathPoints を受け取り、各経路地点を削除する。
経路地点の属性テーブルを返す。
すべてのエッジを含むリストを返す。
経路地点 p0, p1 をつなぐ、属性が attrs であるエッジを作成する。
エッジ pathEdge を削除する。
エッジのリスト pathEdges を受け取り、各エッジを削除する。
エッジの属性テーブルを返す。
レイヤー、ユーザー定義領域、経路地点、エッジ、属性テーブルはそれぞれクラス Layer, UserDefinedRegion, PathPoint, PathEdge, AttributeTable で表現される。 Layer は list を継承しており、各要素が UserDefinedRegion になっている。属性テーブルは dict を継承しており、属性名と属性値がそれぞれ key と value になっている。また、これらは下記に示す独自のメソッドも有している。
レイヤーの名前を返す。
レイヤーの名前を name にする。
領域の形状を表す多角形オブジェクトを返す。
領域の形状を表す多角形オブジェクトをセットする。
属性辞書を返す。
既存の属性 attr に値 value をセットする。
領域が座標 (x, y) を含んでいれば True を、さもなくば False を返す。境界上の場合はどちらの値にもなりうる。
領域がグループなら True を、さもなくば False を返す。
領域を選択する。 shift が False なら他の選択は解除され、 True なら解除されない。
領域を構成しているユーザー定義領域のリストを返す。
経路地点の座標をタプル形式 (x, y) で返す。
経路地点の座標をセットする。
経路地点の半径を返す。
経路地点の半径をセットする。
属性辞書を返す。
既存の属性 attr に値 value をセットする。
経路地点を選択する。 shift が False なら他の選択は解除され、 True なら解除されない。
エッジがつないでいる経路地点を返す。
属性辞書を返す。
既存の属性 attr に値 value をセットする。
経路地点を選択する。 shift が False なら他の選択は解除され、 True なら解除されない。
属性 attr を追加し、デフォルト値を defaultValue とする。
属性 attr を削除する。
既存の属性 attr にデフォルト値 defaultValue をセットする。
以下のAPIで、Pythonコンソールからスクリプト管理機能を呼び出すことができる。
スクリプト名 scriptname, 内容 code のスクリプトを登録する。
スクリプト名が scriptname であるスクリプトのコードを返す。
登録されているスクリプト名のリストを返す。
スクリプト名が scriptname であるスクリプトを実行する。
スクリプト名が scriptname であるスクリプトを削除する。
バージョン番号を返す。5 つの組からなら tuple で、それぞれ、メジャーバージョン、マイナーバージョン、リビジョン、ビルドナンバー、ビルド日時を示す。
(7)