(Question) (Perturbation) Images are always slightly incorrect

  • 7 Replies
  • 158 Views

0 Members and 1 Guest are viewing this topic.

Offline Iluso

  • *
  • Fractal Freshman
  • *
  • Posts: 5
« on: September 26, 2019, 09:46:39 PM »
Hello everyone,

I've been trying to implement Perturbation Theory (for the Mandelbrot Set) for a while now, but every time I write an implementation I get an incorrect image.

At first it seems correct, but the "antennas" are always slightly warped (CLICK on Image 1).
There is also the problem that parts of the set (the "circles" at the top and bottom of the "main" mandelbrot and minibrots) are missing (see Image 2).

Questions:
- Can anyone identify what my mistake is?
- This isn't a deep zoom (the "field of view" is 0.015), is that the issue?

Thanks!

Linkback: https://fractalforums.org/programming/11/perturbation-images-are-always-slightly-incorrect/3094/

Offline 3DickUlus

  • *
  • 3f
  • ******
  • Posts: 1403
    • Digilantism
« Reply #1 on: September 27, 2019, 05:12:06 AM »
offset from reference is out?
Fragmentarium is not a toy, it is a very versatile tool that can be used to make toys ;)

https://en.wikibooks.org/wiki/Fractals/fragmentarium

Offline Iluso

  • *
  • Fractal Freshman
  • *
  • Posts: 5
« Reply #2 on: September 27, 2019, 06:11:26 PM »
Thank you very much for answering! Unfortunately, I don't think there is anything wrong with the offsets.

Here is some pseudo-code of my program:
Code: [Select]
// where the ref. orbit is stored
complex X[]

// variables
complex z, c = <coordinates of the ref. point inside the image>

// calculate ref. orbit
for (i = 0; i < MAX_ITER; i++) {
    z = z * z + c;
    X[i] = z;
}

// loop over the points in the image
for (y = 0; y < HEIGHT; y++) {
    for (x = 0; x < WIDTH; x++) {
        complex yn = 0, y0 = <coordinates of the point>

        // deltas; d0 = the delta at iteration 0
        complex dn = 0, d0 = y0 - X[0];

        // i starts with i = 1
        for (i = 1; i < MAX_ITER; i++) {
            dn = 2 * dn * X[i] + dn * dn + d0

            // if the delta becomes too large
            if (abs(dn) > e^-5) {
                // calculate back to the coordinates of y at this iteration
                yn = dn + X[i + 1]
                // stop this loop
                break;
            }
        }

        // continue with the calculated yn and the normal mandelbrot equation
        for (; i < MAX_ITER; i++) {
            yn = yn * yn + y0;

            if (abs(yn) > 4) {
                // the point has escaped
                // <set color of pixel>

                // finish
                break;
            }
        }
    }
}

And this is the code of my actual program (in C++; it requires png++):
Code: [Select]
#include <math.h>
#include <stdlib.h>
#include <algorithm>
#include <chrono>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <png++/png.hpp>
#include <sstream>
#include <string>
#include <vector>
#include <complex>

int main(int argc, char **argv)
{
    // ======   BEGIN SETUP   ======
    // Define and calculate a few common variables
    double centerX = -1.2553763440860217, centerY = 0.38131720430107524, fov = 0.02;
    centerX -= 0.0016;
    double left = centerX - fov, right = centerX + fov, top = centerY + fov, bottom = centerY - fov;
    const int image_width = 1200, image_height = 1200;
    const int MAX_ITERATIONS = 900;
    png::image<png::rgb_pixel> image(image_width, image_height);
    double range_horizontal = std::abs(left - right), range_vertical = std::abs(top - bottom);
    double step_horizontal = range_horizontal / image_width, step_vertical = range_vertical / image_height;
    // ======   END SETUP   ======


    // ======   BEGIN CALCULATIONS   ======
    // Calulate the orbit of the reference point
    std::complex<double> X[MAX_ITERATIONS] = {0}; // initialise to zero
    std::complex<double> c, z = 0;

    // assign value to c
    c.real(centerX);
    c.imag(centerY);
    for (int i = 0; i < MAX_ITERATIONS; i++)
    {
        if (z.real() * z.real() + z.imag() * z.imag() > 4)
        {
            printf("ERROR: The reference escaped!\n");
            break;
        }
        z = z * z + c;
        // store copy in array
        X[i] = z;
    }

    // loop over all points in the image
    for (int x = 0; x < image_width; x++) {
        for (int y = 0; y < image_height; y++) {
            double coord_y = y * step_vertical + bottom,
                   coord_x = x * step_horizontal + left,
                   brightness = 0;

            std::complex<double> y0, d0, dn = 0, yn;
            y0.real(coord_x);
            y0.imag(coord_y);

            d0 = y0 - X[0];

            int i;
            for (i = 1; i < MAX_ITERATIONS; i++) {
                dn = 2.0 * dn * X[i] + dn * dn + d0;
                if (dn.real() * dn.real() + dn.imag() * dn.imag() > 1e-5) {
                    yn = dn + X[i + 1];
                    break;
                }
            }

            for (; i < MAX_ITERATIONS; i++) {
                yn = yn * yn + y0;
                if (yn.real() * yn.real() + yn.imag() * yn.imag() > 4) {
                    brightness = i;
                    break;
                }
            }
            // ======   END CALCULATIONS   ======

            brightness *= 4;
            double col_r = 0, col_g = 0.8, col_b = 1;
            if (brightness > 255)
                brightness = 255;
            image[image_height - 1 - y][x] = png::rgb_pixel((int)brightness * col_r, (int)brightness * col_g, (int)brightness * col_b);
        }
    }

    image.write("output.png");

    return 0;
}

Offline 3DickUlus

  • *
  • 3f
  • ******
  • Posts: 1403
    • Digilantism
« Reply #3 on: September 28, 2019, 02:16:39 AM »
yeah, that response was a guess...

add lines 22 and 23...
Code: [Select]
...
20    double centerX = -1.2553763440860217, centerY = 0.38131720430107524, fov = 0.02;
21
22    centerX += std::stof(argv[1]);
23    centerY += std::stof(argv[2]);
24
25    double left = centerX - fov, right = centerX + fov, top = centerY + fov, bottom = centerY - fov;
...
...in place of...
Code: [Select]
centerX -= 0.0016;...so I could move the reference a bit

compiled as...
Code: [Select]
g++ -std=c++11 -O3 -march=native IlusoMBperturb.c -lpng -Wall -Wextra -pedantic
run like...
Code: [Select]
./a.out -0.0017 -0.0006
maybe picking a different reference?  the one I found was just trial and error and may not be good either but it looks a bit closer  :-\

result...

Offline claude

  • *
  • 3f
  • ******
  • Posts: 1272
    • mathr.co.uk
« Reply #4 on: September 28, 2019, 10:52:12 AM »
this is the code of my actual program (in C++; it requires png++):
Code: [Select]
   for (int i = 0; i < MAX_ITERATIONS; i++)
        X[i] = z;
  ...
            for (i = 1; i < MAX_ITERATIONS; i++) {
                dn = 2.0 * dn * X[i] + dn * dn + d0;
off by one error?  or maybe off by two? I think X[0] should be 0+0i, if you are initializing dn=0+0i.  X[0] should be c if you are initializing dn=d0.  You have X[0] = c while initializing dn = 0, which is not correct. Second loop should start from i=0 in any case.

Offline Iluso

  • *
  • Fractal Freshman
  • *
  • Posts: 5
« Reply #5 on: September 28, 2019, 10:53:56 AM »
Thanks 3DickUlus,

it certainly does look better now, but its still far off in many places. Is that expected?
The third image is zoomed in a bit more and I just can't find a reference that produces an image that is even close to correct.

I thought with Perturbation Theory I could get the same result as the "real" calculation, but just a lot faster.

Do you know of a simple program that implements Perturbation, so I can look at the code?

Code for third image:
Code: [Select]
double centerX = -1.2539487462197367, centerY = 0.37686868909502685, fov = 0.000001220703125;

centerX -= 0.01 * fov;

Offline Iluso

  • *
  • Fractal Freshman
  • *
  • Posts: 5
« Reply #6 on: September 28, 2019, 11:16:11 AM »
Claude, you're wonderful.

Starting the second loop at i = 0 and setting Δn = Δ0 makes the picture look way better!
I'll do some more testing and will hopefully mark the thread [SOLVED] in the future.

I also want to take this opportunity to say Thank You. Without your posts (on old and new FractalForums and on StackExchange) I would not have been able to get this close.

Thanks you two! :)

Offline 3DickUlus

  • *
  • 3f
  • ******
  • Posts: 1403
    • Digilantism
« Reply #7 on: September 28, 2019, 08:37:39 PM »
with those changes moving the reference point (as long as it doesn't escape?) yields the same image,  :thumbs: @claude


xx
"Time Span"

Started by cricke49 on Fractal Image Gallery

0 Replies
355 Views
Last post August 02, 2018, 07:05:21 AM
by cricke49
clip
Minuscule source code for Lyapunov images (ASCII style)

Started by marcm200 on Programming

8 Replies
496 Views
Last post March 20, 2019, 07:37:58 PM
by marcm200
clip
Slightly altered MandelBox

Started by kosalos on Programming

0 Replies
302 Views
Last post October 03, 2018, 07:15:22 AM
by kosalos
xx
Slightly extended Newton method fractals

Started by gannjondal on Fractal Mathematics And New Theories

6 Replies
253 Views
Last post September 29, 2019, 10:18:01 PM
by gerrit
xx
Birdie Style

Started by gannjondal on Fractal Image Gallery

1 Replies
415 Views
Last post May 08, 2018, 02:39:37 PM
by who8mypnuts