bitterharvest’s diary

A Bitter Harvestは小説の題名。作者は豪州のPeter Yeldham。苦闘の末に勝ちえた偏見からの解放は命との引換になったという悲しい物語

Haskellでお絵かき(3)

1.自然数を数学的な模様にする

中学生のとき、素因数分解を学んだ。与えられた自然数を、割り切れない数(素数)の積で表したものだ。例えば、102は素数17,3,2の積で表すことができる。
自然数をその構成要素である素数を用いて絵画的に表すことを考えたのは、Diagramsの開発者でもあるBrent Yorgeyである。彼のアイデアは次のようになっている。まず、構成要素となっている素数を大きい順にならべる。102の場合には{17,3,2}である。そして、一番大きな素数と同じだけの頂点を有する正多角形を描く。102の場合であれば正17角形である。次に、各頂点の周りにその次に大きな素数と同じ頂点を有する正多角形を描く。102の場合であれば、正3角形である。この操作を続ける。最後の整数に出くわしたら、同じように、正多角形を書いた後、その各頂点に小円を描く。これにより、自然数と同じだけの小円が描かれるが、素因数分解という構造的な表現を用いて表したものとなる。
自然数をこのように絵画的に表した場合の、アニメーションがあるので、こちらを見るとよい。

2.プログラムを書いてみる

Yorgey自身のプログラムもあるし、また、モジュールDiagrams.TwoD.Factorizationをインストールすれば簡単に利用することもできるが、それほど難しいプログラムでもないので、基本的な部分を作成してみる。完成したプログラムは以下のようである。

import Diagrams.Prelude
import Diagrams.Backend.Rasterific.CmdLine
import Math.NumberTheory.Primes.Factorisation (factorise)

node    = circle 0.2 # fc green

factor :: [Int] -> Diagram B R2
factor []     = error "We need a number."
factor [x]    = decorateTrail (regPoly x 1) (replicate x node) # centerXY
factor (x:xs) = decorateTrail (regPoly x (fromIntegral (3 ^ (length xs)))) (map (\n -> (factor xs # rotateBy ((fromIntegral n) / (fromIntegral x))) # centerXY) [1..x])

factorList :: [Int]
factorList = factorise 1365 # concatMap (uncurry $ flip replicate) # reverse # map fromIntegral

example =  factorList # factor # centerXY # lw none # fc white # pad 1.1
--example = [13,7,5,3] # factor # centerXY # lw none # fc white # pad 1.1

main = mainWith example

プログラムを実行したときの例をいくつか挙げておく。
34の場合は次のとおりである。
f:id:bitterharvest:20140803151713p:plain
105の場合は次のとおりである。
f:id:bitterharvest:20140803151807p:plain
1365の場合は次のとおりである。
f:id:bitterharvest:20140803151833p:plain