Group Abstract Group Abstract

Message Boards Message Boards

The Chaos Game - Sierpinski triangles and beyond - part I

POSTED BY: Sander Huisman
12 Replies
POSTED BY: Sander Huisman

enter image description here - Congratulations! This post is now Staff Pick! Thank you for your wonderful contributions. Please, keep them coming!

POSTED BY: EDITORIAL BOARD

Thanks!

POSTED BY: Sander Huisman

Dear Sander,

brilliant - as always! I already knew the 'chaos game', but I was not aware of the fact that it works with simple points - I would have tried something using a sub-triangular mapping ... Thank you very much for sharing!

I could not resist trying your method in 3D! Unfortunately this is much less spectacular ...

ClearAll["Global`*"]
sequence[n_, m_] := RandomChoice[Range[n], m]

fromSphericalCoordinates[{r_, \[Theta]_, \[Phi]_}] := 
  FromSphericalCoordinates[{r, \[Theta], \[Phi]}];
fromSphericalCoordinates[{1, 0., _}] = {0, 0, 1};

sphereDist[sph1_, sph2_] := 
 EuclideanDistance[fromSphericalCoordinates[Prepend[sph1, 1]], 
  fromSphericalCoordinates[Prepend[sph2, 1]]]

(* calculates n positions on a 3D-sphere with minimal 'energy' when \
repulsive  *)

sphereAewquiDist[n_Integer /; n > 2] := 
 Module[{vars, vpairs, energy, constr, sol},
  vars = (({Subscript[\[Theta], #1], Subscript[\[Phi], #1]} &) /@ 
     Range[n]); vpairs = Subsets[vars, {2}]; 
  energy = Total[1./Apply[sphereDist, vpairs, {1}]];
  constr = 
   Flatten[Apply[{0 <= #1 <= Pi, -Pi <= #2 <= Pi} &, vars, {1}]];
  sol = Last[NMinimize[{energy, constr}, constr[[All, 2]]]]; 
  Chop[fromSphericalCoordinates /@ (vars /. 
       sol /. {\[Theta]_, \[Phi]_} :> {1, \[Theta], \[Phi]})]]

gr = Table[
   sPts = sphereAewquiDist[n];
   chmLines = MeshPrimitives[ConvexHullMesh[sPts], 1];
   pts = FoldList[(#1 + sPts[[#2]])/2 &, RandomChoice[sPts], 
     sequence[n, 500000]];
   {n, Graphics3D[{Black, Thick, chmLines, Blue, PointSize[0.0001], 
      Point[pts]}, AspectRatio -> Automatic, ImageSize -> 600, 
     SphericalRegion -> False, Boxed -> False]},
   {n, 4, 6}];

Grid[gr, Frame -> All]

The result:

enter image description here

Best regards -- Henrik

POSTED BY: Henrik Schachner

Wow! Very nice Henrik! For 4 this is a tetrahedron and for 6 an octahedron right? For 5; I have no idea what that is called! For the case of 4 you can see the 3D Sierpinski quite nicely. For the others I think the visualisation is the problem; there seems to be some structure, but hard to figure out how it is shaped! I like your sphereAewquiDist function; the future will be bright for you! That is all I can say!

POSTED BY: Sander Huisman

@Henrik Schachner Since it is now public knowledge: https://reference.wolfram.com/language/ref/SpherePoints.html SpherePoints will be introduced in version 11.1 which is similar to your sphereAewquiDist function, with some hard-coded position for 'small' n. and for large 'n' a fast procedure.

POSTED BY: Sander Huisman

Dear Sander,

thank you for this interesting detail! It is a good thing if there is a specific function for this, because my feeling is that my "solution" (turning it into an optimization problem) is quite inappropriate. My little procedure originally stems from the task of finding "equally spaced" beam directions in radiotherapy.

Best regards -- Henrik

POSTED BY: Henrik Schachner

Just as a minor addendum:

From the documentation:

SpherePoints[n] gives the positions of n uniformly distributed points on the surface of a unit sphere.

At least for certain small numbers of points I would not regard this function as "working". See the following examples using 10, 11 and 13 points (left: result of SpherePoints - right: more like expected result):

enter image description here

This is somewhat disappointing. My code for the above:

ClearAll["Global`*"]

fromSphericalCoordinates[{r_, \[Theta]_, \[Phi]_}] := 
  FromSphericalCoordinates[{r, \[Theta], \[Phi]}];
fromSphericalCoordinates[{1, 0., _}] = {0, 0, 1};
sphereDist[sph1_, sph2_] := 
 EuclideanDistance[fromSphericalCoordinates[Prepend[sph1, 1]], 
  fromSphericalCoordinates[Prepend[sph2, 1]]]

mySpherePoints[n_Integer /; n > 2] := 
 Module[{vars, vpairs, energy, constr, sol}, 
  vars = (({Subscript[\[Theta], #1], Subscript[\[Phi], #1]} &) /@ 
     Range[n]); vpairs = Subsets[vars, {2}];
  energy = Total[1./Apply[sphereDist, vpairs, {1}]];
  constr = 
   Flatten[Apply[{0 <= #1 <= Pi, -Pi <= #2 <= Pi} &, vars, {1}]];
  sol = Last[NMinimize[{energy, constr}, constr[[All, 2]]]];
  Chop[fromSphericalCoordinates /@ (vars /. 
       sol /. {\[Theta]_, \[Phi]_} :> {1, \[Theta], \[Phi]})]]

GraphicsGrid[(Show[
       Graphics3D[{Opacity[.3], Sphere[]}, SphericalRegion -> True], 
       ConvexHullMesh[#]] & /@ {SpherePoints[#], 
      mySpherePoints[#]}) & /@ {10, 11, 13}, Frame -> All, 
 ImageSize -> 600]

Regards -- Henrik

POSTED BY: Henrik Schachner

10 and 11 (among others) are hard-coded:

Cases[DownValues[NKSSpecialFunctions`SpherePoints`Dump`iSpherePoints],HoldPattern[NKSSpecialFunctions`SpherePoints`Dump`iSpherePoints[x_Integer]]:>x,\[Infinity]]

{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 16, 18, 20, 22, 24, 30, 32, 40, 50, 55, 60}

while 13 is generated by a general linear algorithm. I'm not sure what the design criteria of the function were. Was it symmetry? inertial moments? volume? distance?

POSTED BY: Sander Huisman

Very nice, in conception, code, and artistry. One comment: the 4-vertex (square) case that alone seems so boring is probably quite important. The fact that it does not give any "nice" fractal is, I suspect, relevant to why the Chaos Game Representation is so useful for making images from nucleotide sequences. Depending on level of pixelization these have a sort of n-gram "memory", hence (I think) implicitly encode some of the local sequence structure. This does not work for other vertex counts and that is perhaps related to why they give pictures that are nicer for other purposes (fractals, material design maybe, art definitely, ...)

On a different note, I like the phrase "three sided polygon". I'm thinking we could shorten that, perhaps to "trigon". If only the language had a word for this... (look, it was a great post, I gotta be allowed to make light of something).

POSTED BY: Daniel Lichtblau

The square is the consequence of the fact that a square can be tiled exactly by 4 scaled down (by 1/2) versions of itself. While for other polygons this will create 'high-density' and empty regions.

If one assumes we have random points inside the polygon (blue coloured below), and ones maps all those point towards one of the vertices, and do so for all vertices, we get a new 'density-map' of points. If there are holes in this density map, the assumption of having a uniform density at the start was false, and we should repeat the procedure repeatedly turning it in a fractal...

ClearAll[CreateDiagram]
CreateDiagram[n_] := Module[{bg, pts, gr1, gr2, col},
  pts = N@CirclePoints[n];
  col = FaceForm[Directive[Opacity[0.5], RGBColor[0, 0.5, 1]]];
  bg = {FaceForm[], EdgeForm[Black], Polygon[pts]};
  gr1 = {bg, EdgeForm[], col, Polygon[pts]};
  gr2 = {bg, col, Scale[Polygon[pts], 1/2, pts[[#]]]} & /@ Range[n];
  Graphics[{gr1, Translate[#, {0, -4.5}] & /@ gr2, 
    MapThread[{Translate[#1, {2.25 #2, -2.25}], {Darker@Gray, 
        Arrow[{0.2 {2.25 #2, -2.25}, 0.7 {2.25 #2, -2.25}}], 
        Arrow[{0.8 {2.25 #2, -2.25} + 0.2 {0, -4.5}, 
          0.8 {0, -4.5} + 0.2 {2.25 #2, -2.25}}]}} &, {gr2, 
      Range[0, n - 1] - (n - 1)/2}], 
    Arrow[BSplineCurve[{{2, -4.5}, {1.1 2.25 n/2, -4.5}, {1.1 2.25 n/
          2, 0}, {2, 0}}, SplineDegree -> 2]]}]
  ]

Trying out:

CreateDiagram[3]
CreateDiagram[4]
CreateDiagram[5]
CreateDiagram[6]
CreateDiagram[7]

enter image description here enter image description here enter image description here enter image description here enter image description here

I must have had a cognitive glitch while typing the 'trigon' part... I guess I was mixing up 3 sided regular polygon, and equilateral triangle somehow...

POSTED BY: Sander Huisman

Here some more hi-resolution examples:

enter image description here

enter image description here

POSTED BY: Sander Huisman
Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
Attachments
Remove
or Discard