It's been a little bit tricky deciding how I was to approach this. "Begin at the beginning," they say, "and go on till you come to the end. Then stop." Which is all very well in most cases, but in this one - well, it had two beginnings and the end is nowhere in sight. I shall start with a salving of my conscience. Not too long ago I argued somewhat manically that, just as the classical Mandelbrot set serves as an index to the classical Julia sets, so too it could serve as an index into an uncountable infinity of other sets. And just as the two-dimensional Julias could be thought of as being stacked up in two dimensions to form a four-dimensional Julibrot (with the Mandelbrot set itself forming the binding), so too could these other sets be stacked up in however many dimensions might be deemed necessary - in which the binding itself can be pictured as being made up of stack of sets which has the original Mandelbrot set as binding. I gave some examples of _extensions_ to the Mandelbrot set, the quaternions and hypercomplex numbers, some other four-dimensional numbers I'd made up on the spot, and some further extensions to the quaternions (specifically, octonions, decanions, and pentadecanions). But to be honest, none of these were actually presented as being extensions of the Julibrot set in any way - the four-dimensional quaternion Julia sets are not the four-dimensional Julibrot. Of course, the quaternion Julias themselves have a quaternion Mandelbrot, and the two combine to produce an eight-dimensional quaternion Julibrot - in the heart of which the classical Mandelbrot is still to be found. But really there was more handwaving going on than I was really comfortable with. So I decided to actually construct a beast that (a) gave the classical Mandelbrot set an explicit role as an index into the associated Julias, and (b) strongly suggested how other different beasts could be constructed in the same way - makng it obvious that at least a countable infinity of others could be constructed. Where the classical Julibrot has four dimensions - two to index the Julia sets' parameters (these being the two the Mandelbrot set lives in) and two to carry the Julias themselves - the "Quarterblend" (to use the name I just made up for it) Julibrot has ten. The Julia sets are still two-dimensional, but it takes four complex parameters to specify them - so the corresponding Mandelbrot set lives in eight dimensions. The thing is, the eight-dimensional Mandelbrot can itself be looked upon as a Julibrot - with two-dimensional Julias being indexed by a six-dimensional Mandelbrot. This reduction can continue, so that six dimensions split into two and four, with the four- dimensional index set resulting being none other than our familiar classical Julibrot, with two-dimensional Julias being indexed by a two-dimensional Mandelbrot. In a sense this sort of thing can happen anyway when you have a load of independent parameters: with n independent parameters, if you fix all but m you specify an m-dimensional Julia, the set of which is indexed by an (n-m)-dimensional Mandelbrot; and hence an n-dimensional Julibrot. But I wanted to show one where the classical Mandelbrot set could be easily found. As I said, the Quarterblend Julibrot is ten-dimensional. Since the Julia sets I'm drawing are two-dimensional, that means I have to fix eight dimensions. The obvious way to do that is to have four complex parameters. Without any further ado, here's the formula for Quarterblend Julias. quarterblend_pJJJJ{ z=pixel if(imag(pixel)>0) if(real(pixel)<0) c=p1 else c=p2 endif else if(real(pixel)>0) c=p3 else c=p4 endif endif : z=sqr(z)+c |z|<=4} It's simple enough that it's operation should be apparent even without playing with the thing. Now we want to index this. In the same way that Julia sets get indexed by the Mandelbrot: Julia { z = pixel, c = p1: z = sqr(z) + c, |z| <= 4 } Mandelbrot { z = pixel, c = pixel: z = sqr(z) + c, |z| <= 4 } The only difference (apart from the name) is that where in the Julia the parameter is specified and fixed by the user, in the Mandelbrot it's become "pixel": each distinct point in the Mandelbrot corresponds to a distinct Julia set. The formula for the Mandelbrot set isn't entirely truthful: to save one iteration per pixel, the first iteration has actually be done by hand. It should really read: Mandelbrot { z = 0, c = pixel: z = sqr(z) + c, |z| <= 4 } Where 0 is a critical point of the quadratic map z^2+c. Note that after one iteration through the formula, z becomes equal to pixel and the situation matches the earlier version of the Mandelbrot formula. I mention this bit about truth because I'd like you to compare the initialisers of the Julia and "real" Mandelbrot formulae: z = pixel, c = p1: z = 0, c = pixel: Each pixel P of the Mandelbrot set is initialised to z=0, c=P. And the point 0 of the Julia set with parameter c=P is initialised to z=0, c=P. In other words, these two points (one in the Mandelbrot, one in the Julia) have the same initial conditions, and follow identical dynamical rules. Each point of the Mandelbrot set is the zero point of a Julia set, and vice versa. This is what is meant by the Mandelbrot set "indexing" the Julia set, and is the basis of the Julibrot; with two-dimensional Julia sets lying at right angles to the two-dimensional Mandelbrot set, all intersecting it at single points; the whole shebang yielding the four-dimensional Julibrot. So now we can index the quarterblend_pJJJJ formula. There are a variety of ways to do this, some more extreme than others. You might want to build an index in the p1 plane (the plane in which p1 takes all possible values). This would give quarterblend_pMJJJ{ z=pixel if(imag(pixel)>0) if(real(pixel)<0) c=pixel else c=p2 endif else if(real(pixel)>0) c=p3 else c=p4 endif endif : z=sqr(z)+c |z|<=4} or instead index p1 and p3 simultaneously: quarterblend_pMJMJ{ z=pixel if(imag(pixel)>0) if(real(pixel)<0) c=pixel else c=p2 endif else if(real(pixel)>0) c=pixel else c=p4 endif endif : z=sqr(z)+c |z|<=4} Both of these could be called "Mandelbrot" sets, in which a quantity is allowed to vary that could instead be fixed at a particular value to produce corresponding Julia sets. But equally, they could still perhaps be called "Julia" sets, because they do still contain arbitrary parameters. Let's index all of those parameters now: quarterblend_pMMMM{ z=pixel if(imag(pixel)>0) if(real(pixel)<0) c=pixel else c=pixel endif else if(real(pixel)>0) c=pixel else c=pixel endif endif : z=sqr(z)+c |z|<=4} And do some obvious simplifications of the if-else-endif logic: quarterblend_pMMMM{ z=pixel c=pixel : z=sqr(z)+c |z|<=4} Now that looks familiar. The Quarterblend Julibrot is a ten-dimensional structure. An eight-dimensional stack of two-dimensional Julias. The stack is itself a six-dimensional stack of two-dimensional Julias. That stack in turn is a four-dimensional stack of two-dimensional Julias. And _that_ stack is our familiar Julibrot - a two- dimensional stack of two-dimensional Julias. All of the Julias in that last step intersecting with a single plane at their critical points to produce a two-dimensional Mandelbrot - index page for the two-dimensional stack. So yes, it does look patchy, being cut into regions like that, but all the bits all still hang together in one single consistent ten-dimensional shape. And there you have it. Just one of what is (what should be) clearly an (at least countable) infinity of different formulae that all have the classical Mandelbrot set serving to index its Julia sets; just altering the placement of the regime boundaries (real(pixel)<0, etc.), or adding more would be sufficient. Actually, with a little thought it's clear that the different formulae are uncountable in number; the boundaries between the different regions could placed in uncountably many different ways (just nudging one ever so slightly would be enough). Now I can start on the other beginning. I was mulling the difference between the Mandelbrot set and Julia sets, and one of the distinctions I saw concerned memory. Now, I don't say that this is any sort of defining characteristic between them, but it is a difference between them, that can be applied elsewhere. Consider the idea of a dynamical system. We have a space, S, for the sake of argument, and a so-called "vector field", that attaches, to every point of S, a wee arrow which is taken to mean "go this way next". We insert a particle into S at a particular point and then watch what happens, as it moves from point to point, following the arrows. For escape-time fractals such as those rendered by Fractint's formula type, we do this for virtually every point visible in the space, colouring that point according to what happens to a particle starting from that point "in the end" (where "in the end" is defined in terms of bailout condition and maximum iterations). Other Fractint types offer other views of dynamical systems. But this can't really be the entire story. The Mandelbrot set itself looks like its breaking the rule. Mandelbrot { z = 0, c = pixel: z = sqr(z) + c, |z| <= 4 } Let's say you've come across a freeze-frame of a Mandelbrot set in progress. There is a particle sitting at a particular point. The question is: where is it going to go next? Where is the little arrow pointing? The answers are: You can't tell. The arrow isn't defined. It's not? No, because that particle could have started out from a number of different points. Where it goes next depends on c, which is defined to be the point from where the particle originally started from. If you don't know that, you don't know c, and you can't work out sqr(z)+c. This is what I meant by "memory" - the particle remembers where it came from, and this memory affects where it will go, in a fashion not catered for by a simple dynamical system. Julia sets are simple dynamical systems in this case. If we were in the situation of trying to predict where a particle will go next, we will be able to. It still obeys z=sqr(z)+c, but this time we know what c is - it's the Julia set parameter. The particle itself has no need to remember it, because it's already built into the little arrows we're again free to place at every point. In a sense, every single point of the Mandelbrot set represents a different dynamical system - one for each value of c. But this is just another way of saying that the Mandelbrot set indexes the Julia sets - by sampling all of the different dynamical systems and providing a summary. Now the two plot lines I've been developing here can merge. The Kleinian Circle formulas don't have such a memory: The only per-pixel initialisation is the last "z=pixel" for specifying where the particle was to start. After that, the rest was predetermined - you could set up the vector field and all its wee arrows in advance, and every particle arriving at a particular point would all behave the same way, all following the same wee arrow telling them where to go next. (This was why my "precalc" hack could work.) In contrast, my Quarterblend fractal (even the JJJJ julias) does have a memory. Each particle remembers which region (upper/lower left/right) it started out in. Without knowing that about a particle, you wouldn't be able to predict where it was going next. Something had to be done. At least, it suggested something that could be done. So I lobotomised the particles that were supposed to be following the Quarterblend dynamics. No longer could they remember which region they started from; instead they were to just use whatever rule applied in whatever region they happend to be in at the time. The example Quarterblend slices I gave above became: quarterblend_iJJJJ{ z=pixel: if(imag(z)>0) if(real(z)<0) c=p1 else c=p2 endif else if(real(z)>0) c=p3 else c=p4 endif endif z=sqr(z)+c |z|<=4} quarterblend_iMJJJ{ z=pixel: if(imag(z)>0) if(real(z)<0) c=pixel else c=p2 endif else if(real(z)>0) c=p3 else c=p4 endif endif z=sqr(z)+c |z|<=4} quarterblend_iMJMJ{ z=pixel: if(imag(z)>0) if(real(z)<0) c=pixel else c=p2 endif else if(real(z)>0) c=pixel else c=p4 endif endif z=sqr(z)+c |z|<=4} and quarterblend_iMMMM{ z=pixel: c=pixel z=sqr(z)+c |z|<=4} Again, that last one looks familiar. (And now you know what that extra 'p' was for!) All the talk about the quarterblend_p???? fractal applies to this one as well, so the extensions suggested there can all be carried in bulk to this one as well. This one has the advantage that its ten-dimensional space can be filled up with the wee arrows of a vector field in advance and looked at as a pure dynamical system, without giving mere particles anything so pretentious as a memory. Plus the pictures look a bit better. Morgan L. Owens "Pass the dried frog pills."