バーンズリーのシダ

バーンズリーのシダは、イギリスの数学者マイケル・バーンズリーにちなんで名付けられたフラクタルで、その著書『//Fractals Everywhere』//で初めて記述された。チャセンシダの1種であるミヤマカワリシダを模したものである。

1. 歴史
-----

シダは、自己相似図形の代表例の1つである。すなわち、数学的に生成されたパターンであり、そのパターンは任意に拡大または縮小しても同一の形状が現れる自己相似性を示す。シェルピンスキーの三角形のように、バーンズリーのシダは、コンピューターで数式を繰り返し使用することで、視覚的に美しい図形を構築する方法を示している。バーンズリーの1988年の本『//Fractals Everywhere//』は、 ジョージア工科大学数学部の//フラクタル幾何学//と呼ばれるコースにおける学部生と大学院生に対する講義内容に基づいている。この本の出版後、//フラクタル測定理論//と呼ばれる第二のコースが設置された。バーンズリーの作品は、数学モデルで自然を模倣しようとするグラフィックアーティストのインスピレーションの源となっている。 バーンズリーによって開発されたシダのコードは、フラクタルを作成するための反復関数系の例である。これはコラージュ定理に従う。彼はフラクタルを使用して、科学技術におけるさまざまな現象、とりわけ植物構造、についてモデル化している。IFSは、自然の分岐構造でしばしば発生する自己相似性により、特定の植物、葉、およびシダのモデルを提供する。しかし、自然は、あるレベルから次のレベルへのランダム性と変化も示す。2つのシダはまったく同じではなく、枝分かれしている大きな葉は小さなスケールでは小さい葉になる。V変数フラクタルは、スケール全体でこのようなランダム性と変動性を許容すると同時に、幾何学的モデリングを容易にするパラメーターへの連続的な依存性が認められる。これらの要因により、ハイブリッド生物学モデルを作成できる...

...特定の植物の幾何学によく一致するV変数の幾何学的フラクタルモデルが見つかった場合、これらの符号樹と植物の遺伝子に格納されている情報の間に特定の関係があると推測される。// —マイケル・バーンズリー//ら////

2. シダの生成
--------

バーンズリーのシダは、4つのアフィン変換を使用する。変換の式は次のとおりである。

あるいは

バーンズリーは、前述した著書で、シダを生成する//IFS//コードを、以下の表のように、値の行列の形で示した。下表では、列「a」から「f」は前記の等式fの係数を示しており、「p」はそれぞれの値の組に対する確率因子を表している。

上記の表は、次の4つの変換に対応している。

2.1. コンピューターによる生成
-----------------

バーンズリーのシダは、理論的にはペンとグラフ用紙を使用して手でプロットできるが、必要な反復回数は数万回に達するので、実際にはコンピューターを使用する必要がある。バーンズリーのシダの多くのさまざまな計算モデルは、現代の数学者に人気がある。バーンズリーの係数行列を使用し、数式が正しくプログラムされている限り、同じ形状をもったシダが生成される。

最初に描画される点は原点にあり、次の4つの座標変換ƒ1, ƒ2, ƒ3, ƒ4のいずれかを設定した発生確率pでランダムに適用することにより、新しい点を反復的に計算する 。すなわち、どの座標変換を使用するか確率に応じた乱数範囲を設定しておき、コンピューターで乱数を発生させ、乱数の値に応じてどの座標変換を使用するのか決め、変換計算を反復的に実行する。これは、1988年にバーンズリーがランダム・アルゴリズムと名付けた初めての例であり、現在ではカオスゲーム、確率論的反復関数系とも呼ばれている。

//ƒ//1

//x// //n// + 1 = 0 //y// //n// + 1 = 0.16 //y// //n// 。座標変換ƒ1は1％の確率で実行される。この変換は、任意の点を、シダの茎基部の最初の線分にマッピングするだけである。フラクタル図のこの部分は、反復の過程で最初に完了する部分である。

//ƒ//2

//x// //n// + 1 = 0.85 //x// //n// + 0.04 //y// //n// //y// //n// + 1 = −0.04 //x// //n// + 0.85 //y// //n// + 1.6。この座標変換ƒ2は、85％の確率で実行され、図の赤い三角形で表される葉の中の任意のポイントを、青い三角形で表される反対側の小さな葉の中の点にマッピングする。

//ƒ//3

//x// //n// + 1 = 0.2 //x// //n//   −   0.26   //y// //n// //y// //n// + 1 = 0.23 //x// //n//   +   0.22 //y// //n//   +   1.6。この座標変換ƒ3は、7％の確率で実行され、青い三角形で表される葉の中の任意の点を、茎を交差し交互に対応する三角形内にマッピングする。

//ƒ//4

//x// //n// + 1 = −0.15 //x// //n// + 0.28 //y// //n// //y// //n// + 1 = 0.26 //x// //n// + 0.24 //y// //n// + 0.44。この座標変換ƒ4は、7％の確率で実行され、青い三角形で表される葉の中の任意の点を、茎を交差し交互に対応する三角形内にマッピングする。

最初の座標変換は茎を描画する。2番目は茎と下葉を連続コピーして、完全なシダを生成する。3番目は左下葉を描き、4番目は、右下の葉を描く。IFSの再帰的な性質により、全体が各葉の部分の大きな複製となっている。シダ全体が-2.1820 < x < 2.6558 および 0 ≤ //y// <   9.9983　の範囲内にあることに注意。

2.2. 様々なシダの変種
-------------

係数をいろいろと変えることで、様々なシダの品種、変種を作成することが可能である。V変数フラクタルに関する彼の論文において、バーンズリーはこの特性を//スーパー//フラクタルと呼んでいる。

ある実験者は係数の表を作成して、//Cyclosolus//または//Thelypteridaceae//シダに類似した、非常に自然に見える別のシダを作成した 。



3. 構文例
------

以下の各プログラム言語の構文を使用して、シダを自分で描くことができる。

3.1. Python
-----------

import turtle import random

pen = turtle.Turtle pen.speed pen.color pen.penup

x = 0 y = 0 for n in range: pen.goto # 57 is to scale the fern and -275 is to start the drawing from the bottom. pen.pendown pen.dot pen.penup r = random.random # to get probability r = r * 100 xn = x yn = y if r < 1: # elif ladder based on the probability x = 0 y = 0.16 * yn elif r < 86: x = 0.85 * xn + 0.04 * yn y = -0.04 * xn + 0.85 * yn + 1.6 elif r < 93: x = 0.20 * xn - 0.26 * yn y = 0.23 * xn + 0.22 * yn + 1.6 else: x = -0.15 * xn + 0.28 * yn y = 0.26 * xn + 0.24 * yn + 0.44<WtXmlEndTag />

3.2. R
------

Barnsley's Fern
create function of the probability and the current pointfractal_fern2 <- function{ if  { m <- matrix, 2, 2) f <- c } else if  { m <- matrix, 2, 2) f <- c } else if  { m <- matrix, 2, 2) f <- c } else { m <- matrix, 2, 2) f <- c } m %*% x + f }

how many reps determines how detailed the fern will bereps <- 10000

create a vector with probability values, and a matrix to store coordinatesp <- runif

initialise a point at the origincoords <- c

compute Fractal Coordinatesm <- Reduce m <- t)

Create plotplot, ylim = c, xlab = NA, ylab = NA, axes = FALSE)

<WtXmlEndTag />

3.3. Processing
---------------

/* Barnsley Fern for Processing 3.4

/// declaring variables x and y float x, y;

// creating canvas void setup { size; background; }

/* setting stroke, mapping canvas and then plotting the points */ void drawPoint { stroke; strokeWeight; float px = map; float py = map; point; }

/* algorithm for calculating value of th term of x and y based on the transformation matrices */ void nextPoint { float nextX, nextY; float r = random; if  { nextX = 0; nextY = 0.16 * y; } else if  { nextX = 0.85 * x + 0.04 * y; nextY = -0.04 * x + 0.85 * y + 1.6; } else if  { nextX = 0.20 * x - 0.26 * y; nextY = 0.23 * x + 0.22 * y + 1.6; } else { nextX = -0.15 * x + 0.28 * y; nextY = 0.26 * x + 0.24 * y + 0.44; } x = nextX; y = nextY; }

/* iterate the plotting and calculation functions over a loop */ void draw { for  { drawPoint; nextPoint; } }<WtXmlEndTag />

3.4. P5.JS
----------

let x = 0; let y = 0;

function setup { createCanvas; background; }

//range −2.1820 < x < 2.6558 and 0 ≤ y < 9.9983. function drawPoint { stroke; strokeWeight; let px = map; let py = map; point; }

function nextPoint { let nextX; let nextY;

let r = random;

if  { //1 nextX = 0; nextY = 0.16 * y; } else if  { //2 nextX = 0.85 * x + 0.04 * y; nextY = -0.04 * x + 0.85 * y + 1.60; } else if  { //3 nextX = 0.20 * x + -0.26 * y; nextY = 0.23 * x + 0.22 * y + 1.60; } else { //4 nextX = -0.15 * x + 0.28 * y; nextY = 0.26 * x + 0.24 * y + 0.44; }

x = nextX; y = nextY; }

function draw { for  { drawPoint; nextPoint; } }<WtXmlEndTag />

3.5. JavaScript 
-----------------------

let canvas; let canvasContext;

let move;

let fps = 250;

let pointColor = "green"; let backgroundColor = "black"; let pointRadius = 1;

let x = 0; let y = 0;

window.onload = function  { canvas = document.getElementById; canvasContext = canvas.getContext;

canvasContext.fillStyle = backgroundColor; canvasContext.fillRect;

move = setInterval; };

let doIt = function  { for  moveAll };

function moveAll {

let nextX, nextY; let r = Math.random; if  { nextX = 0; nextY = 0.16 * y; } else if  { nextX = 0.85 * x + 0.04 * y; nextY = -0.04 * x + 0.85 * y + 1.6; } else if  { nextX = 0.20 * x - 0.26 * y; nextY = 0.23 * x + 0.22 * y + 1.6; } else { nextX = -0.15 * x + 0.28 * y; nextY = 0.26 * x + 0.24 * y + 0.44; }

// Scaling and positioning let plotX = canvas.width *  / 6; let plotY = canvas.height - canvas.height *  / 14);

drawFilledCircle;

x = nextX; y = nextY;

} const drawFilledCircle =  => { canvasContext.beginPath; canvasContext.fillStyle = color; canvasContext.arc; canvasContext.fill; };<WtXmlEndTag /><WtXmlEndTag />

3.6. QBasic
-----------

SCREEN 12 WINDOW - RANDOMIZE TIMER COLOR 10 DO SELECT CASE RND CASE IS < .01 nextX = 0 nextY = .16 * y CASE .01 TO .08 nextX = .2 * x - .26 * y nextY = .23 * x + .22 * y + 1.6 CASE .08 TO .15 nextX = -.15 * x + .28 * y nextY = .26 * x + .24 * y + .44 CASE ELSE nextX = .85 * x + .04 * y nextY = -.04 * x + .85 * y + 1.6 END SELECT x = nextX y = nextY PSET  LOOP UNTIL INKEY$ = CHR$

3.7. VBA
--------

Sub Barnsley

Dim iEnd As Long Dim i As Long Dim x As Double Dim y As Double Dim nextX As Double Dim nextY As Double Dim sShapeArray As Shape Dim dSize As Double Dim sColor As String

dSize = 0.01 ' Size of the dots sColor = "0,0,100" ' RGB color of dots, value range 0 to 255 iEnd = 5000 ' Number of iterations ReDim sShapeArray ' In Corel, each object drawn requires a variable name of its own

Randomize ' Initialize the Rnd function

For i = 0 To iEnd ' Iterate ... Select Case Rnd Case Is < 0.01 ' f1 = Draw stem nextX = 0 nextY = 0.16 * y Case 0.01 To 0.08 ' f3 nextX = 0.2 * x - 0.26 * y nextY = 0.23 * x + 0.22 * y + 1.6 Case 0.08 To 0.15 ' f4 nextX = -0.15 * x + 0.28 * y nextY = 0.26 * x + 0.24 * y + 0.44 Case Else ' f2 nextX = 0.85 * x + 0.04 * y nextY = -0.04 * x + 0.85 * y + 1.6 End Select x = nextX y = nextY Set sShapeArray = ActiveLayer.CreateEllipse2 sShapeArray.Style.StringAssign "{""fill"":{""primaryColor"":""RGB255,USER," & sColor & ",100,00000000-0000-0000-0000-000000000000"",""secondaryColor"":""RGB255,USER,255,255,255,100,00000000-0000-0000-0000-000000000000"",""type"":""1"",""fillName"":null},""outline"":{""width"":""0"",""color"":""RGB255,USER,0,0,0,100,00000000-0000-0000-0000-000000000000""},""transparency"":{}}" DoEvents Next

End Sub<WtXmlEndTag />

3.8. Amola
----------

addpackage

set set set set

method setup createCanvas rect) end

method drawPoint set), 6)) set, 14)))) set //log //log rect, round, round, round, color) end

method nextPoint set set set) if set set end else if set set end else if set set end else set set end end end

set set end

setup while drawPoint nextPoint end<WtXmlEndTag />

3.9. 表計算ソフトによる計算例
-----------------

プログラム言語の構文と同じ計算を、以下のように表計算ソフトの関数を使用することでも実現できる。

なお、B8,C8,D8のセルには以下のような複数条件判定の関数を入力する。

B8=IF,1,IF,2,IF,3,4)))
C8=IF))
D8=IF))最終8行目をオートフィルで適当な行数だけコピーし、XY散布図とするとバーンズリーのシダのフラクタル図が得られる。各変換式ƒの係数a,b,c,d,e,fと確率pは任意に変更可能である。

各列は以下のような計算を行っている。

A列 乱数を発生させる。
B列 乱数をもとに確率pに応じた条件判定を行い、用いる変換ƒを決める。
C列 先に決めた変換ƒに対応する計算をおこない、Xを求める。
D列 先に決めた変換ƒに対応する計算をおこない、Yを求める。
新たなXとYは前の行のXとYの値を使用し、反復的に計算を進める。

4. 脚注
-----