(追記:2014-3-3) Gvizについてのまとめ頁を作りました。

Gvizの目次 - Rubyの世界からGraphvizの世界にこんにちは!


数字は社会生活における便利な道具の一つです。一方でそれはまた多くの人々を魅了して止まない迷宮の世界です。つまり数字は実用と神秘なる美しさとを同時に兼ね備えた概念なのです。

というわけで…

Gvizを使って今度は数字の美しさを表現してみようと思います。素数とフィボナッチ数を使います。

300までの数字を並べる

まずは単純に1〜300までの数字を平面的に並べてみます。Gvizで300個のノードを生成し、neatoレイアウトで描画します。

require "gviz"

max = 300
label = 'Numbers upto 300'

Graph do
  global layout:'neato', label:label, fontsize:54, size:15
  nodes shape:'circle', style:'filled'

  (1..max).each { |i| node :"#{i}" }
  
  save :number, :png
end

出力は次のようになりました。

numbers noshadow (クリックで拡大します)

カエルの卵みたいでちょっと気持ち悪いです。

素数列を取り出す

さて次に、ここから素数列のみを取り出し、それらのノードを順にエッジでリンクしてみます。

やはりグラフには色がないと寂しいので、素数列には青系の色を付けるようにしましょう。まずは色名をリスト(一行に一つの名前)で持ったテキストファイルcolors.txtを読み出して、青系色を抽出します。

File.open('colors.txt') do |f|
  COLORS = f.read.lines.map(&:chomp).reject { |l| l.empty? }
end

def color_pick(regex)
  COLORS.select { |c| c.match regex }
end

blues = color_pick(/(blue|cyan)\D*$/)

blues # => ["aliceblue", "blue", "blueviolet", "cadetblue", "cornflowerblue", "cyan", "darkslateblue", "deepskyblue", "dodgerblue", "lightblue", "lightcyan", "lightskyblue", "lightslateblue", "lightsteelblue", "mediumblue", "mediumslateblue", "midnightblue", "navyblue", "powderblue", "royalblue", "skyblue", "slateblue", "steelblue"]

色の準備ができたので、次に素数列を作ってrouteメソッドでエッジでリンクされたノード列を作ります。

require "prime"

max = 300
primes = Prime.each(max)

label = 'Prime Numbers upto 300'

Graph do
  global layout:'neato', label:label, fontsize:54, size:15
  nodes shape:'circle', style:'filled'

  (1..max).each { |i| node :"#{i}" }
  
  primes.each_cons(2) do |gr|
    route Hash[*gr]
    c = blues[rand blues.size]
    node :"#{gr[1]}", fillcolor:c, fontcolor:'white'
  end

  save :number, :png
end

出力は次のようになりました。

numbers noshadow (クリックで拡大します)

素数列が300の数字から抽出されて、一列に並びました。

フィボナッチ数を取り出す

次に、一旦素数列を元に戻して、フィボナッチ数を抽出してみます。フィボナッチ数を生成するコードはなんでもいいですが、ここではEnumeratorを使って作ってみました。

class Fib
  def self.create
    Enumerator.new do |y|
      a, b = 1, 1
      loop do
        y << a
        a, b = b, a+b
      end
    end
  end
end

max = 300
fibs = Fib.create.take_while { |i| i <= max*20  }

fibs # => [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181]

300までだとちょっと数が寂しいので、ここでは6000までのフィボナッチ数を抽出しています。

ノードの色を赤系として、フィボナッチ数を抽出します。

max = 300
fibs = Fib.create.take_while { |i| i <= max*20  }

reds = color_pick(/(red|pink|violet)\D*$/)

label = 'Fibonacci Numbers upto 6000'

Graph do
  global layout:'neato', label:label, fontsize:54, size:15
  nodes shape:'circle', style:'filled'

  (1..max).each { |i| node :"#{i}" }
  
  fibs.each_cons(2) do |gr|
    route Hash[*gr]
    c = reds[rand reds.size]
    node :"#{gr[1]}", fillcolor:c, fontcolor:'white'
  end

  save :number, :png
end

出力は次のようになりました。

numbers noshadow (クリックで拡大します)

いいですね。

素数とフィボナッチ数の出会い

さて最後に素数とフィボナッチ数を重ねてみます。つまり先の2つの数列を同時に描画します。2つの数列にどんな出会いがあるのでしょうか。

label = 'Fibonacci Numbers upto 6000'

Graph do
  global layout:'neato', label:label, fontsize:54, size:15
  nodes shape:'circle', style:'filled'

  (1..max).each { |i| node :"#{i}" }
  
  primes.each_cons(2) do |gr|
    route Hash[*gr]
    c = blues[rand blues.size]
    node :"#{gr[1]}", fillcolor:c, fontcolor:'white'
  end
  
  fibs.each_cons(2) do |gr|
    route Hash[*gr]
    c = reds[rand reds.size]
    node :"#{gr[1]}", fillcolor:c, fontcolor:'white'
  end

  save :number, :png
end

結果は次のとおりです!

numbers noshadow (クリックで拡大します)

雰囲気が大分変わりました。数列はループを描いています。ちょっとリンクを追ってみます。

5で別れた2つの数列は13でまたすぐ出会います。それから素数列は下側に小さめのループを描く一方で、フィボナッチ数列は21,34,55と直線的に進んで、両者は89でまた出会います。それから素数列はまた長い旅に出て右上に大きめのループを描く一方で、フィボナッチ数列は144の一つだけ進みます。そして両者は再び233で出会うのです…

ロマンチックです。美しいです。

更に先の出会いへ

ここまで来ると彼らが次にどこで出会うのかが気になります…

max = 5000として描画してみます。

結果は次のとおりです。

numbers noshadow (クリックで拡大します)

なんかどこかで見たような…不思議なかたち…

アダムとイヴは実は素数とフィボナッチ数だったとか!

それはさておき、3つ目のループの交点が見えますか?それが答えです!

(交点の拡大図) numbers noshadow (クリックで拡大します)

さらにmax = 30000としてみます。

出力は次のようになりました。図では確認できませんが、次の出会いは28657でやって来ます。

numbers noshadow (クリックで拡大します)

(交点の拡大図) numbers noshadow (クリックで拡大します)

数字の神秘をGvizで表現してみました。


Gviz sample: Meet Primes with Fibonaccies — Gist


関連記事:

Yet Another Ruby Graphviz Interfaceを作ったからみんなで大量のグラフを作って遊ぼうよ!

Ruby Graphvizラッパー「Gviz」でアメリカ合衆国をデータビジュアライズしよう!

東京の地下鉄をGviz(Ruby Graphviz Wrapper)で描く


(追記:2012-10-7)max=30000の出力を追加しました。


博士の愛した数式 (新潮文庫) by 小川 洋子



blog comments powered by Disqus
ruby_pack8

100円〜で好評発売中!
M'ELBORNE BOOKS