视频的 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 参数的一些控制(我不想花时间学习)并换取了一个非常酷的视频序列编辑器(它有自己重要的学习曲线)。
感谢您提供有关 Parallel Assign() 的详细信息!我的大脑在思考如何使用它。
看起来我从未记录过这一点,我会看看我能做些什么。
是的,它将 1..nrows 线性插值到 top..bottom。 (类似于 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 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 值。
我从这个脚本中获得了一些乐趣,做了一些修改并创建了图像系列以转换成视频来制作我自己的 mandelbrot 之旅。
问题:Parallel Assign() 函数——我正在寻找它的语法参考?我在 JMP 脚本书籍中没有看到它,但在帮助下的 JMP 脚本指南中有一个条目。我不清楚您在脚本中使用 Parallel Assign 函数做什么。
Parallel Assign( {d = d}, mat[r( top, bottom ), c( left, right )] = Mandelbrot( d, 4, c, r ) );r(top,bottom) 和 c(left, right) 对你有什么作用?顶部、底部、左侧和右侧是在脚本中预先确定的,以确定您正在创建的框架的坐标边界。我假设它正在顶部、底部和左侧、右侧之间进行某种插值以获得要使用的 y 和 x 坐标?某处是否有此语法的一般描述?
欢迎,并感谢! 该视频也需要数小时才能渲染,但它是 4K 分辨率和数千帧。
我开始创作GKS 80年代的节目。渲染一个分形需要数小时的 microVAX 计算时间。感谢分享。