A submodule on Quaternions

78 views
Skip to first unread message

Nikhil Pappu

unread,
Aug 4, 2017, 10:12:59 AM8/4/17
to sympy
I was able to find some support for Quaternion Rotation in the Vector module but I did not come across a general submodule on Quaternions which allows users to define them and work with them.
I would like to implement a submodule which can support Quaternion Arithmetic, Functions, Quaternion Calculus, Rotation conversions etc.
It can then be extended to support more advanced Quaternion Algebra.

Would it be a good idea for me to start working on this?

Ondřej Čertík

unread,
Aug 4, 2017, 1:23:38 PM8/4/17
to sympy
Hi Nikhil,
I think that would be useful. I was just looking for such a module few
days ago. You should look into how Julia does it:

https://github.com/JuliaGeometry/Quaternions.jl

Looks like they represent a quaternion a+bi+cj+dk as a tuple of of
coefficients (a, b, c, d) and they also store a flag if the norm can
be computed (it seems).

Here I wrote code to multiply quaternions:

https://gitlab.com/certik/ijk/blob/df5f961d1f0432449fd7f16d21fa14840eef8c72/mul.py

I used complex 2x2 matrices. But Julia simply computes the new
coefficients (a, b, c, d) directly:

https://github.com/JuliaGeometry/Quaternions.jl/blob/62200f0ac5efd6d4d042f5d778d0cf2856c38c50/src/Quaternion.jl#L88

That's probably the way to go.

Ondrej

Nikhil Pappu

unread,
Aug 4, 2017, 2:02:46 PM8/4/17
to sympy
Thanks for the reply Ondřej. I will look into Julia's implementation. I think that is a good place to start. I will eventually try to implement a lot more though. I am looking towards a Quaternion Algebra submodule.
I found one such module in Sage so I guess that might be a good reference as well. 

Aaron Meurer

unread,
Aug 4, 2017, 3:06:30 PM8/4/17
to sy...@googlegroups.com
What level of symbolics would you expect from the module? Would you expect to be able to represent something like i*j unevaluated, or should every quaternion automatically simplify itself to normal form a*i + b*j + c*k + d?

Aaron Meurer

--
You received this message because you are subscribed to the Google Groups "sympy" group.
To unsubscribe from this group and stop receiving emails from it, send an email to sympy+unsubscribe@googlegroups.com.
To post to this group, send email to sy...@googlegroups.com.
Visit this group at https://groups.google.com/group/sympy.
To view this discussion on the web visit https://groups.google.com/d/msgid/sympy/f0b5dcbe-6a3c-4d36-8e0c-e6f7c9de2d1d%40googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

Nikhil Pappu

unread,
Aug 4, 2017, 3:24:13 PM8/4/17
to sympy
I would expect the Quaternions to automatically simplify to normal form.
To unsubscribe from this group and stop receiving emails from it, send an email to sympy+un...@googlegroups.com.

To post to this group, send email to sy...@googlegroups.com.
Visit this group at https://groups.google.com/group/sympy.

Francesco Bonazzi

unread,
Aug 4, 2017, 5:01:40 PM8/4/17
to sympy


On Friday, 4 August 2017 15:06:30 UTC-4, Aaron Meurer wrote:
What level of symbolics would you expect from the module? Would you expect to be able to represent something like i*j unevaluated,

Let's make this simple: Mul(i, j, evaluate=False), it's the same for the complex numbers:

Mul(I, I, evaluate=False)

We don't need special handlers in this case, just a simple Quaternion class and a definition for J and K. We might even be able to recycle the existing I.

Francesco Bonazzi

unread,
Aug 4, 2017, 5:04:18 PM8/4/17
to sympy
Also, consider that we don't have a class for complex numbers, we just define the imaginary unit and then complex numbers are managed by additions and multiplications. Maybe we should proceed by just adding J and K and defining their behavior.

What do you think?

Aaron Meurer

unread,
Aug 4, 2017, 5:34:25 PM8/4/17
to sy...@googlegroups.com
You can try this, but I foresee problems reusing I=sqrt(-1) the complex number as i the quaternion. Mathematically they aren't the same thing, but even in terms of SymPy, ImaginaryUnit is burdened with things like assumptions, which might cause issues with quaternions. 

But I do like the idea of just having 

class QuaternionI(Expr):
    is_commutative = False

class QuaternionJ(Expr):
    is_commutative = False

class QuaternionK(Expr):
    is_commutative = False

# Or maybe it should be I, J, K or i_, j_, k_ to avoid issues with loop variables
i, j, k = QuaternionI(), QuaternionJ(), QuaternionK()

And maybe even you could do something with the Mul processors to make them auto-simplify, if that's what is desired. 

You might also need some tricks to make the printer print them in the right order (not sure what is needed to make that work).

Aaron Meurer

On Fri, Aug 4, 2017 at 5:04 PM, Francesco Bonazzi <franz....@gmail.com> wrote:
Also, consider that we don't have a class for complex numbers, we just define the imaginary unit and then complex numbers are managed by additions and multiplications. Maybe we should proceed by just adding J and K and defining their behavior.

What do you think?

--
You received this message because you are subscribed to the Google Groups "sympy" group.
To unsubscribe from this group and stop receiving emails from it, send an email to sympy+unsubscribe@googlegroups.com.
To post to this group, send email to sy...@googlegroups.com.
Visit this group at https://groups.google.com/group/sympy.

Francesco Bonazzi

unread,
Aug 4, 2017, 6:19:12 PM8/4/17
to sympy


On Friday, 4 August 2017 17:34:25 UTC-4, Aaron Meurer wrote:
You can try this, but I foresee problems reusing I=sqrt(-1) the complex number as i the quaternion. Mathematically they aren't the same thing, but even in terms of SymPy, ImaginaryUnit is burdened with things like assumptions, which might cause issues with quaternions.

Implementing quaternions should be simple. Deciding how they interact with the rest of SymPy may be more complicated.


And maybe even you could do something with the Mul processors to make them auto-simplify, if that's what is desired.

I would suggest an immediate evaluation in this case.

Maybe a Quaternion class is the simplest way to implement quaternions.

Aaron Meurer

unread,
Aug 4, 2017, 7:16:04 PM8/4/17
to sy...@googlegroups.com
On Fri, Aug 4, 2017 at 6:19 PM, Francesco Bonazzi <franz....@gmail.com> wrote:


On Friday, 4 August 2017 17:34:25 UTC-4, Aaron Meurer wrote:
You can try this, but I foresee problems reusing I=sqrt(-1) the complex number as i the quaternion. Mathematically they aren't the same thing, but even in terms of SymPy, ImaginaryUnit is burdened with things like assumptions, which might cause issues with quaternions.

Implementing quaternions should be simple. Deciding how they interact with the rest of SymPy may be more complicated.

If you implement them like Ondrej suggested, as a 4-tuple, they will interact badly. Even just adding a scalar to a quaternion will be difficult to make work, as the scalar x would have to be converted to (x, 0, 0, 0) first.

On the other hand, if the quaternions i, j, and k are just special noncommutative expressions, then they will interact just fine, because SymPy already knows how to deal with noncommutative expressions.  The only hard thing will be making things like i**2 and i*j auto-simplify (if desired). The former can be done with _eval_power, and the latter with Mul postprocessors. 



And maybe even you could do something with the Mul processors to make them auto-simplify, if that's what is desired.

I would suggest an immediate evaluation in this case.

Maybe a Quaternion class is the simplest way to implement quaternions.

What do you mean by a Quaternion class? Are you thinking something more like my or Ondrej's suggestion?

Aaron Meurer
 

--
You received this message because you are subscribed to the Google Groups "sympy" group.
To unsubscribe from this group and stop receiving emails from it, send an email to sympy+unsubscribe@googlegroups.com.
To post to this group, send email to sy...@googlegroups.com.
Visit this group at https://groups.google.com/group/sympy.

Francesco Bonazzi

unread,
Aug 5, 2017, 2:48:55 PM8/5/17
to sympy


On Friday, 4 August 2017 19:16:04 UTC-4, Aaron Meurer wrote:


On Fri, Aug 4, 2017 at 6:19 PM, Francesco Bonazzi <franz....@gmail.com> wrote:


On Friday, 4 August 2017 17:34:25 UTC-4, Aaron Meurer wrote:
You can try this, but I foresee problems reusing I=sqrt(-1) the complex number as i the quaternion. Mathematically they aren't the same thing, but even in terms of SymPy, ImaginaryUnit is burdened with things like assumptions, which might cause issues with quaternions.

Implementing quaternions should be simple. Deciding how they interact with the rest of SymPy may be more complicated.

If you implement them like Ondrej suggested, as a 4-tuple, they will interact badly. Even just adding a scalar to a quaternion will be difficult to make work, as the scalar x would have to be converted to (x, 0, 0, 0) first.

On the other hand, if the quaternions i, j, and k are just special noncommutative expressions, then they will interact just fine, because SymPy already knows how to deal with noncommutative expressions.  The only hard thing will be making things like i**2 and i*j auto-simplify (if desired). The former can be done with _eval_power, and the latter with Mul postprocessors. 


That's one way to go, even if I'm not so sure on whether i should be different from the complex numbers. I don't think we need the postprocessors, setting a right value for _op_priority should be enough in this case. Postprocessors are meant to handle more complicated cases.

 


And maybe even you could do something with the Mul processors to make them auto-simplify, if that's what is desired.

I would suggest an immediate evaluation in this case.

Maybe a Quaternion class is the simplest way to implement quaternions.

What do you mean by a Quaternion class? Are you thinking something more like my or Ondrej's suggestion?

Well, sort of. We could have a class that stores four arguments and overrides __mul__ and __add__ to behave as a Quaternion.

Its constructor could have some special properties, such as:
  • return the first argument only if the other ones are zero (a real number).
  • return a complex number if the last two arguments are zero (a complex number).
  • in the printer, expressions such as Quaternion(0, 0, a, 0) should be printed as a*j where j = Quaternion(0, 0, 1, 0).

Some possible extensions remain:

  • how should functions of quaternions behave? Like exp(q), sin(q), log(q)?
  • how should quaternions interact with matrices?
  • how should quaternions behave in equation solvers?
  • limits and derivatives of quaternions?

Aaron Meurer

unread,
Aug 5, 2017, 4:38:11 PM8/5/17
to sy...@googlegroups.com
If quaternions are just regular noncommutative expressions, these will all just work out of the box.

Aaron Meurer
 
You received this message because you are subscribed to the Google Groups "sympy" group.
To unsubscribe from this group and stop receiving emails from it, send an email to sympy+unsubscribe@googlegroups.com.
To post to this group, send email to sy...@googlegroups.com.
Visit this group at https://groups.google.com/group/sympy.
Reply all
Reply to author
Forward
0 new messages