Riemann zeta function: leveraging main bulb repetition to speed-up fractal rendering
In my previous post, I demonstrated how any fixed image of a certain size centred on the origin can be deformed and repeated in arbitrary regions of the complex plane by the action of the Riemann zeta function.
In practice, for each point, s, in the relevant region of the complex plane, ζ(s) is calculated. If the real and imaginary parts of ζ(s) are within the bounds of the area covered by the fixed image, the colour of the pixel at the {x,y} value {Re(ζ(s), Im( ζ(s))} can be used to colour the pixel at s.
If the fixed image is a high resolution image of the iteration fractal of the Riemann zeta function, we can avoid iterating every point, s, in the target region of the complex plane by using the fixed image as a "lookup table".
Here is the resultant plot for the region of the complex plane covering -2 Re(s) < 5 and 80 < Im(s) < 100 at a resolution of 100 pixels per unit. The image has been rotated clockwise by 90° such that the imaginary axis runs from left to right. The image is derived from a 5001 x 5001 pixel fixed image "lookup table" whose points, f, are in the following ranges: -25 < Re(f) < 25 and -25 Im(f) < 25, also at a resolution of 100 pixels per unit:
-2 < Re(s) < 5, -80 < Im(s) < 100, 100 pixels per unit
It is clear that, for values of s where Re(s) > 0, there is insufficient resolution in the lookup table to give decent resolution in the final image. In the positive real half plane, the value of ζ(s) tends to 1. On that basis, it makes sense to increase the resolution of the lookup table close to the pole of the Riemann zeta function at f = 1.
However, given that the resolution in the rest of the generated image is reasonable, there is no need to create a very large lookup table with a resolution of, say, 1000 pixels per unit. Instead, we can create a series of "nested" lookup tables of increasing resolution centred on the pole, and programmatically decide which to consult after the value of ζ(s) has been calculated.
Here is the resultant plot for same region of the complex plane as above, but derived from a series of four 5001 x 5001 pixel fixed image lookup tables whose points, f, are centred over the pole and which have resolutions of 100, 1000, 10000 and 100000 pixels per unit:
-2 < Re(s) < 5, -80 < Im(s) < 100, 100 pixels per unit
The resolution of the region where Re(s) > 0 is much improved.
Here are the fixed image lookup tables used to generate the above image. Note that they are all centred on the pole at f = 1:
-24.0 < Re(f) < 26.0, -25.0 < Im(f) < 25.0, 100 pixels per unit
-1.50 < Re(f) < 3.50, -2.50 < Im(f) < 2.50, 1000 pixels per unit
0.75 < Re(f) < 1.25, -0.25 < Im(f) < 0.25, 10000 pixels per unit
0.975 < Re(f) < 1.025, -0.025 < Im(f) < 0.025, 100000 pixels per unit
These tables are good for images where Re(s) < 16. Experiments suggest that a further fixed image lookup table with a resolution of 1000000 can extend the scope even further into the positive real half plane. However, I am typically interested in fractal images confined to the region where -2 < Re(s) < 5, so I tend to use only the above four fixed image lookup tables.
Another obvious limitation of using fixed image lookup tables to avoid formal iteration of each point, s, is that the values of ζ(s) where Re(s) < 0 are far too large to be accommodated by any reasonable lookup table. Pixels outside the bounds of the lowest resolution lookup table are therefore coloured black.
However, one aspect of these regions is that iteration is not very costly programmatically provided that appropriate bail-out limits are applied. The vast majority of points in this region blow-up on iteration, and they do so quickly.
Therefore, because only a few iterations are required for the majority of pixels outside the bounds of the lookup tables, it is a trivial matter to provide a function which enables the user to choose to formally iterate any pixel that falls outside the bounds of the lookup tables in order to "fill in" the black regions without too much impact on resolution time.
Here are some resultant images with and without fill in:
-2 < Re(s) < 5, 80 < Im(s) < 100, 100 pixels per unit, without fill-in
-2 < Re(s) < 5, 80 < Im(s) < 100, 100 pixels per unit, with fill-in
-2 < Re(s) < 5, 980 < Im(s) < 1000, 100 pixels per unit, without fill-in
-2 < Re(s) < 5, 980 < Im(s) < 1000, 100 pixels per unit, with fill-in
-2 < Re(s) < 5, 9980 < Im(s) < 10000, 100 pixels per unit, without fill-in
-2 < Re(s) < 5, 9980 < Im(s) < 10000, 100 pixels per unit, with fill-in
-2 < Re(s) < 5, 99980 < Im(s) < 100000, 100 pixels per unit, without fill-in
-2 < Re(s) < 5, 99980 < Im(s) < 100000, 100 pixels per unit, with fill-in
-2 < Re(s) < 5, 999980 < Im(s) < 1000000, 100 pixels per unit, without fill-in
-2 < Re(s) < 5, 999980 < Im(s) < 1000000, 100 pixels per unit, with fill-in
Using fixed image lookup tables leads to a reasonable speed up in rendering performance and good reproducibility. The resultant images are essentially indistinguishable from those generated by zeta_machine.
The rendering of images very high up the imaginary axis is still painfully slow, however, because for every point, s, ζ(s) must be calculated at least once, and the Euler Maclaurin summation requires a partial sum to be calculated with a number of terms in the order of |s|.













