Giter Club home page Giter Club logo

mandelbrot-orbits-rust's Introduction

Mandelbrot Orbits

Test MegaLinter

This is a small project to learn Rust.

It generates an image of the Mandelbrot Set where each pixel color represents the period of the complex point if the point belongs to the Set.

More info about Mandelbrot Set Periods.

You can render it in greyscale.

./docs/images/mandelbrot_2000x2000.png

Or the colorized version.

./docs/images/mandelbrot_2000x2000.png

With a different color depending on the period.

Requirements

  • cargo: ^1.62.1.
  • rustc: ^1.62.1.

Use

git clone [email protected]:josecelano/mandelbrot-orbits-rust.git
cargo run ./output/mandelbrot_2048x2048.png 2048x2048 -2.0,2.00 2.0,-2.0

Development

Execute MegaLinter locally:

./bin/ml.sh

Run tests:

cargo test

More info for developers.

Math

You can find an explanation here.

And I'm trying to find and write a more formal explanation of the math behind the algorithm.

./docs/images/math.png

Execution time

16384x16384px
4,7MB
72m57,099s
32768x32768px
15MB
268m23,032s

Credits

License

MIT.

Links

Repositories

Papers

Books

Wikibook

Demos

Other

mandelbrot-orbits-rust's People

Contributors

dependabot[bot] avatar josecelano avatar

Stargazers

 avatar

Watchers

 avatar  avatar  avatar

mandelbrot-orbits-rust's Issues

Re-use calculation for composition

The escape_time function calculates some interactions (255 right now):

fn escape_time(c: Complex<f64>, limit: usize) -> Option<usize> {
    let mut z = Complex { re: 0.0, im: 0.0 };
    for i in 0..limit {
        if z.norm_sqr() > 4.0 {
            return Some(i);
        }
        z = z * z + c;
    }

    None
}

But the is_period_p starts again from z = 0.

fn is_period_p(z: Complex<f64>,c: Complex<f64>, n: usize) -> bool {
    let max_period = 40;

    let mut result = z.clone();

    for _iter in 0..max_period {

        let lambda = lambda(result, c, n);
        let lambda_abs = lambda.abs();

        if lambda_abs >= 1. {
            return false;
        }

        result = phi(result, c);
    }

    true
}

as you can see in the render function:

fn render(pixels: &mut [u8],
          bounds: (usize, usize),
          upper_left: Complex<f64>,
          lower_right: Complex<f64>)
{
    assert!(pixels.len() == bounds.0 * bounds.1);

    for row in 0..bounds.1 {
        for column in 0..bounds.0 {

            // ...

            pixels[row * bounds.0 + column] =
                match escape_time(point, iteration_limit) {
                    None => {
                        // Mandelbrot Set point
                        // Calculate period
                        let z0 = Complex { re: 0.0, im: 0.0 };
                        let period = calculate_period(z0, point);

                        // ...

                        color
                    },
                    // Not a Mandelbrot Set point. Grayscale depending on the escape time
                    Some(count) => iteration_limit as u8 - count as u8,
                };
        }
    }
}

Consider returning zn from escape_time instead of starting from z0.

Enable `dependabot`

Add file: .github/dependabot.yml

version: 2
updates:
  - package-ecosystem: "cargo" # See documentation for possible values
    directory: "/" # Location of package manifests
    schedule:
      interval: "weekly

Remove darker pixels?

image

At the edge, some pixels are darker than they should. That's because the period is not calculated well, probably because the interactions are insufficient.

If we want to improve the artistic result without increasing the number of iterations. We can apply the direct formulas to detect periods 1 and 2 and adjust the colour.

Workflow with e2e test

We can add a new workflow to generate a sample image. The workflow could:

  • Accept the same input parameters as the console app when you run it manually.
  • Generate an artefact and upload it so you can download the resulting image.

Fix CVE-2021-32810

The image dependency has a transitive dependency with a vulnerability:

  Cargo.lock (cargo)
  ==================
  Total: 1 (UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 0, CRITICAL: 1)
  
  ┌─────────────────┬────────────────┬──────────┬───────────────────┬───────────────┬──────────────────────────────────────────────────────────────┐
  │     Library     │ Vulnerability  │ Severity │ Installed Version │ Fixed Version │                            Title                             │
  ├─────────────────┼────────────────┼──────────┼───────────────────┼───────────────┼──────────────────────────────────────────────────────────────┤
  │ crossbeam-deque │ CVE-2021-32810 │ CRITICAL │ 0.8.00.7.4, 0.8.1  │ rust-crossbeam-deque: race condition may lead to double free │
  │                 │                │          │                   │               │ https://avd.aquasec.com/nvd/cve-2021-32810                   │
  └─────────────────┴────────────────┴──────────┴───────────────────┴───────────────┴──────────────────────────────────────────────────────────────┘
├── image v0.24.3
│   ├── bytemuck v1.11.0
│   ├── byteorder v1.4.3
│   ├── color_quant v1.1.0
│   ├── exr v1.4.2
│   │   ├── bit_field v0.10.1
│   │   ├── deflate v1.0.0
│   │   │   └── adler32 v1.2.0
│   │   ├── flume v0.10.14
│   │   │   ├── futures-core v0.3.21
│   │   │   ├── futures-sink v0.3.21
│   │   │   ├── nanorand v0.7.0
│   │   │   │   └── getrandom v0.2.7
│   │   │   │       ├── cfg-if v1.0.0
│   │   │   │       └── libc v0.2.126
│   │   │   ├── pin-project v1.0.11
│   │   │   │   └── pin-project-internal v1.0.11 (proc-macro)
│   │   │   │       ├── proc-macro2 v1.0.42
│   │   │   │       │   └── unicode-ident v1.0.2
│   │   │   │       ├── quote v1.0.20
│   │   │   │       │   └── proc-macro2 v1.0.42 (*)
│   │   │   │       └── syn v1.0.98
│   │   │   │           ├── proc-macro2 v1.0.42 (*)
│   │   │   │           ├── quote v1.0.20 (*)
│   │   │   │           └── unicode-ident v1.0.2
│   │   │   └── spin v0.9.4
│   │   │       └── lock_api v0.4.6
│   │   │           └── scopeguard v1.1.0
│   │   ├── half v1.8.2
│   │   ├── inflate v0.4.5
│   │   │   └── adler32 v1.2.0
│   │   ├── lebe v0.5.1
│   │   ├── smallvec v1.9.0
│   │   └── threadpool v1.8.1
│   │       └── num_cpus v1.13.0
│   │           └── libc v0.2.126
│   ├── gif v0.11.4
│   │   ├── color_quant v1.1.0
│   │   └── weezl v0.1.7
│   ├── jpeg-decoder v0.2.6
│   │   └── rayon v1.5.1
│   │       ├── crossbeam-deque v0.8.0
│   │       │   ├── cfg-if v1.0.0
│   │       │   ├── crossbeam-epoch v0.9.5
│   │       │   │   ├── cfg-if v1.0.0
│   │       │   │   ├── crossbeam-utils v0.8.5
│   │       │   │   │   ├── cfg-if v1.0.0
│   │       │   │   │   └── lazy_static v1.4.0
│   │       │   │   ├── lazy_static v1.4.0
│   │       │   │   ├── memoffset v0.6.4
│   │       │   │   │   [build-dependencies]
│   │       │   │   │   └── autocfg v1.0.1
│   │       │   │   └── scopeguard v1.1.0
│   │       │   └── crossbeam-utils v0.8.5 (*)
│   │       ├── either v1.6.1
│   │       └── rayon-core v1.9.1
│   │           ├── crossbeam-channel v0.5.1
│   │           │   ├── cfg-if v1.0.0
│   │           │   └── crossbeam-utils v0.8.5 (*)
│   │           ├── crossbeam-deque v0.8.0 (*)
│   │           ├── crossbeam-utils v0.8.5 (*)
│   │           ├── lazy_static v1.4.0
│   │           └── num_cpus v1.13.0 (*)
│   │       [build-dependencies]
│   │       └── autocfg v1.0.1

I've opened an issue.

Use Newton's method to approximate the root

It seems Newton's method can be used to calculate the value we need for the lambda function. What I call "Za". It seems to be much faster.

https://math.stackexchange.com/a/4503144/1082376

I think that value is a root of the nth composition that is the computation of n iteration of z²+c.

This could be an alternative implementation. We could keep both for the record or just remove the old one if this is better.

Use RBG colors

We are using ColorType::L8. We could use RBG to apply other colours, but that would increase the size needed in memory to 3 bytes. And that would lower the maximum image size you can render with your computer because the full image is in memory before writing it into a file. In case you want a bigger image, you could always split it into parts.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.