JSL pour la vidéo.
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 );
);
Il semble que je n'ai jamais documenté cela, je vais voir ce que je peux faire.
Oui, il fait une interpolation linéaire de 1..nrows en haut..bas. (similaire pour c, ncols, gauche, droite).
Si vous omettez le bit (haut, bas), la valeur r dans l'expression sera 1..nrows.
La partie {d = d} doit également être expliquée. Chaque thread obtient sa propre copie de tout ce qu'il doit référencer ; la variable de gauche est le nom du thread de travail et celle de droite est le nom du thread principal. Sur une machine à 4 processeurs, cette affectation est effectuée quatre fois. S'il s'agit d'une énorme matrice que vous copiez, vous ne verrez peut-être pas d'amélioration des performances.
Mandelbrot n'a besoin d'aucune autre donnée et évolue bien. La plupart des vrais problèmes doivent lire à partir d'un autre tableau et peut-être aussi faire de la comptabilité.
Si vous voulez jeter un coup d'œil sous les couvertures, essayez ceci :
m=J(10,10,0);
x=0;
parallelassign({x=x++},m[r,c]=x);
show(x,m);
Ma machine à 8 processeurs produit ceci:
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] ;
Vous ne devez pas écrire de code qui dépend de ce modèle, bien sûr.
Notez également que le côté droit de l'affectation de la matrice peut être plus compliqué.
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" n'existe qu'à l'intérieur de chacun des threads, une copie distincte pour chacun.
That flat area, dark red, was created by the if statementCette zone plate, rouge foncé, a été créée par l'instruction if
Et oui, vous pouvez utiliser pour les déclarations. Vous ne devez pas essayer d'effectuer une quelconque forme d'E/S à l'exception de l'écriture dans le journal. Ne faites pas de boîtes d'affichage, ne mettez pas à jour les boîtes d'affichage, ne lisez pas ou n'écrivez pas de fichiers sur le disque. S'il ne plante pas, ce sera toujours faux.
Vous pouvez utiliser des globals, mais ils utilisent un mutex pour sérialiser l'accès et le code peut ne pas être plus rapide que le code sans 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 est construit dans un ordre imprévisible, déterminé par la vitesse d'exécution des différents threads.
JSL est compliqué (en interne) et le threading aussi. La fonction parallelassign essaie de garder tout sain (ces copies, par exemple). Si vous trouvez un moyen de contourner quelque chose qu'il essaie de vous empêcher de faire, vous risquez d'endommager les structures de données internes lorsque deux threads y accèdent en même temps, ce qui entraînera le blocage de JMP à un moment donné. Économisez souvent.
Oh... une dernière remarque sur les matrices 1D : utilisez deux indices ! Il y a des situations déroutantes si vous avez un vecteur ligne 1xN et essayez d'utiliser un seul indice. Utilisez R,C et ignorez la valeur constante R==1.
Je me suis amusé avec ce script, en faisant quelques modifications et en créant la série d'images à convertir en vidéo pour faire mes propres visites de mandelbrot.
Question : La fonction Parallel Assign() -- Je recherche une référence de syntaxe dessus ?Je ne le vois pas dans les manuels de script JMP, mais il y a une entrée dans le Guide de script JMP sous Aide.Je ne comprends pas ce que vous faites avec la fonction Parallel Assign dans votre script.
Parallel Assign( {d = d}, mat[r( top, bottom ), c( left, right )] = Mandelbrot( d, 4, c, r ) );qu'est-ce que r(haut, bas) et c(gauche, droite) font pour vous ?haut, bas, gauche et droite sont déterminés juste avant dans le script pour déterminer les limites de coordonnées du cadre que vous créez.Je suppose qu'il fait une sorte d'interpolation entre le haut, le bas et la gauche, à droite pour obtenir les coordonnées y et x à utiliser?Existe-t-il quelque part une description générale de cette syntaxe ?