JSL 的视频。
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 );
);
酷,第一个是最难的。 我选择了使用 Blender(内部使用 ffmpeg)而不是直接使用 ffmpeg 的稍微不同的路径。 我放弃了对 ffmpeg 参数的一些控制(我不想花时间学习)并获得一个非常酷的视频序列编辑器作为交换(它有自己重要的学习曲线)。
感谢您提供有关并行分配()的详细信息!我的脑子里充满了如何使用它的想法。
看来我从未记录过这一点,我会看看我能做什么。
是的,它对 top..bottom 进行 1..nrows 的线性插值。 (与 c、ncols、左、右类似)。
如果省略 (top,bottom) 位,则表达式中的 r 值将为 1..nrows。
{d = d} 部分也需要解释。 每个线程都会获得自己需要引用的所有内容的副本;左侧变量是工作线程的名称,右侧是主线程的名称。 在 4 CPU 机器上,该分配完成四次。 如果您正在复制的恰好是一个巨大的矩阵,您可能不会看到性能改进。
Mandelbrot 不需要其他数据并且可以很好地扩展。 大多数实际问题需要从另一个数组中读取,并且可能还需要进行一些簿记。
如果你想一探究竟,试试这个:
m=J(10,10,0);
x=0;
parallelassign({x=x++},m[r,c]=x);
show(x,m);
我的 8-cpu 机器产生这个:
x = 8;
米=
[ 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];
当然,您不应该编写依赖于该模式的代码。
另请注意,矩阵分配的右侧可能更复杂。
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”仅存在于每个线程内,每个线程都有一个单独的副本。
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 statement该平坦区域,深红色,是由 if 语句创建的
是的,您可以使用 for 语句。 除了写入日志之外,您不应尝试执行任何形式的 I/O。 不要制作显示盒,不要更新显示盒,不要读取或写入磁盘文件。 如果不崩溃,它仍然会出错。
您可以使用全局变量,但它们使用互斥体来序列化访问,并且代码可能不会比非线程代码快。
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 是以不可预测的顺序构建的,由不同线程的运行速度决定。
JSL 很复杂(内部),线程也很复杂。 ParallelAssign 函数尝试保持一切正常(例如,那些副本)。 如果您找到一种方法来解决它试图阻止您做的事情,那么当两个线程同时访问内部数据结构时,您可能会损坏内部数据结构,这将导致 JMP 在某些时候崩溃。 经常保存。
哦...关于一维矩阵的最后一点注意:使用两个下标! 如果您有 1xN 行向量并尝试使用单个下标,则会出现一些令人困惑的情况。 使用 R,C 并忽略常量 R==1 值。
我对这个脚本很感兴趣,做了一些修改并创建了图像系列以转换为视频以制作我自己的曼德尔布罗之旅。
问题:并行赋值()函数——我正在寻找它的语法参考?我在 JMP 脚本编写书籍中没有看到它,但在《JMP 脚本指南》的“帮助”下有一个条目。我不清楚您在脚本中使用并行分配函数做什么。
Parallel Assign( {d = d}, mat[r( top, bottom ), c( left, right )] = Mandelbrot( d, 4, c, r ) );r(上、下)和c(左、右)对你有什么作用?顶部、底部、左侧和右侧是在脚本之前确定的,以确定您正在创建的框架的坐标边界。我假设它正在顶部、底部和左、右之间进行某种插值以获得要使用的 y 和 x 坐标?某处有这种语法的一般描述吗?
欢迎,谢谢! 该视频也花了几个小时来渲染,但它是 4K 分辨率和数千帧。
我开始创作吉克斯80 年代的节目。渲染分形需要数小时的 microVAX 计算时间。感谢分享。