JSL per il video.
picpath = ""; // "D:\Chales\pic\m";
//http://www.fractalforums.com/mandelbrot-and-julia-set/good-coordinates-for-mandelbrot-zooms/
//
//Points on the boundary of the Mandelbrot set generally have the most interesting orbits. The easiest boundary points to compute are:
//
//* the spike along the negative real axis
//* the boundary of the main cardioid: r = (1 - cos(theta))/2, x = r*cos(theta)+0.25, y = r*sin(theta)
//* the boundary of the period 2 disk: r = 0.25, x = r*cos(theta)-1, y = r*sin(theta)
eps = 1.6; // slightly outside
deep = 10;
steps = 8000;
angle = 3;
scale = 2; // <<<<<<< video made with 20, very slow
xsize = 192 * scale;
ysize = 108 * scale;
diag = Sqrt( xsize ^ 2 + ysize ^ 2 );
mat = J( ysize, xsize, . );
New Window( "mandelbrot", bb = Border Box( Text Box( "wait" ) ) );
Wait( .2 );
num = 1e6;
For( t = 0, t < steps, t += 1,
If( eps > 1e-9, eps *= .997 );
deep += .3;
angle += eps / 50;
radius = (1 - Cos( angle )) / 2 + eps;
x = radius * Cos( angle ) + 0.25;
y = radius * Sin( angle );
top = y - eps;
bottom = y + eps;
left = x - eps * xsize / ysize;
right = x + eps * xsize / ysize;
d = Floor( Min( 1e5, deep ) );
Parallel Assign( {d = d}, mat[r( top, bottom ), c( left, right )] = Mandelbrot( d, 4, c, r ) );
mat = mat / d;
red = mat ^ .5;
green = mat ^ 9;
both = Loc( red :*</img> green == 1 );
red[both] = .1;
green[both] = .4;
blue = 1 - mat ^ .2;
blue[both] = .1;
img = New Image( "rgb", {red, green, blue} );
(bb << child) << delete;
bb << append( img );
num += 1;
If( picpath != "", img << saveimage( picpath || Char( num ) || ".png" ) );
bb << updatewindow;
Wait( 0 );
);
Ottimo, il primo è il più difficile. Ho scelto un percorso leggermente diverso utilizzando Blender (che utilizza ffmpeg internamente) anziché ffmpeg direttamente. Rinuncio a un po' di controllo sui parametri di ffmpeg (che non volevo perdere tempo ad imparare) e ottengo in cambio un editor di sequenze video piuttosto interessante (che ha una sua significativa curva di apprendimento).
Sembra che non l'abbia mai documentato, vedrò cosa posso fare.
Sì, esegue un'interpolazione lineare di 1..nrows in top..bottom. (simile per c, ncols, sinistra, destra).
Se ometti il bit (top,bottom), il valore r nell'espressione sarà 1..nrows.
Anche la parte {d = d} necessita di essere spiegata. Ogni thread ottiene la propria copia di tutto ciò a cui deve fare riferimento; la variabile del lato sinistro è il nome del thread di lavoro e quella del lato destro è il nome del thread principale. Su una macchina con 4 CPU l'assegnazione viene eseguita quattro volte. Se si tratta di una matrice enorme che stai copiando, potresti non vedere un miglioramento delle prestazioni.
Mandelbrot non ha bisogno di altri dati e si adatta bene. La maggior parte dei problemi reali richiede la lettura da un altro array e magari anche la contabilità.
Se vuoi sbirciare sotto le coperte, prova questo:
m=J(10,10,0);
x=0;
parallelassign({x=x++},m[r,c]=x);
show(x,m);
La mia macchina da 8 CPU produce questo:
x = 8;
m =
[ 0 1 2 3 4 5 6 7 0 1,
2 3 4 5 6 7 0 1 2 3,
4 5 6 7 0 1 2 3 4 5,
6 7 0 1 2 3 4 5 6 7,
0 1 2 3 4 5 6 7 0 1,
2 3 4 5 6 7 0 1 2 3,
4 5 6 7 0 1 2 3 4 5,
6 7 0 1 2 3 4 5 6 7,
0 1 2 3 4 5 6 7 0 1,
2 3 4 5 6 7 0 1 2 3];
Naturalmente non dovresti scrivere codice che dipenda da quel modello.
Si noti inoltre che il lato destro dell'assegnazione della matrice può essere più complicato.
m=J(400,600,0);
parallelassign({},m[r(-1,1),c(-1,1)]=(
z=sqrt(r^2+c^2);
z=if(z<.707,.707,z)-.5;
1-z; // last item in ; sequence is result
));
m=m/max(m); // for heat color
newwindow("example",newimage(heatcolor(m,"spectral")));
"z" esiste solo all'interno di ciascuno dei thread, una copia separata per ciascuno.
That flat area, dark red, was created by the if statementQuell'area piatta, rosso scuro, è stata creata dall'istruzione if
E sì, puoi usarlo per le dichiarazioni. Non dovresti provare a eseguire alcuna forma di I/O tranne la scrittura nel registro. Non creare caselle di visualizzazione, non aggiornare caselle di visualizzazione, non leggere o scrivere file su disco. Se non si blocca, sarà comunque sbagliato.
È possibile utilizzare i globali, ma utilizzano un mutex per serializzare l'accesso e il codice potrebbe non essere più veloce del codice non thread.
m=J(3,5,0);
global:words="";
parallelassign({},m[r(-1,1),c(-1,1)]=(
z=sqrt(r^2+c^2);
show(r+0,c+0,r+c,z); // r and c are special, use an expression
global:words||=char(z);
z=if(z<.707,.707,z)-.5;
1-z; // last item in ; sequence is result
));
show(words);
global:words è costruito in un ordine imprevedibile, determinato dalla velocità di esecuzione dei diversi thread.
JSL è complicato (internamente) e lo è anche il threading. La funzione parallelassign cerca di mantenere tutto sano (quelle copie, per esempio). Se trovi un modo per aggirare qualcosa che sta cercando di impedirti di fare, potresti danneggiare le strutture dati interne quando due thread vi accedono contemporaneamente e ciò causerà l'arresto anomalo di JMP a un certo punto. Risparmia spesso.
Oh...un'ultima nota sulle matrici 1D: usa due pedici! Ci sono alcune situazioni confuse se si dispone di un vettore di riga 1xN e si tenta di utilizzare un singolo pedice. Utilizzare R,C e ignorare il valore costante R==1.
Mi sono divertito un po' con questo script, apportando alcune modifiche e creando la serie di immagini da convertire in un video per realizzare i miei tour di Mandelbrot.
Domanda: La funzione Parallel Assign(): sto cercando riferimenti alla sintassi? Non lo vedo nei libri sullo scripting JMP, ma c'è una voce nella Guida allo scripting JMP sotto Guida. Non mi è chiaro cosa stai facendo con la funzione Parallel Assign nel tuo script.
Parallel Assign( {d = d}, mat[r( top, bottom ), c( left, right )] = Mandelbrot( d, 4, c, r ) );cosa fanno per te la r(in alto, in basso) e la c(sinistra, destra)? superiore, inferiore, sinistra e destra vengono determinati appena prima nello script per determinare i confini delle coordinate del fotogramma che stai creando. Presumo che stia eseguendo una sorta di interpolazione tra alto, basso e sinistra, destra per ottenere le coordinate yex da utilizzare? Esiste una descrizione generale di questa sintassi da qualche parte?