見出し画像

Sprott のコードとストレンジアトラクタ探索機

はじめに

 ストレンジアトラクタというものがある。これは、非常に簡単な数式であるにも関わらず、複雑かつ美しい模様を浮かびあがらせるものであり、摩訶不思議である。

これらは前世紀の半ばより研究されているが、それらが描き出す模様についてのカタログは無いようである。というわけで、今回は、これらストレンジアトラクタのカタログを生成するために、探索機を造ったのでそれを紹介する。

探索機といっても実態は Processing のプログラムである。後ほどプログラム全体を掲示するので、是非とも実際に手を動かして、ストレンジアトラクタの宇宙探索を体験してもらいたい。

 探索には後述するストレンジアトラクタの ID が必要となるが、この ID を発見するプログラムも近日中に公開する予定である。であるので、本稿をご覧になった皆様においては、それを楽しみにしつつ、探検の経験値を上げておいていただければ、と思う。

後述するが、インターネットでいくつかこれら ID を見つけることもできるし、付録として本稿の末尾に面白そうな ID を列挙しておくので、それを入力して出来上がる画像を眺めるのも楽しいと思う(ちなみに本稿のタイトル画像の ID は FIVVUWCSOTTX である)。

開発の経緯

 さて、ストレンジアトラクタに話を戻そう。ストレンジアトラクタとして有名なものは、ローレンツが発見したアトラクタ(ローレンツアトラクタ)がある。その他にも有名なものはいくつか存在する。おそらくそれらを作品に使ったところで、「ああ、あれね」と思われてしまうのが関の山だろう。そのような反応をされると、作りてとしてはちょっと寂しい。できれば、まだあまり知られていないストレンジアトラクタを見つけて、あわよくば作品に応用したいものである(下心ありありである)。

とは言え、積極的にストレンジアトラクタを探す訳でもなく、何かのついでに見つけられたら良いなぁ、と私は漠然と日々を過ごしていた。

 そんな中、先日、ギンさん( @gin_graphic さん )による次のような tweet を拝見した。

すごい。この発想は無かった。なんか面白い式ないかなー、と漠然と日々を過ごしている私とは大違いである。受け身で漠然と過ごしていた己の姿を私は恥じた。

 確かに、既存のストレンジアトラクタを合成して、オリジナルなものを作ってしまえば良いのだ。そうすれば、おそらくまだ誰もが知らない形状が描画できる。なければ作る - これこそがプログラマというかエンジニアとして持っていなければならない最も大切な心がけのひとつである。

ギンさんの素晴らしい tweet を読んで、ものぐさな私はふと思った。合成すらコンピュータにまかせて、ある意味、新しいストレンジアトラクタを収穫することはできないだろうか - と。ものぐさパワー全開である。

 早速、それらしいキーワードで検索すると、ストレンジアトラクタの自動生成について書かれた論文が見つかった。この方法をつかえば、濡れ手に粟で新しいストレンジアトラクタの式を難なく手に入れられるのではないか。というわけで、しっかりと論文を読み込むこととした。

ちなみに、この論文は J. C. Sprott 著の "Automatic Generation of Strange Attractors" というものである。PDF  が公開されているので、興味の有る方は以下のリンクから入手すると良い。

https://sprott.physics.wisc.edu/pubs/paper203.pdf

対象とするストレンジアトラクタの形式と ID について

 この論文で Sprott が調査対称としている式は、

newX = a1 + a2*x + a3*x*x +  a4*x*y +  a5*y +  a6*y*y
newY = a7 + a8*x + a9*x*x + a10*x*y + a11*y + a12*y*y

という形のものである。こんな簡単な式であっても、以下に示すような複雑な図形を生成する。

言うまでもないが、これらの式は a1 から a12 の値の組み合わせにより表現される。Sprott はこれらのパラメータを、-1.2 から +1.2 まで 0.1 刻みで量子化し、それらを魅力的かどうかの調査対称とした。

なぜこの範囲なのかということについて、Sprott は言及していない。ただ、-1.2 を A という文字で表し、-1.1 を B などとすると、-1.2 から +1.2 までの数値は A から Y の 25 文字で表されることを示唆している。

これから考えると、おそらく文字列としてそれぞれのアトラクタを識別したい - という考えがあり、それ故に -1.2 から +1.2 まで 0.1 刻みにしたと考えるのが妥当であろう。

 少し話が横道に逸れた。とにかく、この Sprott の方法により、Sprott が対称とした力学系は 12 文字からなる文字列で一意に表すことが可能となる。

ちなみに上に示した画像のパラメータは DNSPKJUBEAIG である。以後、これをアトラクタの ID と呼ぶ。

 ID と力学系の各係数 - つまり a1 や a2 といった値とは 1 対 1 の関係がある。言い換えれば、ID さえ分かればアトラクタの軌道は計算可能となる。以下の図は、ID のみを指定して後述する探索プログラムで生成した画像である。

これは別の記事で紹介する予定の、ストレンジアトラクタ発見プログラムにより得られた ID である HCEAGYKUKKWT という情報のみから生成している。

ID: HCEAGYKUKKWT

なぜ探索用プログラムが必要なのか?

 発見用プログラムがあるならば、それだけで良いではないか? - と思われるかもしれない。しかし、発見プログラムはランダムにパラメータを決め、それがストレンジアトラクタの可能性があるか否かを計算し、可能性のあるものだけを表示する。

しかし、一度見つかったストレンジアトラクタの周辺、つまり ID が 1 文字だけ異なるようなものもストレンジアトラクタとなる場合がある。このような 1 文字だけ異なる ID は発見プログラムではおそらく出てこない(出てくる可能性もあるが、その確率は非常に低いものとなる)。

 このような事情があるために、探検用のプログラムが必要であるのだ。得られた ID をほんの少しだけ変更し、それが魅力的な図形を生成するか否かを調べていかなければストレンジアトラクタのカタログは完成しない。

 上に示した図の ID は HCEAGYKUKKWT であった。2 文字目を C から D に変更した HDEAGYKUKKWT を指定して、探索用ソフトウェアで画像生成させてみると次のような図が得られる。

発見用ソフトウェアのみを使用していたなら、おそらくこのストレンジアトラクタの画像を私は見ることはなかっただろう。周辺 ID のアトラクタという考えをもったからこそ得られたストレンジアトラクタだと思う。

 このような訳で、ストレンジアトラクタカタログ作成のためには、発見・探索という段階に分ける必要があるのだ。これらを簡単にまとめた記事も記しているので、興味があればご覧になっていただきたい。

探索用プログラム Strange Attractor Explorer

 ストレンジアトラクタ探索用のソフトウェアは Processing で動作するものであり、そのプログラムリストを以下に示す。

使い方は、プログラム冒頭にある ID の値を使用者が自ら変更し、実行する。対称の ID を入力するようなインタフェイスは存在しない。研究用の質実剛健なプログラムとはそういうものなのだ…といえれば格好もつくが、実際のところ Processing で GUI を作る方法を私が知らないだけである。

このプログラムはあくまで探索用であるので、周辺 ID の値によっては何も表示されない場合も存在する。もちろん、運良く表示された場合には、それらを画像ファイルとして保存しておく必要がある。画像ファイルとして保存したい場合は、表示されている画像をクリックして欲しい。

クリックすると、Processing のコンソールエリアに "Generating HiRes Image …" と表示される。暫く待つと(M1 の mac book air で大体数秒程度)、同じくコンソールエリアに "Done." と表示される。これで、そのスケッチのフォルダに ID をファイル名とする画像ファイルが生成されているはずである。

ちなみに画像ファイルは .jpg と .png の 2 種類を生成している。JPEG の方はネットに投稿するように解像度 500x500 の画像を、PNG の方は印刷用を考慮して 2000x2000 ピクセルの画像を生成している。必要に応じて使い分けてくれれば…と思う。

まとめとお願い

 このプログラムはストレンジアトラクタカタログの作成を期待して公開する。そのため、魅力的なストレンジアトラクタを見つけたら、その画像とともにハッシュタグ #StrAttrCat を付けて tweet してもらえたら、と思う。

# strange atractor explorer by Sprott's ID
# program by Koji Saito 2022 (Twitter: @KojiSaito )

ID="DNSPKJUBEAIG"

# -----
N=1000
W=500;H=500
UseColor=True

A=[(ord(ID[i])-77)*.1 for i in range(12)]
ColorH=538
for c in ID:ColorH=ord(c)+ColorH*33
ColorH%=251

def next(x,y):
    u=A[0]+x*(A[1]+A[2]*x+A[3]*y)+y*(A[4]+A[5]*y)
    v=A[6]+x*(A[7]+A[8]*x+A[9]*y)+y*(A[10]+A[11]*y)
    return u,v

def iterate(x0,y0,n,f=None):
    x,y=x0,y0
    for i in range(n):
        u,v=next(x,y)
        if f!=None:f(u,v)
        x,y=u,v
    return x,y

Xmin=Ymin=1e300;Xmax=Ymax=-1e300
def updateRange(x,y):
    global Xmin,Xmax,Ymin,Ymax
    Xmin=min(Xmin,x);Xmax=max(Xmax,x)
    Ymin=min(Ymin,y);Ymax=max(Ymax,y)

# main routine
x,y=iterate(.05,.05,1000) # ignore first 1000 iterations
iterate(x,y,N,updateRange)

Sx=W/(Xmax-Xmin)*.9;Sy=H/(Ymax-Ymin)*.9

PlotColor=color(-1,50)
def setup():
    global PlotColor
    size(500,500);clear();stroke(-1,50)
    if UseColor:
        s=[0]*3;t=int(ColorH)%3
        s[t]=3;s[(t+1)%3]=1.5;s[(t+2)%3]=.8
        colorMode(HSB,250);c=color(ColorH,250,200)
        colorMode(RGB,255);blendMode(ADD);
        PlotColor=color(s[0]*(red(c)+40),s[1]*(green(c)+40),s[2]*(blue(c)+40))
        stroke(PlotColor)
    iterate(.05,.05,N*100,lambda x,y:point(Sx*(x-Xmin)+30,Sy*(y-Ymin)+30))

def draw():pass

Hw=2000
Hh=2000
HiResImage=createImage(Hw,Hh,RGB)
def plotOnHiRes(x,y):
    sx=Hw/(Xmax-Xmin)*.9;sy=Hh/(Ymax-Ymin)*.9
    tx=30.*Hw/W;ty=30.*Hh/H
    u=int(sx*(x-Xmin)+tx)
    v=int(sy*(y-Ymin)+ty)
    if u<0 or Hw<=u or v<0 or Hh<=v:return
    c=HiResImage.pixels[Hw*v+u]
    HiResImage.pixels[Hw*v+u]=color(red(c)+red(PlotColor),
                                    green(c)+green(PlotColor),
                                    blue(c)+blue(PlotColor))
    
def mouseClicked():
    print("Generating Hi-Res Image...")
    iterate(.05,.05,N*100*Hw/W*Hh/H,plotOnHiRes)
    HiResImage.save(ID+'.png')
    save(ID+'.jpg')
    print("Done.")

 プログラムの使い方や処理内容についての質問やコメントは Twitter アカンと @KojiSaito まで送っていただければ幸いである。

付録

 Sprott のストレンジアトラクタ ID については、以下のページにもいくつか記載されている:

また以下に筆者がここ数日で見つけた興味深い ID を記しておくので、これらを試してもらえばと思う。どんな模様が描かれるのかは、お楽しみ、である。

ID="UQCPVXDSYYBD"
ID="RMCDQNXCBYQJ"
ID="DPRTAVLOFHGC"
ID="YEIFWNPTAGKK"

ID="NPLENYSRNLJD"
ID="NQLENYSRNLJD"
ID="NPMENYSRNLJD"
ID="NPLFNYSRNLJD"
ID="NPLENYSRNLKD"
ID="NPLENYSRNLJC"

ID="JLMLFLWYBYCH"

ID="DJRFVUPTHULP"

ID="GHMRYXESOCKU"

ID="WJIBEDGBCKQR"

ID="INSSJSHXACSM"

ID="WCNMRIAJWBMO"

ID="YJEBPTHAWPTR"

ID="NLVXBLEDHUFQ"

ID="UIEXGLLSFDFA"

ID="YWFOXHGHTHTO"

ID="XCUFVFCOKKJY"

ID="VPRXFHDUEIDH"

ID="FQRJKPTBSLIF"

ID="FELICJSBAWXQ"

ID="GUPTSRGHVJIP"

ID="OBLBHKRDAPMH"

ID="KERAXUODWHFV"

ID="GTQCWJNGSWCI"


この記事が参加している募集

この記事が気に入ったらサポートをしてみませんか?