# Multibrot

Generalisation of Mandelbrot set to arbitrary power NN.

fc(z)=zN+cf_c(z) = z^N + c

Here only integer N2N \ge 2 are considered.

# 1 Critical Point

fc(z)=NzN1=0f_c'(z) = N z^{N-1} = 0

has the solution

z0=0z_0 = 0

which is where iteration should start from to determine the number of components that the filled-in Julia set has (1 if it remains bounded, infinitely many if it escapes to infinity).

# 2 Escape To Infinity

Suppose |zn|>Rmax(|c|,1)|z_n| > R \ge \max(|c|, 1) If that implies |zn+1|>(1+ϵ)R|z_{n+1}| > (1 + \epsilon) R with some ϵ>0\epsilon > 0, then |zn+m|>(1+ϵ)mR|z_{n + m}| > (1 + \epsilon)^m R \to \infty as mm \to \infty.

Calculating, |zn+1|=|znN+c|>||znN||c||=|znN||c|>RN|c|RNR=(RN11)R\begin{aligned} |z_{n+1}| &= |z_n^N+c| \\ &> \left||z_n^N| - |c|\right| \\ &= |z_n^N| - |c| \\ &> R^N - |c| \\ &\ge R^N - R \\ &= (R^{N-1} - 1) R \end{aligned}

Therefore, setting 1+ϵ=RN111 + \epsilon = R^{N-1} - 1 gives R=2+ϵN1.R = \sqrt[N-1]{2 + \epsilon}. ϵ\epsilon is arbitrarily small, so this gives bounds: R>2N1|c|R > \sqrt[N-1]{2} \ge |c|

That is, |zn|>2N1|z_n| > \sqrt[N-1]{2} will escape to infinity, and the whole set is contained in the ball of radius 2N1\sqrt[N-1]{2} centered on the origin.

# 3 Boundedness

See:

“Cross-sections of multibrot sets”, Line Baribeau, Thomas Ransford https://arxiv.org/abs/1701.05535

Relevant result:

If |c|(N1)/NN/(N1)|c| \le (N-1)/N^{N/(N-1)} then |zn|1/N1/(N1)|z_n| \le 1/N^{1/(N-1)}, that is, znz_n remains bounded.

# 4 Fast Exponentiation

Simply multiplying by zz NN times is inefficient. Much better is exponentiation by squaring:

z2N+1=z2N×zz2N=(zN)2\begin{aligned} z^{2 N + 1} &= z^{2 N} \times z \\ z^{2 N} &= \left(z^N\right)^2 \end{aligned}

This takes O(log(N))O(\log(N)) operations instead of O(N)O(N), which is a big improvement.

The recursive description gives the operations in the reverse order to which they need to be performed.

The execution opcodes can be captured in a table, or in unrolled inner loops of generated code. The opcodes for one iteration of zzN+cz \to z^N + c are ×z\cdot \times z, 2\cdot^2, and +c\cdot + c.

# 5 Perturbation

Perturbing zN+cz^N+c gives an expression with O(N)O(N) terms: ((Z+z)N+(C+c))(ZN+C)=c+k=1N(Nk)ZNkzk((Z+z)^N+(C+c)) - (Z^N+C) = c + \sum_{k=1}^N \begin{pmatrix} N \\ k \end{pmatrix} Z^{N-k} z^k This is inefficient in terms of number of operations.

Images also can have glitches if care is not taken: the glitch test is no longer |Z+z|<|z||Z+z| < |z| but needs to be more like |Z+z|<N|z||Z+z| < N |z| (to be verified).

For greater efficiency and robustness, combine with fast exponentiation: store the reference ZZ before opcode step, that is, store O(log(N))O(\log(N)) values per iteration.

Then check and rebase pixel iterations using Zhuoran’s trick before each opcode step: whenever |Z+z|<|z||Z+z|<|z|, set z=Z+zz=Z+z and Z=0Z=0 (the latter by resetting the iteration index into the reference orbit; don’t reset the reference’s step index).

This works so easily because 0 is the only critical point, and 0=02=z×00 = 0^2 = z \times 0 so the initial portion of the reference orbit is a sequence of 00 steps in the first iteration until the first cc at the start of the second iteration. For non-zero or multiple critical points it would be more complicated.

# 6 Implementation

Example implementation:

git clone https://code.mathr.co.uk/fractal-bits.git
cd fractal-bits/mandelbrot-arbitrary-power
make
./znc >100.pgm
display 100.pgm

Browse source: znc.c.