Construindo plantas e fractais via Iterated function systems

Bem, uma critica recorrente, e que sempre aparece em relação a teoria da evolução é que ela não poderia gerar estruturas tão complexas como o olho humano.

Eu acho que o grande apelo desse argumento é o fato de quase nunca entrarmos em contato com jogos ou regras simples que fazem coisas complexas. Claro que a gente ja viu aqui o jogo da vida de Conway, mas outra coisa que é bem legal também é ver como estruturas como plantas ou folhas, que parecem complexas, podem ser derivadas também de regras simples, como quando a gente constrói fractais.

Um fractal é um fenômeno natural ou conjunto matemático que exibe um padrão repetitivo que está presente em todas as escalas.

Para entender melhor, é mais fácil tentar fazer um fractal, que podemos conseguir usando Sistemas de funções iteradas, ou IFS (Iterated function systems).

Sistemas de funções iteradas ou IFSs são um método de construção de fractais; as figuras resultantes são sempre similares a si mesmas, como se os pedaços para construir elas mesma fossem a mesma imagem.

Fractais IFS, como são normalmente chamados, podem ser de qualquer número de dimensões, mas são comumente calculado e desenhado em 2D. O fractal é composta da união de várias cópias de si mesmo, cada cópia que está sendo transformado por uma função (daí o “sistema de função”). As funções são normalmente contracionista, o que significa que eles trazem pontos mais próximos e fazer formas menores a cada iteração. Assim, a forma de um fractal IFS é composta de várias cópias, possivelmente sobrepostas e cada vez menores de si mesma, cada uma das quais é também composta de cópias de si próprio, ad infinitum.

Vamos fazer um exemplo chamado de Samambaia de Barnsley (Barnsley Fern).

Basicamente, você começa com um ponto, (um ponto são dois números, uma coordenada para o eixo x e outra para o eixo y), ai você aplica uma função para conseguir o próximo ponto, e assim infinitamente, so que ao seguir uma função determinada de transformação, uma figura é formada, sempre, mesmo a transformação tendo um componente aleatório.

Olhando a página da wikipedia sobre o Barnsley Fern, a gente ve que a transformação é dada por parametros que estão no formato de uma matriz.

então a gente tem alguns parametros:

> matriz a b c d e f p f1 0.00 0.00 0.00 0.16 0 0.00 0.01 f2 0.85 0.04 -0.04 0.85 0 1.60 0.85 f3 0.20 -0.26 0.23 0.22 0 1.60 0.07 f4 -0.15 0.28 0.26 0.24 0 0.44 0.07

E dado um ponto inicial, por exemplo x=0 e y=0, aplicamos a seguinte transformação.

 {f(x,y)}={ \left[\begin{array}{c c} a & b \\ c & d \end{array} \right] \ast         \left[\begin{array}{c} x \\ y \end{array} \right] + \left[\begin{array}{c} e \\ f \end{array} \right]}

As letras a, b, c, d, e e f estão na matriz ali em cima, mas veja que temos 4 linhas, cada linha é uma função, ou seja:

 {f_1(x,y)}={ \left[\begin{array}{c c} 0 & 0 \\ 0 & 0.16 \end{array} \right] \ast         \left[\begin{array}{c} x \\ y \end{array} \right] + \left[\begin{array}{c} 0.00 \\ 0.16 \end{array} \right]}

Agora você me fala qualquer ponto inicial, jogamos nessa formula e temos um novo ponto.
Lembrando que é uma multiplicação de matriz, e no R a gente tem que usar %*% e não * para multiplicação de matriz, senão a multiplicação sai elemento por elemento.

Suponha a matriz:

> matrix(1:4,ncol=2) [,1] [,2] [1,] 1 3 [2,] 2 4

Veja que assim a gente multiplica 1*1, 2*2, ao multiplicar duas matrizes, e não é isso que pra fazer.

> matrix(1:4,ncol=2)*matrix(1:4,ncol=2) [,1] [,2] [1,] 1 9 [2,] 4 16

Queremos esse resultado.

> matrix(1:4,ncol=2)%*%matrix(1:4,ncol=2) [,1] [,2] [1,] 7 15 [2,] 10 22

Isso é de certa forma confuso, porque se você pegar código de matlab, tudo funciona ao contrario, o * é operação com matriz enquanto que para operação elemento por elemento você tem que usar outro comando.

Ok, mas então voltando ao ponto que temos ao todo 4 funções, mas temos que entrar com 1 ponto e sair com o outro ponto. Então temos que escolher um dos resultados, e para isso usamos a coluna p, de probabilidade. Ou seja escolhemos por acaso qual das equações, quais parâmetros daquele set usar.

Então basicamente iniciamos um ponto qualquer, por exemplo

x<-0 y<-0

Aplicamos a equação

 {f(x,y)}={ \left[\begin{array}{c c} a & b \\ c & d \end{array} \right] \ast         \left[\begin{array}{c} x \\ y \end{array} \right] + \left[\begin{array}{c} e \\ f \end{array} \right]}

Nesse ponto usando os parâmetros.

Então criamos uma matriz para guardar o resultado e jogamos naquela formula

f<-matrix(0,ncol=4,nrow=2)
f[,1]<-matrix(matriz[1,1:4],2,2,byrow=T)%*%matrix(c(x,y),2,1,byrow=T)+matrix(matriz[1,5:6],2,1,byrow=T)
f[,2]<-matrix(matriz[2,1:4],2,2,byrow=T)%*%matrix(c(x,y),2,1,byrow=T)+matrix(matriz[2,5:6],2,1,byrow=T)
f[,3]<-matrix(matriz[3,1:4],2,2,byrow=T)%*%matrix(c(x,y),2,1,byrow=T)+matrix(matriz[3,5:6],2,1,byrow=T)
f[,4]<-matrix(matriz[4,1:4],2,2,byrow=T)%*%matrix(c(x,y),2,1,byrow=T)+matrix(matriz[4,5:6],2,1,byrow=T)

Dai temos 4 possibilidades de novo ponto

> f [,1] [,2] [,3] [,4] [1,] 0 0.0 0.0 0.00 [2,] 0 1.6 1.6 0.44

Dai escolhemos qual ponto desse vai ser usado e mudamos os valores de x e y para esses novos pontos

ponto<-sample(1:nrow(matriz),1,prob=matriz[,7]) x<-f[1,ponto] y<-f[2,ponto]
> x [1] 0 > y [1] 1.6

Agora temos um conjunto com dois pontos, S=\{(0,0),(0,1.6)\} e podemos, se quisermos usar esse novos ponto, o 0 e 1.6 e jogar na função denovo e produzir dois novos pontos, e podemos fazer isso denovo, denovo, denovo, para produzir sei la, uns 3 mil pontos.

x<-0
y<-0
n<-3000
f<-matrix(0,ncol=4,nrow=2)
saida<-matrix(NA,ncol=2,nrow=n)
 
for(i in 1:n) {
    f[,1]<-matrix(matriz[1,1:4],2,2,byrow=T)%*%matrix(c(x,y),2,1,byrow=T)+matrix(matriz[1,5:6],2,1,byrow=T)
    f[,2]<-matrix(matriz[2,1:4],2,2,byrow=T)%*%matrix(c(x,y),2,1,byrow=T)+matrix(matriz[2,5:6],2,1,byrow=T)
    f[,3]<-matrix(matriz[3,1:4],2,2,byrow=T)%*%matrix(c(x,y),2,1,byrow=T)+matrix(matriz[3,5:6],2,1,byrow=T)
    f[,4]<-matrix(matriz[4,1:4],2,2,byrow=T)%*%matrix(c(x,y),2,1,byrow=T)+matrix(matriz[4,5:6],2,1,byrow=T)
    ponto<-sample(1:nrow(matriz),1,prob=matriz[,7])
    x<-f[1,ponto]
    y<-f[2,ponto]
    saida[i,]<-c(f[,ponto])
}

Agora criamos uma matriz saída para guardar esses 3 mil pontos que vamos produzir, e você pode pensar, meu, isso tem cara que não vai dar em nada, mas ao fazermos um gráfico vemos o seguinte.

01

Ha parece bruxaria, mas é matemágica. Pra figura ficar mais bonitinha, a gente pode usar pontos cheios e diminuir um pouco o tamanho deles.

02

Quem teve essa sacada, que certos conjuntos de funções, com parâmetros específicos construíam fractais, ou imagens com padrões que “significam” alguma coisa pra gente, ou que simplesmente são legais de se olhar foi um cara chamado John E. Hutchinson, mas o Michael Barnsley que escreveu um livro chamado Fractals Everywhere e popularizou essa ideia, tanto que essa “Samambaia” ai foi descrito por ele.

Com mudanças certas nos valores dos parâmetros, podemos fazer figuras um pouco diferentes, como folhinhas mais restas.

03

Bem, mas para se divertir no R experimentando esse esquema, podemos fazer uma função para fazer isso, talvez de forma um pouco mais econômica e testar mais alguns exemplos, ja que isso é bem legal.

IFS<-function(T,dist,cx,cy) {
    saida<-matrix(NA,ncol=2,nrow=T)
    x <- 0.0
    y <- 0.0
    for(t in 1:T) {
        r <- sample(1:length(dist),1,prob=dist)
        x0 <- cx[r,1]*x + cx[r,2]*y + cx[r,3]
        y0 <- cy[r,1]*x + cy[r,2]*y + cy[r,3]
        x <- x0
        y <- y0
        saida[t,]<-c(x, y)
    }
    return(saida)
}

Primeiro não precisamos fazer todas as equações, podemos primeiro sortear qual vamos usar, e depois so selecionar os valores, e como a equação é a mesma, basta guardar os valores de transição e modificar o que vai multiplicar, e por ultimo podemos fazer isso por variável, e não com matriz como fizemos primeiro, mas la só estávamos seguindo o exemplo do wikipedia, para compreender o processo, mas essa função faz exatamente aquele processo, somente dividindo aquela matriz gigante em uma para o x, uma para o y e as probabilidades de escolha de função e é isso. Na verdade eu so copiei o código em Java do livro do Introduction to Programming in Java do Robert Sedgewick.

Agora é so entrar os parâmetros nesse formato de geramos nossos pontos, prontos para virarem um gráfico.

#Samambaia
dist<-c(0.01,0.85,0.07,0.07)
cx<-matrix(c(0.00,0.00,0.50,0.85,0.04,0.075,0.20,-0.26,0.400,-0.15,0.28,0.575),ncol=3,nrow=4,byrow=T)
cy<-matrix(c(0.00,0.16,0.00,-0.04,0.85,0.18,0.23,0.22,0.045,0.26,0.24,-0.086),ncol=3,nrow=4,byrow=T)
 
samambaia<-IFS(100000,dist=dist,cx=cx,cy=cy)
 
plot(samambaia,pch=19,cex=0.3,col="darkgreen",main="Samambaia")

04

E podemos usar outros parâmetros para fazer outras folhas, um pouco modificadas

05

06

07

Ou até mesmo estruturas bem diferentes, como árvores

08

Mas claro que na minha visão, o legal é ver essas folhas, árvores sendo derivadas de regras simples, mas esse negocio funciona para outras formas também, desde o exemplo que talvez seja anterior a Samambaia, que é o triangulo de Sierpinski

09

Até essa outras coisas loucas

10

11

13

14

15

16

17

Bem, é isso ae, realmente A Samambaia de Barnsley como o Jogo da vida são exemplos interessantes de como regras simples podem fazer coisas que aparentam ser muito complexas. Um exemplo é a expectativas que tínhamos do número de genes do ser humano. Um gene é um pedaço de DNA que codifica uma proteína, antes do projeto genoma humano, todo mundo chutava números muito altos, como 100.000 pra mais, durante o projeto genoma humano que sequencio pela primeira vez todo o DNA de uma pessoa,segundo o James Watson, no livro DNA: The Secret of Life, existia uma banca de apostas, onde todo mundo chutava o número de genes que o ser humano tinha, e como somos o que somos, todo mundo achava que tínhamos que ser muito complicados, ter muitos genes diferentes, mas no final sabe quem ganhou? Ninguém, porque a estimativa foi de 20,000 a 25,000, de um quinto a um quarto dos chutes iniciais. Ou seja precisa de muito menos para ser humano que esperávamos.

Bem e além disso, eu acho que se um dia dar uma aula de R, esse vai ser um exemplo muito legal, todo mundo deve curtir fazer uma função tão simples e produzir algo tão legal.

Então o script está aqui em baixo, além do repositório recologia. E é isso, até o próximo post.

matriz<-matrix(c(0,0,0,0.16,0,0,0.01,0.85,0.04,-0.04,0.85,0,1.6,0.85,0.2,-0.26,0.23,0.22,0,1.6,0.07,-0.15,0.28,0.26,0.24,0,0.44,0.07)
               ,byrow=T,nrow=4,ncol=7,dimnames = list(c("f1", "f2","f3","f4"),c("a", "b", "c","d","e","f","p")))
matriz
 
x<-0
y<-0
n<-3000
f<-matrix(0,ncol=4,nrow=2)
saida<-matrix(NA,ncol=2,nrow=n)
 
for(i in 1:n) {
    f[,1]<-matrix(matriz[1,1:4],2,2,byrow=T)%*%matrix(c(x,y),2,1,byrow=T)+matrix(matriz[1,5:6],2,1,byrow=T)
    f[,2]<-matrix(matriz[2,1:4],2,2,byrow=T)%*%matrix(c(x,y),2,1,byrow=T)+matrix(matriz[2,5:6],2,1,byrow=T)
    f[,3]<-matrix(matriz[3,1:4],2,2,byrow=T)%*%matrix(c(x,y),2,1,byrow=T)+matrix(matriz[3,5:6],2,1,byrow=T)
    f[,4]<-matrix(matriz[4,1:4],2,2,byrow=T)%*%matrix(c(x,y),2,1,byrow=T)+matrix(matriz[4,5:6],2,1,byrow=T)
    ponto<-sample(1:nrow(matriz),1,prob=matriz[,7])
    x<-f[1,ponto]
    y<-f[2,ponto]
    saida[i,]<-c(f[,ponto])
}
 
plot(saida)
 
plot(saida,pch=19,cex=0.5)
#############################################################
matriz<-matrix(c(0,0,0,0.25,0,-0.4,0.02,0.95,0.005,-0.005,0.93,-0.002,0.5,0.84,0.035,-0.2,0.16,0.04,-0.09,0.02,0.07,
                 -0.04,0.2,0.16,0.04,0.083,0.12,0.07),byrow=T,nrow=4,ncol=7,dimnames = list(c("f1", "f2","f3","f4"),
                                                                                c("a", "b", "c","d","e","f","p")))
matriz
x<-0
y<-0
n<-100000
f<-matrix(0,ncol=4,nrow=2)
saida<-matrix(NA,ncol=2,nrow=n)
 
for(i in 1:n) {
    f[,1]<-matrix(matriz[1,1:4],2,2,byrow=T)%*%matrix(c(x,y),2,1,byrow=T)+matrix(matriz[1,5:6],2,1,byrow=T)
    f[,2]<-matrix(matriz[2,1:4],2,2,byrow=T)%*%matrix(c(x,y),2,1,byrow=T)+matrix(matriz[2,5:6],2,1,byrow=T)
    f[,3]<-matrix(matriz[3,1:4],2,2,byrow=T)%*%matrix(c(x,y),2,1,byrow=T)+matrix(matriz[3,5:6],2,1,byrow=T)
    f[,4]<-matrix(matriz[4,1:4],2,2,byrow=T)%*%matrix(c(x,y),2,1,byrow=T)+matrix(matriz[4,5:6],2,1,byrow=T)
    ponto<-sample(1:nrow(matriz),1,prob=matriz[,7])
    x<-f[1,ponto]
    y<-f[2,ponto]
    saida[i,]<-c(f[,ponto])
}
 
plot(saida,pch=19,cex=0.4)
 
#####################################
IFS<-function(T,dist,cx,cy) {
    saida<-matrix(NA,ncol=2,nrow=T)
    x <- 0.0
    y <- 0.0
    for(t in 1:T) {
        r <- sample(1:length(dist),1,prob=dist)
        x0 <- cx[r,1]*x + cx[r,2]*y + cx[r,3]
        y0 <- cy[r,1]*x + cy[r,2]*y + cy[r,3]
        x <- x0
        y <- y0
        saida[t,]<-c(x, y)
    }
    return(saida)
}
 
########################
#Samambaia
dist<-c(0.01,0.85,0.07,0.07)
cx<-matrix(c(0.00,0.00,0.50,0.85,0.04,0.075,0.20,-0.26,0.400,-0.15,0.28,0.575),ncol=3,nrow=4,byrow=T)
cy<-matrix(c(0.00,0.16,0.00,-0.04,0.85,0.18,0.23,0.22,0.045,0.26,0.24,-0.086),ncol=3,nrow=4,byrow=T)
 
samambaia<-IFS(100000,dist=dist,cx=cx,cy=cy)
plot(samambaia,pch=19,cex=0.3,col="darkgreen",main="Samambaia")
 
#Samambaia Culcita
dist<-c(0.0200, 0.8400, 0.0700, 0.0700)
 
cx<-matrix(c( 0.000,  0.000,  0.500,
              0.850,  0.020,  0.075,
              0.090, -0.280,  0.455,
             -0.090,  0.280,  0.545),ncol=3,nrow=length(dist),byrow=T)
 
cy<-matrix(c( 0.000,  0.250, -0.014,
             -0.020,  0.830,  0.110,
              0.300,  0.110, -0.090,
              0.300,  0.090, -0.080),ncol=3,nrow=length(dist),byrow=T)
 
Culcita<-IFS(100000,dist=dist,cx=cx,cy=cy)
plot(Culcita,pch=19,cex=0.3,col="darkgreen",main="Samambaia Culcita")
 
#Samambaia Cyclosorus
dist<-c(0.02, 0.84, 0.07, 0.07)
 
cx<-matrix(c(0.000,  0.000,  0.500,
             0.950,  0.005,  0.025,
             0.035, -0.200,  0.474,
            -0.040,  0.200,  0.528),ncol=3,nrow=length(dist),byrow=T)
 
cy<-matrix(c( 0.000,  0.250, -0.040,
             -0.005,  0.930,  0.053,
              0.160,  0.040, -0.078,
              0.160,  0.040, -0.068),ncol=3,nrow=length(dist),byrow=T)
 
Cyclosorus<-IFS(100000,dist=dist,cx=cx,cy=cy)
plot(Cyclosorus,pch=19,cex=0.3,col="darkgreen",main="Samambaia Cyclosorus")
 
#Samambaia sedgewick
dist<-c(0.02,0.15,0.13,0.70)
 
cx<-matrix(c(0.000,0.000,0.500,
             -0.139,0.263,0.570,
             0.170,-0.215,0.408,
             0.781,0.034,0.1075),ncol=3,nrow=length(dist),byrow=T)
 
cy<-matrix(c(0.000,0.270,0.000,
             0.246,0.224,-0.036,
             0.222,0.176,0.0893,
             -0.032,0.739,0.270),ncol=3,nrow=length(dist),byrow=T)
 
Sedgewick<-IFS(100000,dist=dist,cx=cx,cy=cy)
plot(Sedgewick,pch=19,cex=0.3,col="darkgreen",main="Samambaia Sedgewick")
 
#arvore
dist<-c(0.1,0.1,0.2,0.2,0.2,0.2)
 
cx<-matrix(c(0.00,0.00,0.550,
            -0.05,0.00,0.525,
             0.46,-0.15,0.270,
             0.47,-0.15,0.265,
             0.43,0.28,0.285,
             0.42,0.26,0.290),ncol=3,nrow=length(dist),byrow=T)
 
cy<-matrix(c(0.00,0.60,0.000,
            -0.50,0.00,0.750,
             0.39,0.38,0.105,
             0.17,0.42,0.465,
            -0.25,0.45,0.625,
            -0.35,0.31,0.525),ncol=3,nrow=length(dist),byrow=T)
 
arvore<-IFS(100000,dist=dist,cx=cx,cy=cy)
plot(arvore,pch=19,col="darkgreen",cex=0.3,main="Árvore")
 
#Triângulo de sierpinski
dist<-c(0.33,0.33,0.34)
cx<-matrix(c(0.50,0.00,0.00,0.50,0.00,0.50,0.50,0.00,0.25),ncol=3,nrow=3,byrow=T)
cy<-matrix(c(0.00,0.50,0.00,0.00,0.50,0.00,0.00,0.50,0.433),ncol=3,nrow=3,byrow=T)
 
triangulo<-IFS(10000,dist=dist,cx=cx,cy=cy)
plot(triangulo,pch=19,cex=0.4,main="Triângulo de sierpinski")
 
#binary
dist<-c(0.3333,0.3333,0.3334)
cx<-matrix(c(0.5,0.0,-0.0063477,0.5,0.0,0.4936544,0.0,-0.5,0.9873085),ncol=3,nrow=3,byrow=T)
cy<-matrix(c(0.0,0.5,-0.0000003,0.0,0.5,-0.0000003,0.5,0.0,0.5063492),ncol=3,nrow=3,byrow=T)
 
binary<-IFS(100000,dist=dist,cx=cx,cy=cy)
plot(binary,pch=19,cex=0.3,main="binary")
 
#dragon
dist<-c(0.787473,  0.212527)
 
cx<-matrix(c( 0.824074,  0.281482, -0.1002660,
   0.088272,  0.520988,  0.5344000),ncol=3,nrow=length(dist),byrow=T)
 
cy<-matrix(c(-0.212346,  0.864198,  0.0951123,
  -0.463889, -0.377778,  1.0415240),ncol=3,nrow=length(dist),byrow=T)
 
dragon<-IFS(100000,dist=dist,cx=cx,cy=cy)
plot(dragon,pch=19,cex=0.3,main="dragon")
 
#Espinha de Peixe
dist<-c(0.0200,0.8400,0.0700,0.0700)
 
cx<-matrix(c(0.000,0.000,0.500,
             0.950,0.002,0.025,
             0.035,-0.110,0.478,
             -0.040,0.110,0.525),ncol=3,nrow=length(dist),byrow=T)
 
cy<-matrix(c(0.000,0.250,-0.040,
            -0.002,0.930,0.051,
             0.270,0.010,-0.135,
             0.270,0.010,-0.129),ncol=3,nrow=length(dist),byrow=T)
 
espinha<-IFS(100000,dist=dist,cx=cx,cy=cy)
plot(espinha,pch=19,cex=0.3,main="Espinha de Peixe")
 
#Chão
dist<-c(0.3333,0.3333,0.3334)
 
cx<-matrix(c(0.0,-0.5,0.3267634,
             0.5,0.0,0.2472109,
             0.0,0.5,0.6620804),ncol=3,nrow=length(dist),byrow=T)
 
cy<-matrix(c(0.5,0.0,0.0866182,
             0.0,0.5,0.5014877,
            -0.5,0.0,0.5810401),ncol=3,nrow=length(dist),byrow=T)
 
chao<-IFS(100000,dist=dist,cx=cx,cy=cy)
plot(chao,pch=19,cex=0.3,main="Chão")
 
#koch
dist<-c(0.151515  0.253788  0.253788  0.151515  0.189394)
 
cx<-matrix(c(0.307692,-0.000000,0.7580704,
  0.192308,-0.205882,0.3349620,
  0.192308,0.205882,0.4707040,
  0.307692,-0.000000,-0.0674990,
  0.307692,-0.000000,0.3453822),ncol=3,nrow=length(dist),byrow=T)
 
cy<-matrix(c(0.000000,0.294118,0.1604278,
  0.653846,0.088235,0.2709686,
  -0.653846,0.088235,0.9231744,
  0.000000,0.294118,0.1604278,
  0.000000,-0.294118,0.2941176),ncol=3,nrow=length(dist),byrow=T)
 
koch<-IFS(100000,dist=dist,cx=cx,cy=cy)
plot(koch,pch=19,cex=0.3,main="koch")
 
#Espiral
dist<-c(0.895652,0.052174,0.052174)
 
cx<-matrix(c(0.787879,-0.424242,0.2819252,
            -0.121212,0.257576,-0.1115594,
             0.181818,-0.136364,1.0177017),ncol=3,nrow=length(dist),byrow=T)
 
cy<-matrix(c(0.242424,0.859848,0.0195945,
             0.151515,0.053030,0.0619661,
             0.090909,0.181818,0.1113490),ncol=3,nrow=length(dist),byrow=T)
 
espiral<-IFS(100000,dist=dist,cx=cx,cy=cy)
plot(espiral,pch=19,cex=0.3,main="Espiral")
 
 
#swirl pattern
dist<-c(0.9126750,0.0873250)
 
cx<-matrix(c(0.745455,-0.459091,0.2733004,
            -0.424242,-0.065152,1.0930777),ncol=3,nrow=length(dist),byrow=T)
 
cy<-matrix(c(0.406061,0.887121,-0.1339233,
            -0.175758,-0.218182,0.7620266),ncol=3,nrow=length(dist),byrow=T)
 
swirl<-IFS(100000,dist=dist,cx=cx,cy=cy)
plot(swirl,pch=19,cex=0.3,main="Swirl Pattern")
 
#zig-zag
dist<-c(0.888128,0.111872)
 
cx<-matrix(c(-0.632407,-0.614815,1.2002857,
             -0.036111,0.444444,0.7251636),ncol=3,nrow=length(dist),byrow=T)
 
cy<-matrix(c(-0.545370,0.659259,0.4009171,
              0.210185,0.037037,0.7279627),ncol=3,nrow=length(dist),byrow=T)
 
zigzag<-IFS(100000,dist=dist,cx=cx,cy=cy)
plot(zigzag,pch=19,cex=0.3,main="Zig Zag")