AKAGI Rails

鉄道模型シミュレーターで遊んでいたはずが、気づいたらPythonなども。

自作車両第二弾、完結

昨年7/31に先行リリースした731系に加えて、2/01にキハ201系をリリースしまして、自作車両第二弾は一応完結ということになりました。 ブログでの告知がすっかり遅くなってしまいました。

中身についてはVRM Terminalダウンロードページでたっぷりご覧ください。

f:id:AKAGI-vrmstation:20210217010835j:plain

せっかくなので、ブログではこの形式を選んだ経緯みたいなものをご紹介しましょう。

ダウンロードページから察しがついた方もあるかもしれませんが、結論から言ってしまえば、音楽館が昔出していた Train Simulator JR北海道① (函館本線余市〜小樽〜札幌)がAKAGIとこれらの形式の出会いでした。15年以上は前です(いくつだよオレ)

f:id:AKAGI-vrmstation:20210217151046j:plain

963D普通列車で小樽に到着すると731系とキハ201系の連結シーンが見られるというボーナス(?)が付いていました。これが物珍しい感じで好きでしたね。

運転ゲームにハマり直すまでずっと放置してたので、試験モードをクリアしたのは数年前と割と最近。音楽館のゲームはとにかく辛めな仕上がりで難しいのです。快速列車はまだマシですが、普通列車の山線区間は制限が多い上にダイヤがかなりキツかった。小樽では連結を含めて停車時間が10分あるので待たなくてはいけない(飛ばせない)ので、パソコンを離れて休憩してたら時間過ぎててダメになったりもしました(笑)

なんの役にも立たない思い出話をしてしまいましたが、このゲームの雰囲気を見ることができるYouTube動画を発掘しました。カッコいいオープニングと、先程も出てきた連結シーン(22分15秒~)は、ぜひとも音付きでご覧頂きたい。

このゲームもWindows95/98世代のものですから今のWindows 10では動かそうとしたことすらありませんね。動くんでしょうかね?流石にもういいですけどね(笑)

VRMNXで大型レイアウトを遊ぶときのJITレンダリングの設定について

あけましておめでとうございます。2021年もよろしくおねがいします。

さて、VRMデータ広場で先日公開となった、shirokuma氏の「複線レイアウト」をVRMNXで開いて遊ぼうと思ったところ、トラブルに遭遇しました(それで、冬休み最後の貴重な時間を4時間も溶かして解決した)ので備忘録的に書き留めておきます。

分かってしまえば簡単に解決可能なトラブルだったので、みなさんぜひ「複線レイアウト」をお手元の環境で鑑賞してみてください。4時間かけて見てみる価値のあるレイアウトでした。

続きを読む

Twitterウィジェットをクラウドから #VRMポータル #試運転中

VRMポータルでご提供しているTwitterウィジェットは、PythonプログラムでTwitter APIを叩いてツイートを収集する仕組みです。しかし最近、プログラムをホストしていたAndroidタブレットの調子が悪くてしばしば収集が停止していました。

(プログラム自体はシンプルで、動く環境さえあればいい、という感じなので、タブレットで24時間稼働させていました。USB電源で動きますしファンの音もしないのでこれはこれで良かったのです。動きさえすれば。)

最近の流行に乗っかって、Google Cloud Platformに乗せ換えることにしました。最近流行りの、クラウドコンピューティングです。

  • AWSにしろGCPにしろ、機能が色々ある・組み合わせて使うことが前提であるため、なかなか複雑で分かりにくい
  • 無料で使える使用枠もあるものの、回したいシステムがどのくらい負荷があるか、無料枠に収まるかどうかが分かりにくい

という不安要素もありますが、まずは試運転という感じです。

仕組みとしては、

  1. Cloud Scheduler で、毎日決まった時刻にPub/Subのトピックを起動する
  2. トピックをトリガーにCloud Functionsに作成したPythonプログラムが呼び出される

このPythonプログラムは、これまでローカルで動いていたものとほとんど同じです。

Sphinx-automodapiでVRMNX用パッケージのリファレンスを作る

ATENXAという名前で、VRMNXpy用のパッケージを計画中です。

f:id:AKAGI-vrmstation:20201013234850p:plain

汎用ライブラリとしてもお使いいただける機能があるので、リファレンスマニュアルを準備したいのですが、その方法をいつも忘れては調べ直している(そして、そこそこ時間がかかる)ので、備忘録として書き残しておきます。おきましたが、直後に結局方策を改めたので、以下、全面的に書き換えました。(9/22)

経過のあらまし

  • 当初、Sphinx-apidocでのドキュメント作成を計画した。
  • apidocは複雑なimport関係をもつパッケージのドキュメント化に向かないことが分かった。
  • Sphinx-autosummaryをプランBとして検討したが、構文解析中のImportError (atenxaがimportできない) により、断念した。(ディレクトリ構成は合っているはずなのだが…)
  • サードパーティSphinxむけドキュメント生成ツールとして、Sphinx-automodapiを見つけた。ユーザが使用するときのパッケージの階層構造の見た目に適応してドキュメントを作ることができるとのことで、これを採用した。

必要なもの

restructured-text (reST) や Markdown をビルドしてhtmlにしてくれる。公式ドキュメントは日本語訳が中途半端で、かつ、オリジナルの英語版も難解であり、そして、巷間のブログの情報も(少なくとも日本語では)上質なものが少ないが、Python関係のドキュメントといえばデファクト・スタンダードとなっている。Pythonパッケージとして動作するので

pip install sphinx

する。

sphinx-automodapi.readthedocs.io

これも同様に、

pip install sphinx-automodapi

する。

  • HTMLテーマ

書き出されたHTMLドキュメントの見た目のプリセットがいろいろ配布されている。有名どこだと、Read the Docsとか。

今回は、I.MAGIC御用達のMaterial for MkDocsをオマージュしたMaterial for Sphinxを使う。

pip install git+https://github.com/bashtage/sphinx-material.git
  • ダミーの vrmapi.py

VRMNX用の拡張モジュールなので、どうしてもvrmapiモジュールに依存する。しかしこれが、通常使われるPythonシステムのsite-packagesにはないので、Sphinxのパーサーが一度ATENXAのコードを実行するときに ImportError: No module 'vrmapi' was found. が出てしまう。このエラーを回避するため、ダミーのvrmapi.pyを作っておく。

このエラーは、autodocに対しては、autodoc_mock_importsオプションによってどうやら回避できるらしい。automodapiに対する回避策として適当かは未検証である。しかし、Visual Studio Code(のPython拡張)の字句解析上のエラーメッセージを封じるためにもある程度有用なので、作っておくとよい。

# -*- coding: utf-8 -*-
def LAYOUT():
    return None

def SYSTEM():
    return None

def LOG(obj):
    return

def CLEARLOG():
    return

def ImGui():
    return None

フォルダ構成

ATENXA-0.1.0alpha
├── docs
├── atenxa
│ ├── __init__.py
│ └── (他いろいろ)
├── vrmapi.py (ダミーのやつ)
└── (テスト用の.vrmnxとかいろいろ)

Sphinx のセットアップ(最初だけ)

./docs 以下にSphinx関係のもろもろをセットアップする。コマンドライン

cd docs
sphinx-quickstart

を実行すると、対話形式でいろいろ聞かれる。

Welcome to the Sphinx 1.7.1 quickstart utility.

Please enter values for the following settings (just press Enter to
accept a default value, if one is given in brackets).

Selected root path: .

You have two options for placing the build directory for Sphinx output.
Either, you use a directory "_build" within the root path, or you separate
"source" and "build" directories within the root path.
> Separate source and build directories (y/n) [n]: y

... 途中省略

For a list of supported codes, see
http://sphinx-doc.org/config.html#confval-language.
> Project language [ja]: (ENTER)

... 以下省略
  • sourceとbuildのフォルダを分けるかと聞かれるが、分けておいたほうが整理できてよい。
  • 言語を聞かれたら、jaで日本語になる。

初期設定

sphinx-quickstartをすると ./docs に色々フォルダやファイルが生成される。 そのなかで、 ./docs/souce/conf.py./docs/source/index.rst を編集する。

conf.py の設定

冒頭のコメントアウトされている3行を戻す。3行目はちょこっと編集して、atenxaパッケージとvrmapi.pyが見えるトップディレクトリを参照している。(conf.pyからの相対参照である。)

import os
import sys
sys.path.insert(0, os.path.abspath('../../'))

必要なSphinx拡張を有効化する。

extensions = [
    #'sphinx.ext.autodoc',
    #'sphinx.ext.autosummary',
    'sphinx_automodapi.automodapi',
    'sphinx.ext.napoleon',
    'sphinx.ext.viewcode',
    'sphinx.ext.todo',
    'recommonmark',
]

Sphinx拡張のオプションを設定する。

source_suffix = {
    '.rst': 'restructuredtext',
    '.md': 'markdown',
}

#autodoc_mock_imports = ['vrmapi']
#autodoc_member_order = 'bysource'
napoleon_use_rtype = False
todo_include_todos = True

テーマにsphinx-materialを指定し、細かい設定をいくつか。

html_theme = 'sphinx_material'

# Material theme options (see theme.conf for more information)
html_theme_options = {

    # Set the name of the project to appear in the navigation.
    'nav_title': 'ATENXA',

    # Set you GA account ID to enable tracking
    #'google_analytics_account': 'UA-XXXXX',

    # Specify a base_url used to generate sitemap.xml. If not
    # specified, then no sitemap will be built.
    #'base_url': 'https://project.github.io/project',

    # Set the color and the accent color
    'color_primary': 'red',
    'color_accent': 'yellow',

    # Set the repo location to get a badge with stats
    #'repo_url': 'https://github.com/project/project/',
    #'repo_name': 'Project',

    # Visible levels of the global TOC; -1 means unlimited
    'globaltoc_depth': 3,
    # If False, expand all TOC entries
    'globaltoc_collapse': False,
    # If True, show hidden TOC entries
    'globaltoc_includehidden': False,
}

index.rst の設定

indexでなくてもよいのだが、関数とその概要の一覧表を入れたい箇所に

.. automodapi:: atenxa
    :no-inheritance-diagram:

こんなのを書いておく。(TOCtreeと同じ要領である。)

ドキュメントのビルド

./docsで

make clean make html

1行目で./docs/buildを一度きれいに空にして、改めてhtmlをビルドする。

./buildにHTMLなど必要なものが書き出されるので、まとめてFTPでアップすればよい。

f:id:AKAGI-vrmstation:20201013235108p:plain

かなり良くできているSphinx-automodapiであるが、唯一心配なのは、あまりに知名度が低いことである。

参考

sphinx-rtd-tutorial.readthedocs.io

bashtage.github.io

www.sphinx-doc.org

www.sphinx-doc.org

Pydoc-Markdown をお試し

Pythonのdocstringを自動でドキュメント化するときはSphinxが定番ですが,それに代わるPydoc-Markdownというのを見つけたので,備忘録がてら紹介します。

pypi.org

インストール

pipからインストールできます。pipxでのインストールが推奨されています。私は無視して普通にpipでインストールしましたが,言われたとおりにするとしたら

pip install pipx
pipx install pydoc-markdown

どうせ必要になるので,MkDocsも入れておきます。MkDocs-Materialも。

お試し

Pydoc-MarkdownのGithubからまるごとダウンロードしてきて,Pydoc-MarkdownでPydoc-Markdownのドキュメントを作ってみます。

pydoc-markdown-develop (pydoc-markdown.yamlとかreadme.mdがあるディレクトリ) でターミナルを開き,次のコマンドを実行すると,ブラウザが立ち上がりlocalhostでドキュメントが読めます。

pydoc-markdown  --watch-and-serve -o

もう少し詳しく

pydoc-markdown.yaml の中身を見てみると,ここでドキュメントの構造をはじめいろいろなオプションを設定していることが分かります。

pydoc-markdown.yamlのひな型は

pydoc-markdown --bootstrap-mkdocs

で生成できます。

ただしコイツの書き方の詳しいところが私もよく分かっていません。pydoc-markdown-develop/pydoc-markdown.yamlを雰囲気でマネするのがいいかも。

HTML化

./docs/build をさらにMkDocsでビルドすると,HTMLドキュメントにできます。手順はCaldia氏のMkDocsマニュアルが参考になりますのでご参照ください。

蛇足

VRMNXpy用の拡張パッケージを作れないかと思っていろいろ試していますが,マニュアル作りのことも考えておかないといけません。 しかしSphinxではコードを一通り実行してdocstringを整形するので,実行中にvrmapiのImportErrorが出ると止まってしまい,うまくいきません。

その点Pydoc-Markdownは,コードを実行せずにdocstringをパースして整形してくれるので,この問題を回避できる…と思われたのですが,謎のエラーに遭遇しておりこちらもうまくいっていません。

STATIONflowも気になっている

factorioはまだロケットが打ち上がっていませんが、一旦飽きが来ました(苦笑) コロナ騒ぎで再注目を浴びたPlague Inc.というゲームもやってみました。じっくり系のゲームではなく、テーブルゲームのようなゲームサイクルの感覚でした。

ちょっと前に教えてもらった、STATIONflowというゲームも気になっています。地下鉄の駅を作り、発生する乗客の流れを満足させていくゲームのようです。

各エージェントが視野を持っていて、案内サインを見つけてそれぞれ行動を決定するという、なかなか凝った作りになっています。

続きの話はゲームと関係なくなってくるので、暇で暇で仕方がなくパソコンを閉じても他にやることが本当に無い方だけお読み下さい。

交通流ネットワークの2つの切り口

交通流ネットワークの見方には、大きく2つのアプローチがあります。 ひとつはネットワークを「静的」なものとして捉え、一定の交通フローが定常的に存在する(または、1回きりの流れが発生する)ような状態を考える切り口。もう一つは、時々刻々と流れが変化していく「動的」なものとして捉える切り口です。

「静的」なモデルでは渋滞の再現が難しいなど解析できることに限りがあるため、近年では「動的」な切り口での話が多いと思います。STATIONflowもリアルタイムにエージェントがその時の周囲の状態に合わせて行動するというものなので、「動的」な交通流シミュレーションになっています。

ところが静的モデルも結構面白い話題があるので、自分の勉強がてら紹介したいと思います。前から興味があったのでいい機会ですw

静的モデルの基本

こういう系で最も分かりやすい基本的なものは、「最大流問題」ではないでしょうか。

あなた=奉行は、江戸から上田にできるだけたくさんの物資を運ばなくてはなりません。各街道(隣接した2地点間)の人足には限りがあるので中山道だけではなく別の裏街道を使ったルートも検討することになっていますが、物資を溢れさせずに運びきれる量はいくらで、どの道にどれだけ通すのがよいでしょうか。

f:id:AKAGI-vrmstation:20200507125330p:plain
適当な地図

グラフ理論の言葉では、各地点を頂点(ノード)、街道を枝(エッジ)といいます。そして江戸-熊谷-高崎-軽井沢-小諸-上田 が中山道のルートですね。このような一連の経路のことをパスといいます。

図には書いていませんが、各枝には、人足に応じて運べる物資の上限が決まっているものとします。

本筋とは逸れますが草津を通って草軽交通のルートで軽井沢に出るルートがあったり、菅平のほうを回って直接上田に出るルートもあるのがマニアックですねw 果たしてそのルートを使ってどれだけ輸送量を増やせるのやら(笑)

交通流ネットワークの利用者均衡条件

もう少し交通流っぽい状況を考えてみましょう。交通流の場合は、シンプルな問題と違って、

  • ネットワーク内にいろいろな種類のODペア(起終点=Origin→Destinationの組み合わせのこと)の流れが発生する
  • 流量が先に決まっている
  • 混雑すると余計に時間(≒コスト)がかかる
  • 多少遠回りでも空いている道なら、早く着くので通る人が現れる

そこで、 誰もが「比べたら一番早く着く経路」を選ぶ ときに全体としてどのような流れが出来上がるか、を考えます。 このとき、例えば江戸-上田間で、中山道経由と川越街道経由の流れができたとして、「どちらの経路も結局所要時間は同じ」で「他の経路の所要時間よりも短いか、せいぜい等しい」ということが結果的に成り立ちます。なぜなら、仮にどちらかのルートのほうが早かったとしたら、より時間の掛かるルートから人が流れてきて混雑度が増し、2つのルートの所要時間が等しくなるように均衡するからです。

この均衡状態が成り立つことをはWardropの第1原則(利用者均衡条件)といいます。

新しい道ができたのに遅くなる?

直感的には納得しづらいですが、Wardropの第1原則に基づいて調べると、「道を増やすと全体の所要時間の合計が悪化する」事態が起きることがあります。この現象は「Braessのパラドクス」と名前までついています。調べるとWikipediaにも記事がありますが、平易なものでは「高校数学の美しい物語」が分かりやすいです。

mathtrain.jp

極端な例ではありますが、Wikipediaによると、「うまくない道路」を閉鎖して交通を改善した例があるそうです。

交通流ネットワークのシステム最適化

Braessのパラドクスから、利用者それぞれが自分のことだけを考えて通る道を選んでいては、利用者一人ひとりも損をするようなケースがあることが分かります。逆に言えば、社会全体として所要時間を最小化するには、別の通り方(通し方)があるということです。

このとき、先ほどと同様に、仮に中山道経由と川越街道経由の流れが決まったとして、「どちらの経路の限界所要時間も同じ」で、「それ以外の使われていない経路の限界所要時間よりも短いかせいぜい等しい」という均衡条件が成り立ちます。こちらはWardropの第2原則と呼ばれます。限界所要時間って何よ?というと、「流量を1増やしたときに余分に増える所要時間」のことです。

仮に、限界所要時間がアンバランスな状態があったとしたら、お上の目線で考えて、「限界所要時間の大きい経路」の流量を減らして「限界所要時間の少ない経路」に振り替えれば、全体の所要時間合計を短縮できてしまいます。「全体の所要時間が最小」ということは、振り替えて所要時間合計を短縮できるような経路がないということなので、先ほどの均衡条件が成り立っていることが言えます。

(ここでいう限界というのは、経済学方面で、英語のmarginalに充てられている訳語です。)

システム最適フローを求めることはちょうど、リンクコスト=各枝の交通量に対して全体に発生している費用が下に凸の多品種最小費用流問題を解くことになります。(つまり、増えれば増えるほど混雑に対応する余分なコストがかかる状態を表します。)(よね?ちょっと自信がない…) ふつうの最小費用流問題問題に比べると解くのに手間がかかります。

静的な解析の限界

こんどはmarginalの意味ではなく、limitationsですかね。

  • Wardropの第2原則(全体最適化)は、理論的に考えることはできるものの、実現についてハードルが高い。
  • 第1原則も、各交通利用者がネットワーク上の交通量や混み具合について完全に知っていることを仮定しており、この仮定は現実に成り立っているとは言い難い。 (最近は高性能のカーナビが、リアルタイムの渋滞情報に基づいて経路を計算してくれますが…。)
  • 現実には、ある程度以上の交通需要がドバっと発生すると、詰まってしまって動かなくなり、渋滞が他の道に伝播する現象が起きるが、再現できていない

などの限界があります。

おわりに

  • 駅の人の流れというと、渋谷駅が槍玉に上がることが多い気がします。銀座線乗り場のリニューアルで改札周りが混むようになったとか、東横線から井の頭線への最短ルートはサインに出ておらず隠されているとか。原理的に仕方のない部分とか、敢えて情報を歪めて全体最適に近づけているとか、そういう事情があるものと思われます。
  • 正しくないことを書いていたらごめんなさい。優しく教えて下さい。
  • こっちの方面をマジメに勉強したい場合、その手の専門書はSTATIONflowよりも高いです。