Rustプログラミングでジュリア集合(Julia Set)

Rust言語でジュリア集合(Julia Set)をプログラミングした。
GitHubでコードを公開しています。

マンデルブロ集合ジュリア集合は姉妹関係にあります。
マンデルブロ集合では複素数zの初期値を0として、複素数cを複素平面上で変化させます。
$z_{0}=0$
$z_{n+1}=z_{n}^{2}+c$
漸化式をある回数、繰り返して計算し、値が収束するか発散するかを判定して、漸化式の計算回数に合わせて適当に色付けします。
これに対してJulia集合では複素数cを固定値にして、初期値zを複素平面上で変化させて複素数の漸化式計算を行います。
更にcをパラメータとして変化させて生成した複数の画像をアニメーション化すると以下の様な不思議な図形が現れます。

Rustプログラミング言語は高速性と安全性に優れていると言われているコンパイラ言語です。
C++と比較すると、クラスや継承が無いので、直接的にC++のプロジェクトから移行するのは困難でしょうが、
C++などでの比較的大規模なプロジェクトでよく悩ませられる問題の解決法の1つになるかもしれません。

Rustのクロージャーや並列処理を利用したプログラム例になります。
使い方はCargoでプロジェクトを新規に作成して、プロジェクトのデイレクトリにCDして画像保存用のフォルダを作成する。
以下の開発環境はLinux(Ubuntu20.04)で行っています。
複素数はnumクレートで直接使用できる。
rayonクレートによる並列処理による効果もあってか、400枚のJulia画像をほぼ瞬時に作成します。

cargo new julia
cd julia
mkdir julia
cargo run --release

main.rs
------------------------------------------------------------------------------------------------

//! An example of generating julia fractals.
//mkdir julia
// cargo run --release
extern crate image;
use num::complex::Complex;
use rayon::prelude::*;
 
fn main() {
    let imgx = 600; //画像の解像度 X
    let imgy = 600; //画像の解像度 Y
 
    let scalex = 3.0 / imgx as f64;
    let scaley = 3.0 / imgy as f64;
 
    const IMAGE_CNT: usize = 400; //画像数
    const RE_START: f64 = -0.8;
    const RE_STOP: f64 = -0.4;
    const IM_START: f64 = 0.1;
    const IM_STOP: f64 = 0.6;
    let mut c_array: [Complex<f64>; IMAGE_CNT] = [Complex::new(RE_START, IM_START); IMAGE_CNT];
 
    let delta = Complex::new(
        (RE_STOP - RE_START) / IMAGE_CNT as f64,
        (IM_STOP - IM_START) / IMAGE_CNT as f64,
    );
 
    (0..IMAGE_CNT)
        .into_iter()
        .for_each(|i| c_array[i] += delta * (i as f64));
 
    (0..IMAGE_CNT).into_par_iter().for_each(|n| {//IMAGE_CNT個の画像を並列処理で作成 
        let mut imgbuf = image::ImageBuffer::new(imgx, imgy);
        // Iterate over the coordinates and pixels of the image
        for (x, y, pixel) in imgbuf.enumerate_pixels_mut() {
            //カラーを初期化
            let r = (0.3 * x as f64) as u8;
            let b = (0.3 * y as f64) as u8;
            *pixel = image::Rgb([r, 0, b]);
        }
        //1個の画像を作成
        for (x, y, pixel) in imgbuf.enumerate_pixels_mut() {
            let cx = y as f64 * scalex - 1.5;
            let cy = x as f64 * scaley - 1.5;
            let mut z = Complex::new(cx, cy);
            let mut i = 0;
 
            while i < 255 && z.norm_sqr() <= 4.0 {
                z = z * z + c_array[n];
                i += 1;
            }
            let image::Rgb(data) = *pixel;
            *pixel = image::Rgb([data[0], i as u8, data[2]]);
        }
        // Save the image as “fractal.png”, the format is deduced from the path
        let s = format!("julia/foo-{:04}.png", n);
        imgbuf.save(&s).unwrap();
    })

}
--------------------------------------------------------------------------------------------------------------

Cargo.toml
----------------------------------------------------------------------------------------------------------------

[package]
name = "julia"
version = "0.1.0"
edition = "2018"
 
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
[dependencies]
num = "0.4.0"
image = "0.23.14"

rayon = "1.5.0"

 


-----------------------------------------------------------------------------------------------------------
更に全体を並列処理して高速化して、マンデルブロー集合のようにカラーパレットを使ってみました。
最大反復数を上げた効果もあってか、マンダラか地獄絵のような絵になりました。

やはりジュリア集合も色が命です。