|Presented below is the grammar on informal terms. If you'd like bnf or something more formal than have a look at the file expr_parser.y in the distribution|
There are two important concepts to keep in mind when reading the grammar description below.
The first is the notion of iteration. What we are really doing is defining a sequence of points. To understand this we can look at the complex case. What we have is a function, f(z) and an initial value for the sequence, say z0. We can then generate each new point in the sequence by the rule zn+1 = f(zn).
The second idea is that of context. Operators do different things based upon their context, given by the type of their arguements. Libquat distinguishes between three contexts: quaternion, complex, and scalar. That is, every expression that it recgonizes evaluates to one of these three types of values. There is the added restriction that quaternion and complex contexts may not coexist.
Given these two ideas, we are ready to discuss the heart of the issue, which are the two expressions that define our sequence of points. The most important expression is the function f. f is a function of either q or z, and can be built from any of the symbols listed below. There is also the expression for the initial iterate of the sequence, z0. This expression can be built in the same manner as f, but it is not a function of either q or z. For a given point it should always evaulate to a constant value.
|q||A quaternion variable. 'q' implies a quaternion context. q is implicitly qn in the relation qn+1 = f(qn)|
|q_(n-4)||Another quaternion variable, in this case qn-4. Previous iterates can be referenced as far back in the sequence as desired. They are defined to be 0 if the subscript evaluates to less than 0. Note that when using the previous iterate the shown on the left, f changes from f(qn) to f(qn,qn-4).|
|z||A complex variable. 'z' implies a complex context. That is the only difference between z and q.|
|z_(n-4)||A complex previous iterate. All the same rules apply as for the quaternion ones.|
|[1 0 3.5 0]||A literal quaternion. The values specified are the coefficients of the unit vectors in each direction (1, i, j, k)|
|c||A constant variable. At the beginning of the iteration of each point 'c' is replaced with the coordinates of the point being iterated. This allows for maps such as z^2+c. 'c' can imply either a quaternion or a complex context, depending upon whether f is a function of q or z.|
|[0 2]||A literal complex number. This one is 2*i.|
|4.5||A literal scalar.|
|i j k||Imaginary unit vectors. Here i is the familiar square root of -1. j and k are quaternion unit vectors, also roots of -1. i, j, and k are not equal because they are all mutually perpendicular. j and k imply a quaternion context, i can imply either depending upon the context.|
|e pi||Everyone's favorite irrational numbers, e and pi.|
|+||The plus operator is defined for all contexts as pairwise addition of elements.|
|-||The minus operator is similarly defined for all contexts as pairwise subtraction.|
|*||Multiplication is tricky. It can do one of many different things depending upon the context. When both arguments are scalars, it is the traditional scalar product. When one is a scalar and the other is not, each element of the complex or quaternion number gets multiplied by the scalar separately. Complex multiplication is defined as (x1+i*y1)*(x2+i*y2). Quaternion multiplication can similiarly be defined as (s1+i*a1+j*b1+k*c1)*(s2+i*a2+j*b2+k*c2). Yes, this is messy, and even better, it is not commutitive, so for two arbitrary quaternions q1 and q2, q1*q2 does not necessarily equal q2*q1.|
|/||Division is messy as well. It is defined in an analgous fashion to multiplication when there is a scalar involved, except when dividing by a non scalar. For quaternion and complex division, we define it as x1/x2 = x1*x2-1 = x1*conj(x2)/|x2|2, where conj gives the conjugate of the number and |x| is the magnitude. Division of a scalar by a quaternion or a complex number is a special case of the above.|
|^||Exponentiation is not defined for all cases. Scalar exponentiation is implemented with the pow() function. Complex and quaternion exponentiation is currently only implemented for integer exponents > 0. Real exponents are feasable for complex numbers, but I haven't worked out the math for quaternions to real powers yet. Scalars may be raised to any power however, using a generalization of Euler's forumula. So it is possible to write ei*pi as e^(i*pi).|
||z|||Vertical bars indicate the magnitude of the argument. For scalars this is simply the absolute value, for complex numbers and quaternions it is the square root of the sum of the coefficients squared.|
|re and im return the real and imaginary parts of a complex number (or quaternion for that matter) as a scalar.|
|These operators return the coefficients of the i, j, and k components of a quaternion, respectively. im_i and im are identical. And just in case you were wondering, re works on quaternions as well.|
|The trig functions are only implemented for scalars and complex numbers, as I have been told that it is not possible to take the sine of a quaternion :(. None of the inverse (arc) functions are implemented either.|