# mathr

## Collatz fractal

The Collatz conjecture involves a piecewise integer recurrence:

$c(n) = \left\{ \begin{array}{ll} n/2 & n\text{ even} \\ 3n+1 & n\text{ odd} \end{array} \right.$

The unsolved conjecture is that iterating $$c$$ starting with a positive integer will always reach $$1$$.

The integer function $$c$$ can be extended to real and complex numbers like this:

$c(z) = \frac{1}{4}(1 + 4z - (1 + 2z)\cos(\pi z))$

and iterating this function for each pixel of an image gives an escape time fractal with escape condition $$|\Im(z)| \to \infty$$. I implemented this in Fragmentarium, also calculating the running derivative for distance estimate colouring:

#include "Progressive2D.frag"

float pi = 3.141592653;

// hyperbolic cosine
float cosh(float x) {
return (exp(x) + exp(-x))/2.0;
}

// hyperbolic sine
float sinh(float x) {
return (exp(x) - exp(-x))/2.0;
}

// complex multiplication
vec2 cmul(vec2 a, vec2 b) {
return vec2(a.x * b.x - a.y * b.y, a.x * b.y + a.y * b.x);
}

// complex cosine
vec2 ccos(vec2 a) {
return vec2(cos(a.x) * cosh(a.y), -sin(a.x) * sinh(a.y));
}

// complex sine
vec2 csin(vec2 a) {
return vec2(sin(a.x) * cosh(a.y), cos(a.x) * sinh(a.y));
}

vec3 color(vec2 z0) {
// initialize
vec2 z = z0;
vec2 dz = vec2(1.0, 0.0);
int n = 0;
// iterate
for (int i = 1; i < 2048; ++i) {
// bail out if z gets too big
if (abs(z.y) > 4.0) {
n = i;
break;
}
// do one step of generalized Collatz function
dz = cmul(dz, (vec2(4.0,0.0)
- cmul(vec2(1.0, 0.0) + 2.0 * z, pi * -csin(pi * z))
- 2.0 * ccos(pi * z)) / 4.0);
z = (vec2(1.0,0.0) + 4.0 * z
- cmul(vec2(1.0,0.0) + 2.0 * z, ccos(pi * z))) / 4.0;
}
// colour pixel according to distance estimate
float de = length(z) * log(length(z)) / length(dz);
if (n == 0) { return vec3(1.0, 0.7, 0.0); }
return vec3(tanh(clamp(de / length(dFdx(z0)), 0.0, 4.0)));
}