यह guide केवल जापानी में उपलब्ध है (यह मनुष्य द्वारा लिखा गद्य है, इसलिए इसमें कुछ भी machine से बदला नहीं गया है)।
Fullseye のほとんどの op は与えられた画像を測る側にいます。この族だけが反対側にいて、画像を作ります。ただし作るのは「素材」ではなく、真値が最初から付いている画像です。
3 つの入口があります。
| 入口 | 何が出るか | 何を主張するか |
|---|---|---|
| 錯視(13 op) | 1 枚の rgb | 目が否定する不変量(平行・等長・同値・共線)を、厳密に守っている |
| 無限描画(12 op) | 1 枚の rgb | 絵とは独立に成り立つ恒等式を持っている |
| 循環動画(2 op)+ 状態(3 op) | rgbvideo / table | 継ぎ目が無いことを、構成から保証している |
新しい型語は 1 つも作っていません。返りは既存の rgb(H,W,3)・ rgbvideo(T,H,W,3)・table だけです。「錯視画像」という特別な型を作らない のが設計の中心で、作った絵に既存の 2,000 以上の op がそのまま掛かることが、この族の値打ちそのものだからです。
装飾だからではありません。錯視は「見た目は確かめの役に立たない」ことの、最も純粋な実例だからです。
illusion_cafe_wall の目地は厳密な水平線です。illusion_muller_lyer の 2 本の軸は厳密に等長です。illusion_checker_shadow の 2 マスは浮動小数として同じ値です。見えているものが違う、というだけ。
そして面白いのはここから先で —— 錯視は人間の目だけを騙すのではありません。illusion_muller_lyer の図で「行の黒い区間」を素朴に測ると、2 本の軸は 223 画素と 225 画素になります(矢羽根の反エイリアスの裾が軸の端に乗る)。素朴な計測も 2 画素ずれる。だからこの族は、測る側の採点表として使えます。
Mermaid diagram (source):
flowchart LR
G["illusion_cafe_wall<br/>illusion_checker_shadow<br/>…13 op"] -->|rgb| M["既存の計測 op<br/>(threshold / blob / measure1d …)"]
G -->|table| T["illusion_ground_truth<br/>目が否定する不変量"]
M --> C{一致するか}
T --> C
C -->|一致| OK["測る側は目に騙されていない"]
C -->|不一致| NG["測り方の欠陥が見えた"]
perpetual_ten_print(Commodore 64 の一行プログラム)、perpetual_elementary_ca(Wolfram の 256 規則)、perpetual_langtons_ant、perpetual_chaos_game、perpetual_apollonian、perpetual_harmonograph、perpetual_ifs_attractor、perpetual_flow_field、perpetual_reaction_diffusion、perpetual_plasma、perpetual_truchet —— どれも「いつ止めても途中」なので、絵の見た目では採点できません。
そこで、絵とは独立に成り立つ主張を持つものだけを入れました。perpetual_identities が 6 本まとめて実測で返します。
| 系 | 恒等式 | 実測の残差 |
|---|---|---|
| 規則 90 | 第 n 行 = C(n,k) mod 2(リュカの定理) | 0.000e+00 |
| ラングトンの蟻 | 周期 104 で同じ斜め (2,2) を繰り返す | 0.000e+00 |
| アポロニウス | (Σk)² = 2Σk²(デカルトの円定理) | 1.19e-16 |
| 流れ場 | div(curl ψ) = 0(非圧縮) | 6.95e-17 |
| 反応拡散 | 餌も死も 0 なら総量保存 | 1.98e-16 |
| プラズマ | 4 隅は最後まで書き換えられない | 0.000e+00 |
1 枚返す生成器だけでは「無限に描き続ける」ことになりません。だから 状態 → 進める → 描くの 3 本組を置いてあります —— perpetual_state / perpetual_step / perpetual_render。op の側は「いつ止めるか」を決めません。
import fullseye as fs
s = fs.ledger.perpetual_state("langtons_ant", size=301)
s = fs.ledger.perpetual_step(s, 12_000) # 好きなだけ回してよい
img = fs.ledger.perpetual_render(s) # 何歩目で描いてもよい
ident = fs.ledger.perpetual_identities() # 絵を見ずに採点する
print(dict(zip(ident["system"], ident["residual"])))
状態の宣言型は table ですが、table は広い型です。無関係な表を渡されたら KeyError ではなく「これは perpetual の状態ではない」と明示的に拒否します(fail-closed)。
perpetual_loop は継ぎ目の無い動画を返します。ここは作り方が要点で、「最後に頭へ戻す」のではありません。時間依存の量をすべて θ の関数にして θ = 2πt/T を回すと、t = T は t = 0 と同じ式になります —— つまり継ぎ目は最初から存在しません。編集で消す種類のものではなく、構成から従います。
perpetual_loop_seam がそれを数で出します。読み方に注意が要ります:
> 比が 0 ではなく 1 に近いのが正解。 比 = (最後のまたぎの差) ÷ (ふつうのコマ間の差)。1 なら「最後のまたぎが、ほかのまたぎと見分けが付かない」。0 なら継ぎ目が無いのではなく、動きが止まっているという意味になります。
v = fs.ledger.perpetual_loop("plasma_orbit", frames=48, size=360)
m = fs.ledger.perpetual_loop_seam(v)
print(float(m["ratio"][0])) # 0.99〜1.02 なら継ぎ目なし
向く: 測る側の採点(錯視図 + illusion_ground_truth)、尽きない試験入力、周期境界を持つ時間方向 op の素材、真値つきの合成データ。
向かない: 「作品」としての完成度。この族は主張が検算できる図だけを持っていて、美しいが検算できない図は入れていません(illusion_ebbinghaus / illusion_zollner / illusion_ponzo / illusion_poggendorff / illusion_fraser_spiral / illusion_kanizsa / illusion_hermann_grid / illusion_scintillating_grid / illusion_simultaneous_contrast はいずれも不変量を持ちます)。
どれも絵を見ても気づけない型でした。
1. 二項係数を int64 で積んでいて、C(62,31)×31 で黙って溢れた。リュカの定理「C(n,k) が奇 ⟺ (n&k)==k」に置き換えて、桁あふれの余地を消した。
2. illusion_checker_shadow で対にするマスを間違えていた(同じ明暗のマスを 2 つ選んでいた。差 0.31)。対にすべきは「影の外の暗マス」と「影の中の明マス」。
3. 定数の配列でも std() は厳密に 0 になりません(平均を引く途中で 1 ulp 残る、実測 5.6e-17)。「全部同じ値」を厳密に言うなら ptp(最大 − 最小)を使います。