# Quaternions Missing Important Functionality?

I use quaternions and Clifford algebras frequently for solving PDE boundary value problems as well as things like reflections, rotations etc. The underlying field for my quaternions is almost always either the complex numbers or the symbolic ring.

I am making an attempt to use them in Sage but I've run into a couple of obstacles that have given me pause. The absolute first things I looked for were,

1) scalar part or real part of the quaternion. Where is this function? I stumbled upon turning it into a list or vector but I presume that just taking the scalar part would be more efficient than dumping all the coefficients. For matrix representations it's often just the trace of the matrix. Correspondingly obtaining the vector part should be a standard function as well.

2) Quaternion automorphisms and anti-automorphisms? where are they? Yes we have conjugate which is both a method and an external function but what about the reversion and involution and the many other automorphisms? I don't expect to have to multiply by a bunch of unit vectors to get them for efficiency reasons. Also how do I distinguish between the quaternion conjugate and the complex conjugate of each of it's elements? This is a very important distinction that I would not know how to do without stripping out it's components and then remapping it.

3) Constructing a quaternion from coefficients. The only examples I've seen require explicit multiplications like q = q0 + q1 * i + q2 * j + q3 * k . That doesn't seem efficient.

4) quaternions as elements of enclosing matrices and vectors. This would be very helpful since you could generate any Clifford algebra with this and it's often easier to analyze the components of said algebra that are isomorphic to Quaternions or Biquaternions in the complex case. Moreover I need to be able to do this for quaternions over the symbolic ring. It fails for me as this example from sage 7.3 shows:


Q.<e1,e2,e3> = QuaternionAlgebra(SR, -1,-1)
var('x y z', domain='real')
q1 = x + x * I * e1
q2 = x - x * I * e1
v = vector([q1,q2])

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "_sage_input_36.py", line 10, in <module>
exec compile(u'open("___code___.py","w").write("# -*- coding: utf-8 -*-\\n" +     _support_.preparse_worksheet_cell(base64.b64decode("US48ZTEsZTIsZTM+ID0gUXVhdGVybmlvbkFsZ2VicmEoU1IsIC0xLC0xKQp2YXIoJ3ggeSB6JywgZG9tYWluPSdyZWFsJykKcTEgPSB4ICsgeCAqIEkgKiBlMQpxMiA9IHggLSB4ICogSSAqIGUxCnYgPSB2ZWN0b3IoW3ExLHEyXSk="),globals())+"\\n"); execfile(os.path.abspath("___code___.py"))
File "", line 1, in <module>

File "/tmp/tmpQ0ibdW/___code___.py", line 7, in <module>
exec compile(u'v = vector([q1,q2])  File "", line 1, in <module>

File "sage/modules/free_module_element.pyx", line 510, in sage.modules.free_module_element.vector (/data/AppData/SageMath/src/build/cythonized/sage/modules/free_module_element.c:5811)
TypeError: unsupported operand type(s) for ** or pow(): 'QuaternionAlgebra_ab' and 'int'


5) quaternion rotations. Most libraries will generate the unit quaternion that rotates in 3D space and/or have a function that applies it efficiently.

There are probably a few other things like generating a canonical matrix ...

edit retag close merge delete

I just want to say this is a really great and well-thought-out question, and I hope someone answers it soon. My guess is that at least some of this really would need new tickets; quaternion stuff in Sage I think is more there for algebraists than e.g. graphics.

( 2016-08-26 06:40:36 -0500 )edit

Sort by » oldest newest most voted

I agree that many quarternion functionalities are missing. Here is simply the answer to the point 3) you have raised: a quaternion can be constructed directly from its coefficients by means of SageMath's standard element instanciation from the parent, i.e. H(...) where H is the quaternion algebra:

sage: H.<i,j,k> = QuaternionAlgebra(SR, -1, -1)
sage: var("t x y z", domain='real')
(t, x, y, z)
sage: q = H((t, x, y, z)); q
t + x*i + y*j + z*k
sage: q.conjugate()
t + (-x)*i + (-y)*j + (-z)*k
sage: q2 = H((2, 0, -3*x^2, 4)); q2
2 + (-3*x^2)*j + 4*k
sage: q2.conjugate()
2 + 3*x^2*j + (-4)*k


The reverse operation is provided by the method coefficient_tuple:

sage: q.coefficient_tuple()
(t, x, y, z)
sage: q2.coefficient_tuple()
(2, 0, -3*x^2, 4)

more

After hacking away at this for a day or so, I can start answering some of my own questions. One reason why I didn't have answers right away is due to the fact that the automatically generated documentation for the quaternions does not cover the methods in the parent class nor does it cover several external functions that still work against the quaternion object.

The other problem is that I am not an algebraist. So for example the fact that the scalar part is actually half the reduced trace was not readily obvious. So here is my take so far on my "issues".

1) Let q be an instance of a quaternion. q.reduced_trace()/2 is the scalar part. But even better is the undocumented fact that the [] operator has been overloaded so that you can simply do q[0]. That latter is a nice feature. Once you have that generating the "vector part" is easy enough.

2) Another undocumented feature is the .C method for matrices and the .conjugate() method which appears to exist for both quaternions and matrices. However it only gives you the quaternion conjugation not the elementwise complex conjugation. The latter has to be added by the programmer as far as I can tell.

As for the other automorphisms like involution and reversion, they would have to be implemented by the programmer as far as I can tell. I suspect the same might be true for the more general Clifford algebras, but I'm not certain.

3) I'm stuck with this for now. Maybe there are undocumented constructors somewhere.

4) Well quaternions can not be elements of a vector, but it can be elements of a matrix! Whoo Hoo! Something like
mat12 = matrix([q1,q2])
will actually create row matrix from two quaternions. Now I can implement the direct sum of two biquaternions, which is the odd degenerate space I have to work with. I guess someone forgot or didn't see the need to implement a _vector_ method.

5) As for rotations I guess we are on our own here. You will have to implement that your self as well as slerp and so forth for the computer graphics guys. I guess reflections or Lorentz transformations and so forth, which are nicely expressed in quaternions would also have to be a user application for now, along with wedge products, inner products and all the other types of multiplication in geometric algebras/clifford algebras.

I have accumulated a few more complaints though as I have continued. First it appears that there is not a lot of support for global substitutions on symbolic quaternions. You can't define quaternion functions symbolically and you can't do global variable substitutions without directly accessing the components. Global differentiation also appears broken.

Another gaping hole for any serious use of these libraries is the complete absence of quaternion transcendental functions. First there is no inverse! Yup quaternion inverse is missing. There is no exponentiation, no logarithm, no powers ...

more

I have run into another major problem with the quaternion package. You can not create functions that map variables to quaternions nor can you do global substitutions of variables. Here is an example, e1 is a quaternion.

~~~~

 var('x y', domain='real')
Q.<e1,e2,e3> = QuaternionAlgebra(SR, -1,-1)
q1 = I * x - x * e1
print (q1.subs(x=y))
qfunc(x) = I * x + x * e1
print(qfunc(y))
print(q1[0].subs(x=y))


~~~~

With output:

~~~~

 I*x + (-x)*e1
I*x + x*e1
I*y


~~~~

As you can see, only when I extract a coefficient of the quaternion do I get what I expect from a simple substitution.

( 2016-08-26 16:13:11 -0500 )edit