Finding Periodic/Fixed Points in the Julia Sets close to the Period-3 Cardioid

complex numberscomplex-dynamicsfixed points-fractalsrecreational-mathematics

The first image below shows the Julia Set at $-1.749512 + 0i$ (close to the base of the Period-3 Cardioid), and I'd like to find the periodic point located at where the white arrow is pointing at. However, this is my first exposure to Julia Sets beyond the Period-1 Cardioid and the Period-2 Main Disk of the Mandelbrot, and my methods of calculating periodic points don't seem to work here.

Working off my question here, I concluded that I needed to use $\frac{1 – \sqrt{1 – 4c}}{2}$ to find the desired point – and this worked as intended for all Julia Sets close to the Period-1 and 2 components of the Mandelbrot. Applying that to this Julia Set, however, centers at the white arrow in the second image (I understand why this is, but I don't know how to work around it).

I also tried using the following formula for finding pre-images of periodic points (which I learned from this question), but the found point never falls on the center, regardless of the combination of pluses and minuses I use…

$$z_{-1}^*(t)=\pm\sqrt{z_0^*(t)-c(t)}=\pm\sqrt{\frac{1\mp\sqrt{1-4c(t)}}{2}-c(t)}$$

enter image description here

enter image description here

Edit:

Thanks to Mark in the comments, I figured it might be beneficial if I just show what I'm looking for – given that I don't quite know which terms to use (although I'm pretty confident I'm looking for fixed points, based off of this question). Here are some videos showing the intended effect on the main cardioid and disk of the Mandelbrot Set (using the algebraic solutions to $z_{p+1}=z_p^2+c$), and what I'd like to replicate with the period-3 cardioid:

Main Cardioid ($z_0=\frac{1 – \sqrt{1 – 4c}}{2}$ – THIS is what I'd like to replicate with the Period-3 Cardioid): https://youtu.be/C22P6ScEU1I

Main Disk ($z_0=\frac{1 – \sqrt{1 – 4c}}{2}$ – NOT what I'm looking for): https://youtu.be/MUuuf8K4SiQ

Main Disk ($z_1=\frac{-1 – \sqrt{-3 – 4c}}{2}$): https://youtu.be/3RuNjWLHuWA

Period-3 Cardioid (THIS is the video I'd like to apply the previous effect on): https://youtu.be/G1tkBMshd2k

Judging by the trend in the videos, I'd like to think that finding the algebraic solution to $z_{p+1}=z_p^2+c$ when $p=2$ would get me the points I'm looking for, but given that Wolfram Alpha has trouble with this (or I'm just not understanding how I can use the answer), I'm unsure of how to get a solution I can work with:

https://www.wolframalpha.com/input/?i=solve+for+z%3A+%28%28%28%28%28%28z%5E2%29+%2B+c%29%5E2%29+%2B+c%29%5E2%29+-+z+%2B+c%29

Best Answer

For the promenade around the main cardioid, the point in the Julia set you want is a fixed point $z = f_c(z)$. By tuning (renormalization), the point you want in the "little Julia set" at the center of the Julia set is a periodic point $z = f_c^p(z)$, in this particular case $p = 3$. You can use Newton's method to find the root numerically, the degree is too high for symbolic solution via radicals. You need a good initial guess for Newton's method to converge to the "correct" tuned fixed point (periodic point), as there is another one at the "tip" of the little Julia set (just as there two fixed points for $z = f_c(z)$), and moreover the fixed points $z = f_c(z)$ are also (unwanted) solutions for $z = f_c^p(z)$.

Here is a small C99 program using my mandelbrot-numerics library:

/*
gcc julia-spiral-center.c `PKG_CONFIG_PATH=${HOME}/opt/lib/pkgconfig pkg-config --cflags --libs mandelbrot-numerics` -lm -fopenmp -O3 -std=c99 -Wall -Wextra -pedantic
LD_LIBRARY_PATH=${HOME}/opt/lib/ ./a.out |
ffmpeg -framerate 25 -i - -pix_fmt yuv420p -profile:v high -level:v 4.1 -crf:v 20 -movflags +faststart julia-spiral-center.mp4 -y
*/

#include <complex.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>

#ifndef M_PI
#define M_PI 3.141592653589793
#endif

// git clone https://code.mathr.co.uk/mandelbrot-numerics.git
// make -C mandelbrot-numerics/c/lib prefix=${HOME}/opt install
#include <mandelbrot-numerics.h>

double cnorm(double _Complex z)
{
  double x = creal(z);
  double y = cimag(z);
  return x * x + y * y;
}

int main(int argc, char **argv)
{
  // silence -Wunused-parameter
  (void) argc;
  (void) argv;
  // number of animation frames
  const int frames = 25 * 30 * 1;
  // parameters for Julia set graphics rendering
  const int iterations = 1024;
  const double escape_radius_squared = 1 << 24;
  const int width = 640;
  const int height = 360;
  unsigned char *pgm = malloc(width * height);
  // how far from the target component to place the moving c
  // 1.0 is the boundary of the component
  const double radius = 1.25;
  // period of the target component
  const int period = 3;
  // these don't need to be exact, they will be changed by m_d_interior()
  double _Complex z = 0;
  double _Complex c = -1.754;
  // maximum number of steps of Newton's method
  const int steps = 64;
  // needs a good initial guess to converge to the correct attractor
  double _Complex w = -0.1 - 0.01 * I;
  for (int frame = 0; frame < frames; ++frame)
  {
    // path around the exterior of the component
    double t = (frame + 0.5) / frames;
    double _Complex q = radius * cexp(2 * M_PI * I * t);
    // find c,z such that f_c^p(z) = z and d/dz f_c^p(z) = q
    m_d_interior(&z, &c, z, c, q, period, steps);
    // find w such that f_c^p(w) = w
    // use previous frame's w as initial guess for continuity
    m_d_attractor(&w, w, c, period, steps);
    // scaling for view
    double r = cabs(w);
    // render Julia set
    #pragma omp parallel for
    for (int j = 0; j < height; ++j)
    {
      for (int i = 0; i < width; ++i)
      {
        // view centered on w
        double _Complex z0 =
          ( ((i + 0.5) / width - 0.5) * 2 * width / height
            - I * ((j + 0.5) / height - 0.5) * 2 ) * r + w;
        // initialize derivative with pixel spacing
        double _Complex dz = 2 * r / height;
        // unescaped pixels will be grey
        pgm[j * width + i] = 128;
        for (int k = 0; k < iterations; ++k)
        {
          dz = 2 * z0 * dz;
          z0 = z0 * z0 + c;
          if (cnorm(z0) > escape_radius_squared)
          {
            // compute exterior distance estimate
            double de = 2 * cabs(z0) * log(cabs(z0)) / cabs(dz);
            // colour boundary based on distance estimate
            pgm[j * width + i] = 255 * tanh(de);
            break;
          }
        }
      }
    }
    // output PGM stream to stdout
    fprintf(stdout, "P5\n%d %d\n255\n", width, height);
    fwrite(pgm, width * height, 1, stdout);
    fflush(stdout);
  }
  // cleanup
  free(pgm);
  return 0;
}

The source code for the two functions I used from the library can be browsed at:

They are both applications of Newton's root finding method, in 2 complex variables and 1 complex variables respectively.

You can view the video rendered by this program.

Related Question