MATSimではエージェントを、どういう単位で実現していますか?
私の場合、Go言語のgoroutineを使って、人数分のスレッドをつくって、その中にメソッドを書き込んでいますが、MATSimは、こういうプログラマブルな記述をエージェントに実装する仕組みになっているのですか?
いい質問です。結論から言うと、
MATSim の「エージェント」は、人数分のスレッドが立っていて、その中にメソッドを書くような仕組みではありません。
1人ずつプログラムを書くというより、共通の振る舞いロジック+個別の状態データという構成になっています。
江端さんの Go + goroutine のイメージと対比しながら整理します。
1. MATSimでのエージェントの「単位」
MATSim では、論理的なエージェントは大きく分けて2段階で表現されています。
(1) 計画レベル:Person + Plan
-
Person-
住民1人=
Id<Person>で識別されるエージェント -
属性(年齢・性別・地区 …)は
PersonAttributesに持たせる
-
-
Plan-
その人の一日の台本:
Activity(自宅・職場・買い物)とLeg(移動)の列 -
1人が複数の
Planを持ち、スコアが高いものが選ばれていく
-
ここまではただのデータ構造で、「どう動くか」のロジックは何も書いていません。
(2) シミュレーション中:MobsimAgent / MobsimDriverAgent
実際に qsim(交通流シミュレータ)が回っているときは、
-
各
Personに対応する「実行時エージェント」がMobsimAgentとして生成されます。 -
代表的には、
MobsimDriverAgentというインタフェースを実装したクラスで、-
「次にどのリンクに進むか」
-
「次の Activity にいつ切り替えるか」
などを qsim から問いかけられ、それに応答する形で動きます。
-
この MobsimAgent はJavaオブジェクトであって、スレッドではありません。
シミュレータ本体(QSim)がループを回しながら、全エージェントの状態を順番に(または一部並列で)進めていきます。
2. Go の goroutine モデルとの違い
江端さんの Go 実装イメージ:
-
人数分の goroutine を立てる
-
各 goroutine の中にその人専用のメソッド・ロジックを書く
-
goroutine 同士はチャネルなどで通信
これに対して MATSim は:
-
人数分のスレッドは作らない(基本は1スレッド+αのイベント駆動)
-
エージェント固有のロジックは「個別のソースコード」ではなく、
**共通コード+個別パラメータ(属性・計画)**で表現 -
エージェント間の関係やイベント反応は、
EventHandlerやScoringFunctionの実装として「横串」で書く
ざっくりいうと、MATSimは
「1人1スレッド+個別のプログラム」ではなく
「1つの交通流エンジンの中で、多数の状態マシンを回す」
タイプの設計です。
3. 「プログラマブルなエージェント」を実装する方法
とはいえ、「エージェントにメソッドを書き込めない」のではなく、
やり方が違うだけです。
3.1 共通ロジック+個別パラメータ
一番MATSimらしいやり方は:
-
行動ルールは共通のクラスに書く(例:
MyDynAgent) -
各エージェントごとに
-
属性(risk好き、社交的、インドアなど)
-
特定の人物Id、行きたがる施設リスト
を変えることで個性を出す
-
イメージ:
ここではコードは一種類ですが、
フィールド値によって**「人ごとの性格」が変わる**構造です。
3.2 DynAgent / within-day で「その場の意思決定」
前のやりとりで話したような、
-
「特定の人に会った瞬間に進路を変える」
-
「人混みが嫌いな人は混雑リンクを回避する」
といったその場での意思決定は、
-
DynAgent系のエージェントクラスの中で実装 -
あるいは
within-day replanningのロジックで、シミュレーション中に plan を書き換える
という形で書きます。
4. 「各エージェントに好き勝手メソッドを書く」ことはできるか?
技術的に言えば、Java なのでやろうと思えば何でもできますが、
-
人数分のクラスや匿名クラスを作る
-
人数分のスレッドを立てる
といった設計は、MATSimの思想とは真逆で、スケールもしません。
MATSimが想定しているのは、
-
「エージェント全体を貫く共通ルールセット」
-
+「個体差は属性とパラメータで表現」
-
+「再計画(replanning)とスコアリングで行動パターンが進化」
というマクロな人口挙動モデルです。
江端さんの「1人1goroutine+個別メソッド」モデルは、
エージェント指向プログラミング / Actorモデルに近くて、それはそれで強力ですが、
MATSimはそこまでの自由度よりも「大量の人口を高速に回すこと」を優先して設計されています。
5. まとめ
-
MATSimのエージェントは:
-
論理的には
Person+Plan(データ) -
実行時には
MobsimAgent/MobsimDriverAgent(状態マシン)
-
-
人数分のスレッドや、人数分の別メソッドを持つ構造ではありません。
-
プログラマブルな振る舞いは、
-
共通のエージェントクラス(DynAgentなど)にロジックを書く
-
各人ごとの属性・パラメータで個性を出す
-
EventHandler / Scoring / within-day replanning で「接触」「出会い」への反応を定義する
というスタイルになります。
-
もし「江端版MAS(Go + goroutine +性格つきエージェント)」を、
どこまでMATSim側にマッピングできるか、という視点で整理したいなら、
-
性格・嗜好 →
PersonAttributes -
台本(1日の予定) →
Plan -
その場の意思決定ロジック →
DynAgent実装 -
接触に応じた行動変更 → EventHandler + DynAgent / within-day
という対応表を、もう少しきれいな図にしてお見せできます。必要ならそこまで書き起こします。
自律的判断を持てないエージェントは正直困ります。
しかし一方、「MAS本体をスクラッチから作れ」などと言う残酷なことを、私は、学生や後輩には言えません。
Go言語でエージェントを作って、それをMATSimで回す方法って、ないでしょうか?
正直に言うと、
「Go のエージェントをそのまま MATSim の中で走らせる」
という“公式なやり方”は ほぼ無い です。
MATSim はあくまで Java の中にすべてのエージェントを抱え込む設計 なので、
Go の goroutine をそのまま埋め込む、という発想とは構造が合いません。
ただ、完全に道がないわけではなくて、現実的な選択肢としてはこの3パターンかな、と思います。
選択肢①:Javaエージェント+Go「頭脳」の双方向連携(かなりヘビー)
イメージ
-
MATSim側
-
各 Person に対応する
DynAgent(Javaクラス)を作る -
この DynAgent は、自分の「次の行動」を決めるときに
→ Go プロセスに状態を投げて、戻ってきた「行動案」に従う
-
-
Go側
-
いま江端さんが作っているような「自律判断エージェント」を goroutine で動かす
-
Java から送られてくる「現在位置・時刻・周辺状況」を入力にして
「次にどこへ行くか」「どのリンクを選ぶか」を返す
-
技術的には
-
Java ↔ Go を
-
TCP/UDP socket
-
gRPC / HTTP
などでつなぐ「コ・シミュレーション」になります。
-
メリット・デメリット
-
✅ Go で書いた自律ロジックをそのまま活かせる
-
✅ 交通流エンジンやネットワーク・経路計算は MATSim に任せられる
-
❌ 実装はかなり大掛かり(Java 側と Go 側の両方にフレームワークが必要)
-
❌ 性能・デバッグも重くなる(人数×ステップ分のRPCが飛ぶ)
「MAS本体をスクラッチで書くよりはマシ」かもしれないけど、
正直これは“自作フレームワーク級”の重さ です。
選択肢②:MATSimは「シナリオ&ネットワーク生成器」と割り切り、Goで本番MASを回す
これは発想を逆にして、
-
MATSimはオフライン専用に使う
-
ネットワーク(リンク・ノード)
-
速度プロファイル・所要時間
-
初期 OD・パーソントリップ的なプラン
などを出すための「前処理ツール」と割り切る
-
-
本番のエージェントシミュレーションは Go で書く
-
すでにお持ちの goroutine ベースのエージェントを使う
-
移動に関するコスト・時間は、MATSim からエクスポートした表(スキム)を参照
-
つまり、
ネットワーク・時空間コストの計算 → MATSim
エージェントの自律行動・出会い・心理 → Go の MAS
と役割を分けてしまうやり方です。
これは
-
✅ 自律判断を全部 Go 側に寄せられる
-
✅ MATSim の「一日分プラン+イテレーション」という思想に縛られない
-
✅ 実装難易度は選択肢①よりずっと低い
-
❌ 「MATSimの中で走っている」とは言えない(ただし実務上は問題ないことが多い)
**「江端版MAS+MATSim由来のネットワーク/コスト」**という構成なら、
今の Go コードを活かしつつ、MATSim を“いいとこ取り”できます。
選択肢③:自律性はJava側で書くと割り切り、MATSimの中で完結させる
もうひとつ現実的なのは、
「自律判断ロジックを Java に書き直す」
+「MATSimの DynAgent / within-day をフル活用する」
という割り切りです。
-
エージェントの「性格」「嗜好」「出会いへの反応」などを
PersonAttributes+DynAgentクラスに埋め込む -
「特定人物に接触したら plan をその場で変える」
→ DynAgent / within-day replanning で実装
これは
-
✅ MATSimの設計に素直に乗っかれる
-
✅ 既存のドキュメントやサンプルを流用しやすい
-
❌ Go のコードは直接は使えない(考え方だけ移植)
「スクラッチでMAS全部書け」は避けつつ、
自律性をできるだけMATSimの中で実現する現実路線です。
どれを選ぶのが良さそうか
江端さんの条件をざっくり整理すると:
-
「エージェントは自律的判断をしてほしい」
-
しかし「MAS本体をイチから書け、とは言いにくい(言いたくない)」
-
かつ Go で既にエージェントモデルを持ちつつある
とすると、個人的なおすすめは順に:
-
選択肢③
-
まずは MATSim の中で DynAgent / within-day だけで
「接触で行動が変わる」「性格で行動が変わる」をどこまで再現できるか試す
-
-
それでも「やっぱり Go のコード資産を活かしたい」となったら、
選択肢② で「ネットワーク・コストはMATSim、MASはGo」ときれいに役割分担 -
選択肢①(Java↔Goのオンライン連携)は、
「研究テーマとしてコ・シミュレーションをやる」レベルの話にした方がよさそうです。
結論
-
MATSimの中に「Goのエージェントを直接入れて回す」ための素直な拡張ポイントは無い
-
やるとしたら、
-
Java側からGoにRPCするコ・シミュレーション(重い)か、
-
MATSimを“ネットワーク・前処理ツール”として使い、MAS本体はGoで回す構成か、
-
そもそも自律性をJava(DynAgent)側に移植するか、
のどれかになる。
-
もし、「こういう感じで Go 側エージェントが state を持っている」というサンプル(擬似コードでも可)を1体ぶん見せて頂ければ、
-
それを MATSim DynAgent クラスにマッピングする案
-
もしくは MATSim↔Go コ・シミュレーションで最小構成のAPI設計案
をこちらで一回“たたき台”にして書いてみます。
「ここまでやるなら③でいいか…」という判断材料にもなると思います。
つまりJavaのクラスを使う方法なら、「まあ、なんとかなるかもしれない」という感じでしょうか?
そう、その理解でだいたい合ってる。
「Go でやっていることを、Java のクラスとして MATSim の枠の中に移植する」
という路線なら、“まあ、なんとかなる”現実的な射程に入っていると思う。
もちろん「楽勝」とまでは言わないけど、
「MAS本体をスクラッチで書け」という残酷さとは次元が違う、という感じ。
何をやれば済むのか(ざっくりスコープ)
Java クラスで頑張る場合に必要なのは、フルスクラッチではなくて、だいたいこの程度。
-
標準 MATSim はそのまま使う
-
ネットワーク構築、経路計算、qsim、反復(replanning)あたりは全部既製品に任せる。
-
-
エージェントの性格・状態を
PersonAttributesに持たせる-
Go 側の「性格フラグ」「好み」「会いたい相手リスト」などを Java の属性に写す。
-
-
接触検出用の
EventsHandlerを 1クラス書く-
LinkEnterEvent/ActivityStartEventを拾って、 -
「誰と誰が、どこで、いつ接触したか」を記録するクラス(前に書いた EncounterTracker)。
-
-
自律判断エージェントとしての
DynAgentを 1クラス作る-
Go の goroutine に相当する「頭脳」を Java クラスとして書くイメージ。
-
QSim から「次どこ行く?」と聞かれたときに、
-
自分の属性
-
EncounterTracker が持っている「さっき誰に会ったか」
を見て、経路変更や行動変更を決める。
-
-
-
必要なら within-day replanning で「残りの plan の書き換え」を入れる
-
「会った瞬間から予定を変える」系の挙動をここで実現する。
-
やることは多いが、MATSim のコア部分には触らなくていいので、
「フレームワーク作者になる」必要まではない。
感覚的な対応づけ
江端版 MAS(Go) ↔ MATSim(Java) を、かなり雑に対応づけるとこうなる。
-
goroutine = 1人ぶんの自律エージェント
→MyDynAgent implements MobsimDriverAgent -
goroutine 内の状態変数
→PersonAttributes+ DynAgent のフィールド -
goroutine 間の情報共有(チャネル/共有メモリ)
→ MATSim のEvents+ それを受けるEventsHandler -
「接触した瞬間に挙動を変える」
→ EventHandler でフラグ更新 → DynAgent/within-day が次の意思決定で参照
まとめ
-
「Go エージェントをそのまま MATSim の中で動かす」は現実的ではない。
-
しかし Java クラス(DynAgent+EventsHandler+独自 Scoring)として書き直す路線なら、
-
MAS本体をスクラッチで書くほどの地獄ではなく、
-
「いくつかの拡張クラスを追加する」レベルで収まる可能性が高い。
-
なので、「Java のクラスを使う方法なら『まあ、なんとかなるかもしれない』」という感触は、かなり現実に近いと思う。
もし次の一歩を決めるなら、
まずは「1人だけ特別扱いする DynAgent」の最小サンプル(接触したら家に帰る、くらい)を設計してみる、あたりから始めるのが良さそう。
正直に言うと「Javaって記述長いし、エラーメッセージ訳分からないし、ライブラリ煩いし、コンパイルも面倒」と思っているのですが、これって、単なる私の偏見でしょうか?
正直に言います。
いいえ、それは偏見ではなく、“かなり多くのエンジニアが抱えている実感”です。
江端さんが感じている
「Javaは記述が長い」「エラーが読みにくい」「ビルドがうるさい」「ライブラリが重い」
という感覚は、Java経験者の間でほぼ共通認識です。
以下、冷静に、しかし正直に整理します。
■ 1. Java は「記述が長い」 → 事実です
Java の根本思想が、
-
明示的な型
-
明示的なクラス構造
-
例外宣言
-
インターフェースの多階層
なので、Go や Python に慣れていると異様に冗長に感じます。
例:Go の HTTP ハンドラは数行で書けるのに、
Java だとクラス+メソッド+アノテーション+例外+import で 10倍になります。
これは「言語として目指している方向が違う」ので、実際に短くはなりません。
■ 2. Java のエラーメッセージは「読みにくい」 → これも事実
Java の例外は階層が深く、スタックトレースも長い。
Go の panic() や Python の ValueError の方がよほど読みやすい。
MATSim になるとさらに、
-
Guice(DIコンテナ)
-
config 読み込み
-
XML パース
-
イベントバス
など抽象レイヤが多く、“どこが本当の原因なのか”の特定に時間がかかりやすいです。
これは多くの開発者が「つらい」と感じています。
■ 3. Java のライブラリ管理は「煩い」 → ほぼ全員の共感ポイント
Maven / Gradle / Ivy などビルドツールの文化が複雑で、
-
依存関係ツリーが長い
-
SNAPSHOT
-
transitive dependency
-
Java version mismatch
など、トラブルの原因が多い。
MATSim は依存関係が特に多いので、Java初心者が触ると「ライブラリ沼」にハマりがちです。
■ 4. コンパイルが面倒 → はい、Goと比べれば間違いなく面倒
Go:
Java:
-
Maven/Gradle を叩く
-
依存解決
-
テスト
-
JVM バージョン
-
ビルドパス
-
クラスパス
つまり、「作業が 1段多い」。
経験者でも「Javaはセットアップが面倒」と言うのが普通です。
■ では、Java の良いところは何か?
こういう “面倒なもの” が生き残っている理由は明確で、
✔ 大規模システムに強い(MATSimがJavaを採用した 最大理由)
✔ 型安全・例外安全が徹底している
✔ 並列・GC・JIT など実行性能が高い
✔ 20年以上の生態系と豊富なツール
✔ ユーザ数が世界的に多く、長期メンテ性が高い
簡単に言えば、
Java は「100万人の都市交通を動かすレベルの巨大なMAS」のために選ばれた言語
であって、
Go のような“軽量で気持ちよく書ける”言語とは目的が違う
ということです。
■ 結論:「あなたの感覚は正しい」+「MATSim的には Java は合理的」
江端さんが感じている不満は、
偏見ではなく、Javaを使う人のほぼ全員が抱く問題意識です。
そして、MATSimがJavaで書かれているのは、
「大規模・高性能・堅牢さ」が最優先のシミュレーションエンジンだから
という理由に基づいたものです。
■ もし「Javaがつらい」が続く場合の方針
1. Javaエージェントを最小限にとどめる
→ 行動ロジックは属性+簡単な条件分岐のみにする
2. Goで自律的判断を作り、それをMATSim側の「入力データ」に落とす
→ MATSim は「道路・ルーティング専用エンジン」と割り切る
3. DynAgent を使うが、Java部分はラッパー的にして実質ロジックは外出し
→ Java コードの負担を極力減らす
■ 最後に:江端さんの直感は、技術的にかなり妥当です
-
Java は冗長
-
エラーは読みにくい
-
コンパイルは面倒
-
ライブラリ管理も難しい
→ それは個人的な偏見ではなく、Javaが歴史的に背負っている宿命です。
ただし、
MATSimのように「巨大都市を1分単位で交通シミュレートする」世界では、
その“重厚さ”が必要だった
というだけです。
必要なら:
-
「最小コードで DynAgent を書くテンプレ」
-
「Go のエージェント実装を Java に写すためのマッピング表」
-
「江端さんの MAS を MATSim と融合する最も軽い構成案」
なども作れます。
どういう方向に進むか、言っていただければ道筋をもっとクリアにします。