JSL por el vídeo.
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 );
);
Parece que nunca documenté eso, veré qué puedo hacer.
Sí, hace una interpolación lineal de 1..nrows en top..bottom. (similar para c, ncols, izquierda, derecha).
Si omite el bit (superior, inferior), el valor r en la expresión será 1...nfilas.
La parte {d = d} también necesita explicación. Cada subproceso obtiene su propia copia de todo lo que necesita referenciar; la variable del lado izquierdo es el nombre del subproceso de trabajo y el lado derecho es el nombre del subproceso principal. En una máquina de 4 CPU, esa asignación se realiza cuatro veces. Si lo que está copiando es una matriz enorme, es posible que no vea una mejora en el rendimiento.
Mandelbrot no necesita otros datos y escala muy bien. La mayoría de los problemas reales necesitan leer de otra matriz y tal vez también hacer algo de contabilidad.
Si quieres echar un vistazo debajo de las sábanas, prueba esto:
m=J(10,10,0);
x=0;
parallelassign({x=x++},m[r,c]=x);
show(x,m);
Mi máquina de 8 CPU produce esto:
x = 8;
metro =
[ 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];
Por supuesto, no debe escribir código que dependa de ese patrón.
También observe que el lado derecho de la asignación de matriz puede ser más complicado.
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" solo existe dentro de cada uno de los hilos, una copia separada para cada uno.
That flat area, dark red, was created by the if statementThat flat area, dark red, was created by the if statementThat flat area, dark red, was created by the if statementThat flat area, dark red, was created by the if statementEsa área plana, de color rojo oscuro, fue creada por la instrucción if
Y sí, puede usar para declaraciones. No debe intentar realizar ningún tipo de E/S excepto escribir en el registro. No haga cuadros de visualización, no actualice cuadros de visualización, no lea ni escriba archivos de disco. Si no falla, seguirá estando mal.
Puede usar globales, pero usan un mutex para serializar el acceso y es posible que el código no sea más rápido que el código sin subprocesamiento.
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 se crea en un orden impredecible, determinado por la rapidez con la que se ejecutan los distintos subprocesos.
JSL es complicado (internamente) y también lo es el enhebrado. La función de asignación paralela intenta mantener todo en orden (esas copias, por ejemplo). Si encuentra una manera de evitar algo que intenta evitar que haga, puede estar dañando las estructuras de datos internas cuando dos subprocesos acceden a ellos al mismo tiempo, y eso hará que JMP se bloquee en algún momento. Ahorre a menudo.
Oh... una nota final sobre las matrices 1D: ¡use dos subíndices! Hay algunas situaciones confusas si tiene un vector de fila 1xN e intenta usar un solo subíndice. Utilice R,C e ignore el valor constante R==1.
Me he estado divirtiendo con este guión, haciendo algunas modificaciones y creando la serie de imágenes para convertirlas en un video para hacer mis propios recorridos de mandelbrot.
Pregunta: La función Parallel Assign() -- ¿Estoy buscando una referencia de sintaxis en ella?No lo veo en los libros de secuencias de comandos de JMP, pero hay una entrada en la Guía de secuencias de comandos de JMP en Ayuda.No me queda claro qué está haciendo con la función de asignación paralela en su secuencia de comandos.
Parallel Assign( {d = d}, mat[r( top, bottom ), c( left, right )] = Mandelbrot( d, 4, c, r ) );¿Qué hace la r (arriba, abajo) y la c (izquierda, derecha) por ti?arriba, abajo, izquierda y derecha se determinan justo antes en la secuencia de comandos para determinar los límites de coordenadas del marco que está creando.Supongo que está haciendo algún tipo de interpolación entre arriba, abajo e izquierda, derecha para obtener las coordenadas y y x para usar.¿Hay una descripción general de esta sintaxis en alguna parte?