momente şi schiţe de informatică şi matematică
To attain knowledge, write. To attain wisdom, rewrite.

Fractalii Newton ai rădăcinilor unităţii - partea a doua

limbajul R
2017 jun

5. Obţinerea preimaginilor originii

Pentru orice punct $z \ne 0$ putem determina $z_1=N(z)=z-\dfrac{z^n-1}{nz^{n-1}}=\dfrac{(n-1)z^n+1}{nz^{n-1}}$; dacă $z_1\ne 0$, putem obţine $z_2=N(z_1)=N(N(z))=N^{\circ 2}(z)$ şi dacă $z_2 \ne 0$ - putem continua "orbita" lui $z$ cu $z_3=N(z_2)=N^{\circ 3}(z)$, ş.a.m.d. Dacă la un anumit moment $z_k=N^{\circ k}(z)=0$, atunci iterarea nu mai trebuie continuată (am avea "împărţire la zero", deci $z_{k+1}=\infty$); în acest caz $z$ este punct "de excepţie" (nu orbitează spre vreuna dintre rădăcinile unităţii; v. [1]).

Deci preimaginile lui $0$ formează o submulţime - strictă, cum vom arăta mai târziu în §6 - a mulţimii tuturor punctelor "de excepţie". Avem $n$ preimagini "imediate" ale lui $0$ - anume, punctele $z$ pentru care $(n-1)z^n=-1$; fiecare dintre acestea are câte $n$ preimagini, deci avem (cel puţin) $n^2$ preimagini "de odinul doi" ale lui $0$, ş.a.m.d.

Dacă $\zeta$ este o preimagine de un anumit ordin a lui $0$, pentru a găsi preimaginile lui $\zeta$ avem de rezolvat ecuaţia $N(z)=\zeta \iff (n-1)z^n-n\zeta z^{n-1}+1=0$; următoarea funcţie produce o funcţie care, primind parametrul $\zeta$ returnează vectorul celor $n$ coeficienţi ai polinomului din această ecuaţie (în ordinea crescătoare a gradelor monoamelor):

poly_newton <- function(n) {
  function(zeta) c(1, rep(0, n-2), -n*zeta, n-1)
}

Putem obţine rădăcinile unui polinom folosind funcţia polyroot(); de exemplu, pentru $n=4$ avem $N(z)=0 \iff 3z^4=-1 \iff z=3^{-1/4}\sqrt[4]{-1}=3^{-1/4} {\boldsymbol e}^{{\boldsymbol {i(2h\pi + \pi)/4}}}{\textstyle ,~\small h=0..3}$ - ceea ce verificăm acum şi astfel:

pn4 <- poly_newton(4)
print(polyroot(pn4(0)))  # rădăcinile ecuaţiei 3z^4 + 1 = 0
[1]  0.537285+0.537285i -0.537285+0.537285i -0.537285-0.537285i  0.537285-0.537285i
print(3^(-1/4)*exp(1i*(2*(0:3)+1)*pi/4))  # (atestând rădăcinile obţinute mai sus)

Dacă vectorul 'roots' conţine preimaginile lui $0$ (de un acelaşi anumit ordin), atunci putem folosi mecanismul apply() pentru a obţine mulţimea tuturor preimaginilor acestora:

sapply(roots, function(r) polyroot(pn4(r)))  # rezolvă N(z)=r pentru ∀r ∈ 'roots'

În final, putem asambla cu cele de mai sus următoarea funcţie, prin care obţinem mulţimea preimaginilor lui $0$ până la o anumită adâncime de iterare:

orb2zero <- function(n = 3, iterations = 10) {
  poly_newton <- function(deg) {
    function(zeta) c(1, rep(0, deg-2), -zeta*deg, deg-1)
  }
  pn <- poly_newton(n)
  get_preimages <- function(roots) {
    as.vector(sapply(roots, function(r) polyroot(pn(r))))
  }
  allr <- roots <- polyroot(pn(0))
  for(i in 1:iterations) {
    roots <- get_preimages(roots) 
    allr <- append(allr, roots)  # append(allr, roots[abs(roots) < 1.56])
  }
  return(allr)
}

Nu ne speriem deocamdată de faptul că este necesară multă memorie şi în plus, execuţia poate dura mult (pentru $n \gt 4$, sau/şi 'iterations' > 10); vom vedea poate mai târziu, cum s-ar formula mai eficient funcţia de mai sus. O idee de reducere (eventual, chiar "drastică") a cerinţei de memorie este deja sugerată în linia de comentariu din textul funcţiei redat mai sus: păstrăm numai preimaginile care se află într-un anumit disc (de rază 1, de exemplu) centrat în origine.

Putem folosi orb2zero() (pentru a obţine imagini precum cele tocmai redate), după modelul:

orb <- orb2zero(it=12)
orb <- orb[abs(orb) < 1.56]  # restrânge la un anumit disc centrat în origine
png <- png("orb2zero.png", units="px", width=1200, height=600, bg="white")
opar <- par(mfrow = c(1, 2), mar=c(0, 0, 0, 0), bty="n")
plot(orb, pch=20, cex=0.01, asp=1); grid()  
orb <- orb[Re(orb) < -0.05 & Re(orb) > -2^(-1/3)-0.05]  # selectează o "petală"
plot(orb, pch=20, cex=0.01, asp=1); grid()
dev.off(); par(opar)

După ce am obţinut în vectorul 'orb' preimaginile lui $0$ (până la ordinul 12), am selectat numai pe cele aflate într-un anumit disc centrat în origine (experimentând cu diverse raze) şi respectiv (pentru a doua imagine), pe cele corespunzătoare unui anumit detaliu (aici, "petala" formată în stânga originii) - şi am plotat apoi punctele respective.

Imaginile rezultate "trunchiază" mulţimea denumită de obicei mulţimea Julia a transformării respective; aceasta este frontiera comună a bazinelor de atracţie ale rădăcinilor polinomului, pe întregul plan (în vecinătatea oricât de mică a oricărui punct al ei există "pre-imagini" ale fiecărei rădăcini - cu interpretarea şocantă că în fiecare punct "se întâlnesc" câte $n$ culori; "pre-imagine" a rădăcinii însemnând aici un punct a cărui orbită converge la o rădăcină a polinomului).

Dacă ignorăm contextul şi vedem imaginile ca atare, ne-am putea gândi să testăm anumite transformări asupra vectorilor 'orb' din secvenţa de mai sus; de exemplu, plotând pătratele acestora (plot(orb^2, ...)) găsim:

Este discutabil dacă asemenea transformări au vreo relevanţă pentru fractali, dar vedem că pot rezulta şi "decoraţiuni" interesante.

Rămânând la terminologia modestă din [1], ne propunem în §6 să căutăm şi altfel de "puncte de excepţie" (cele ale căror orbite sunt şiruri periodice neatractoare).

vezi Cărţile mele (de programare)

docerpro | Prev | Next