JSL für das 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 );
);
Es sieht so aus, als hätte ich das nie dokumentiert, ich werde sehen, was ich tun kann.
Ja, es führt eine lineare Interpolation von 1..nrows in top..bottom durch. (ähnlich für c, ncols, links, rechts).
Wenn Sie das (top,bottom)-Bit weglassen, ist der r-Wert im Ausdruck 1..nrows.
Der Teil {d = d} muss ebenfalls erklärt werden. Jeder Thread erhält seine eigene Kopie von allem, was er referenzieren muss; Die Variable auf der linken Seite ist der Name des Worker-Threads und die rechte Seite ist der Name des Haupt-Threads. Auf einer Maschine mit 4 CPUs wird diese Zuweisung viermal durchgeführt. Wenn es sich um eine riesige Matrix handelt, in die Sie kopieren, sehen Sie möglicherweise keine Leistungsverbesserung.
Mandelbrot benötigt keine weiteren Daten und skaliert gut. Die meisten echten Probleme müssen aus einem anderen Array gelesen und vielleicht auch etwas Buchhaltung gemacht werden.
Wenn Sie unter die Decke schauen möchten, versuchen Sie Folgendes:
m=J(10,10,0);
x=0;
parallelassign({x=x++},m[r,c]=x);
show(x,m);
Meine 8-CPU-Maschine produziert dies:
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];
Sie sollten natürlich keinen Code schreiben, der von diesem Muster abhängt.
Beachten Sie auch, dass die rechte Seite der Matrixzuweisung komplizierter sein kann.
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" existiert nur in jedem der Threads, eine separate Kopie für jeden.
That flat area, dark red, was created by the if statementDieser flache Bereich, dunkelrot, wurde durch die if-Anweisung erstellt
Und ja, Sie können for-Anweisungen verwenden. Sie sollten nicht versuchen, irgendeine Form von I/O auszuführen, außer in das Protokoll zu schreiben. Erstellen Sie keine Anzeigeboxen, aktualisieren Sie keine Anzeigeboxen, lesen oder schreiben Sie keine Datenträgerdateien. Wenn es nicht abstürzt, wird es immer noch falsch sein.
Sie können Globals verwenden, aber sie verwenden einen Mutex, um den Zugriff zu serialisieren, und der Code ist möglicherweise nicht schneller als Code ohne Threads.
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 wird in einer unvorhersehbaren Reihenfolge erstellt, die dadurch bestimmt wird, wie schnell verschiedene Threads ausgeführt werden.
JSL ist (intern) kompliziert, ebenso das Threading. Die parallelassign-Funktion versucht, alles in Ordnung zu halten (zum Beispiel diese Kopien). Wenn Sie einen Weg finden, etwas zu umgehen, wovon es Sie abzuhalten versucht, beschädigen Sie möglicherweise interne Datenstrukturen, wenn zwei Threads gleichzeitig darauf zugreifen, und das wird irgendwann zum Absturz von JMP führen. Speichern Sie oft.
Oh ... eine letzte Anmerkung zu 1D-Matrizen: Verwenden Sie zwei Indizes! Es gibt einige verwirrende Situationen, wenn Sie einen 1xN-Zeilenvektor haben und versuchen, einen einzelnen Index zu verwenden. Verwenden Sie R,C und ignorieren Sie den Wert der Konstante R==1.
Ich hatte viel Spaß mit diesem Skript, nahm einige Änderungen vor und erstellte die Bildserie, um sie in ein Video umzuwandeln, um meine eigenen Mandelbrot-Touren zu machen.
Frage: Die Funktion Parallel Assign() – ich suche nach einer Syntaxreferenz darauf?Ich sehe es nicht in den JMP-Scripting-Büchern, aber es gibt einen Eintrag im JMP-Scripting-Handbuch unter Hilfe.Mir ist nicht klar, was Sie mit der Parallel Assign-Funktion in Ihrem Skript machen.
Parallel Assign( {d = d}, mat[r( top, bottom ), c( left, right )] = Mandelbrot( d, 4, c, r ) );Was macht das r (oben, unten) und c (links, rechts) für Sie?Oben, Unten, Links und Rechts werden kurz zuvor im Skript bestimmt, um die Koordinatengrenzen des Rahmens zu bestimmen, den Sie erstellen.Ich nehme an, es wird eine Art Interpolation zwischen oben, unten und links und rechts durchgeführt, um die zu verwendenden y- und x-Koordinaten zu erhalten?Gibt es irgendwo eine allgemeine Beschreibung dieser Syntax?