Generating an Ikeda Map
Today in my ongoing quest to generate fractals in Rstats using every available avenue: generating an Ikeda map.
Methods for generating fractals so far:
Ikeda map
An Ikeda map is a model of light going acound a nonlinear optical resonator. To be honest, the wiki page and the original paper by Ikeda are impenetrable to me!
However, creating the map is relatively straightforward.
- Start at a random point
- Update the position of the point
- Continue updating the point’s position for N steps
- Draw the path joining all the positions of this point
- Repeat steps 1-4
library(tidyverse)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#' Computing a single path from the given starting point
#'
#' @param u ikeda parameter
#' @param x,y starting point
#' @param N is the number of iterations
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
compute_ikeda_trajectory <- function(u=0.918, x1, y1, N) {
x <- y <- double(N)
x[1] <- x1
y[1] <- y1
for (i in 2:N) {
t <- 0.4 - 6/(1 + x[i-1]*x[i-1] + y[i-1]*y[i-1])
x[i] <- 1 + u * (x[i-1] * cos(t) - y[i-1] * sin(t))
y[i] <- u * (x[i-1] * sin(t) + y[i-1] * cos(t))
}
data_frame(x=x, y=y)
}
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Generate P random starting points
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
P <- 2000 # Number of starting points
N <- 1000 # Number of iterations of each point
set.seed(1)
x <- rnorm(P) * 10
y <- rnorm(P) * 10
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Generate the P paths from the random starting points
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
res <- seq(P) %>%
map(~compute_ikeda_trajectory(u=0.928, x[.x], y[.x], N))
Warning: `data_frame()` is deprecated, use `tibble()`.
This warning is displayed once per session.
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Plot all the paths
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
par(pty='s',bg='black')
plot(0, type='n', as=1, xlim=c(-10, 10), ylim=c(-10, 10))
res %>% walk(~lines(.x, col='#ffffff08'))
Tweetable Ikeda map
This one was a hell of a squeeze to get it into a tweet:
- Use
1e3
instead of1000
to save a single character. - Drop leading
0
from0.9
- Use
rep(0,N)
instead ofdouble(N)
to save a single character - use
lst
instead oftibble
ordata.frame
to save at least 3 chars - Dropping from
10
to9
as a multiplier to trip a single digit each time. - Came out at exactly 280 characters!
- Update Thanks to Jonathan Carroll for pointing out a shorter way to call
map2
it’s down to 272 characters which means I can include the #rstats hashtag! (which then brings it back up to 280 characters)
#rstats
library(tidyverse)
N=1e3
x=y=rep(0,N)
F=function(X,Y){x[1]=X
y[1]=Y
for(i in 2:N){X=x[i-1];Y=y[i-1]
t=.4-6/(1+X^2+Y^2)
S=sin(t);C=cos(t)
x[i]=1+.9*(X*C-Y*S)
y[i]=.9*(X*S+Y*C)}
lst(x,y)}
r=rnorm
plot(0,as=1,yli=c(-9,9))
walk(map2(r(N)*9,r(N)*9,F),~lines(.x,co='#00000010'))