Hypercomplex Math in Fractal Programming



Next

This is a tutorial on using hypercomplex math in fractal coding. The code examples I show will be C code from my own programs, just to illustrate the technique.

Hypercomplex numbers are four-dimensional in the form of h(4) = hr+hi+hj+hk. To begin with, we set up a basic structure for the variables we'll be using in hypercomplex math:

typedef struct hcomplex{
	double x;
	double y;
	double z;
	double w;
}hcomplex;

This contains the first two dimensions of a complex variable, x and y, which
refer to real and imaginary z, plus a couple more for the hypercomplex
"extensions."
      

The way hypercomplex math is done (using Fractal Creation's method), a sort of matrix math is used to combine the first two fields with the last two extension fields. A complex function is called twice with different combinations of the hypercomplex fields, and the separate complex return values are recombined into a single hypercomplex variable. The first call to a function uses the arguments (h.x-h.w,h.y+h.z). The second call uses (h.x+h.w,h.y-h.z).

For a hypercomplex cubing function, this looks like:

hcomplex cubeh(hcomplex *h)
{
	cmplex c,d;
	hcomplex r;

	c=cubez(h->x-h->w,h->y+h->z);
	d=cubez(h->x+h->w,h->y-h->z);
	r.x=(c.x+d.x)/2.0;
	r.y=(c.y+d.y)/2.0;
	r.z=(c.y-d.y)/2.0;
	r.w=(d.x-c.x)/2.0;
	return(r);
}


This is the "discrete" form of quad math that is useful to convert most formulas
that use common complex math functions.   A quad "library" would work here as well. But there are other formulas that may use no complex math functions per se, as in some IFS formulas, but you may want to convert them anyway to a hypercomplex model. That is where I use a more "general" method of conversion.  Let's say you have a formula that uses c and z as discrete elements, but calls no squaring or other complex functions.  Then you can't use the discrete form of hypercomplex math I've shown, at least not very easily. But you can set up another function to call that formula twice, varying the c and z components as I've shown above, then recombine the return values to form a hypercomplex equivalent.  An example of this (using
discrete variables instead of structures):

int snowflake(double x, double y);
int snowflake(double x, double y)
{
	if(y<0.0){
		r1=0.0;
		r2=-1.0;
		return(TRUE);
	}
	if(x<(-y/1.7320508+1.0)){
		r1=3.0*x;
		r2=3.0*y;
		return(TRUE);
	}
	if(x>=(-y/1.7320508+1.0) && x<1.5){
		r1=(9.0-3.0*x-5.1961524*y)/2.0;
		r2=(5.1961524-5.1961524*x+3.0)/2.0;
		return(TRUE);
	}
	if(x>=1.5 && x<(x/1.7320508+2.0)){
		r1=(3.0*x-5.1961524*y)/4.0;
		r2=(5.1961524*x+3.0*y-10.3923048)/4.0;
		return(TRUE);
	}
	r1=9.0-3.0*x;
	r2=3.0*y;
	return(TRUE);
}

int hype25() /* hypercomplex snowflake */
{
	double cx,cy,dx,dy;

	snowflake(a0-a3,a1+a2);
	cx=r1;	
	cy=r2;
	snowflake(a0+a3,a1-a2);
	dx=r1;
	dy=r2;
	a0=(cx+dx)/2.0;
	a1=(cy+dy)/2.0;
	a2=(cy-dy)/2.0;
	a3=(dx-cx)/2.0;
	magh();
	return(TRUE);
}

      

This example uses only complex z, but you could have a formula which used both z and c, and pass both sets of arguments to it, such as:  someformula (h.x-h.k, h.y+h.j, c.x-c.k, c.y+c.j);

Note the magh() function at the end of hype25().  This converts the hypercomplex variable into a complex modulus of z, for loop-bailout purposes.

Magh() looks like:

void magh()

{
	double temp;

	zr=a0;
	temp=a1*a1+a2*a2+a3*a3;
	if(temp <= DBL_MIN)
	zi = 0.0;
	else
	zi=sqrt(temp);
}

      

What I haven't shown is an example that uses the discrete form of hypercomplex math in an actual formula.  A simple example is:

hype0() /* h^2+c */

{

	hcomplex h;

	h.x=a0;

	h.y=a1;
	h.z=a2;
	h.w=a3;
	sqrh(&h);
	a0=r1+conr;
	a1=r2+coni;
	a2=r3+conj;
	a3=r4+conk;
	magh();
	return(TRUE);
}

Copyright 1989-2005 Mystic Fractal.   All rights reserved.   Reproduction in whole or in part in any form or medium without express written permission of Mystic Fractal is prohibited.   The name 'Mystic Fractal' and the Mystic Fractal logo are trademarks.