library(ggplot2) library(gridExtra) #define functions m1<-matrix(c(cos(pi/4),sin(pi/4),-sin(pi/4),cos(pi/4)),ncol=2) m2<-matrix(c(cos(3*pi/4),sin(3*pi/4),-sin(3*pi/4),cos(3*pi/4)),ncol=2) #define functions f1<-function(x){m1 %*% (x/sqrt(2))} f2<-function(x){m2 %*% (x/sqrt(2))+c(1,0)} IFS<-list(f1=f1,f2=f2) #choose starting point that is contained in attractor and run chaos game: x<-point<-c(0,0) nr<-1:length(IFS) steps<-10000 indices<-sample(nr,size=steps,replace=TRUE) A<-data.frame(x=rep(point[1],steps+1),y=rep(point[2],steps+1)) for(r in 1:steps){ x<-IFS[[indices[r]]](x) A[r+1,]<-x } #reexpress IFS as function of data.frame with columns x and y (will become clear why) reflection<-function(A){ R<-A R$y<-(-1)*A$y return(R) } rotation<-function(A,phi=pi/4){ R<-A R$x<-A$x*cos(phi)-A$y*sin(phi) R$y<-A$x*sin(phi)+A$y*cos(phi) return(R) } translation<-function(A,shift=(1)){ R<-A R$x=A$x+shift return(R) } plot(A,cex=0.1,xlim=c(-1,1.3),ylim=c(-0.7,1)) abline(h=0) abline(v=0) #decompose f1 in two simple steps A1<-rotation(A) lines(A1,type="p",col="green",cex=0.1) A2<-1/sqrt(2)*A1 lines(A2,type="p",col="magenta",cex=0.1) plot(A,cex=0.1,xlim=c(-1,1.3),ylim=c(-0.7,1)) abline(h=0) abline(v=0) #same with f2 in 3 steps A1<-rotation(A,phi=3*pi/4) lines(A1,type="p",col="green",cex=0.1) A2<-1/sqrt(2)*A1 lines(A2,type="p",col="blue",cex=0.1) A3<-translation(A2,shift=1) lines(A3,type="p",col="blue",cex=0.1) #altogether: plot(A,cex=0.1,xlim=c(-1,1.3),ylim=c(-0.7,1)) abline(h=0) abline(v=0) A2<-1/sqrt(2)*rotation(A) lines(A2,type="p",col="magenta",cex=0.1) A3<-translation(1/sqrt(2)*rotation(A,phi=3*pi/4)) lines(A3,type="p",col="blue",cex=0.1)