Package: numpy-quaternion
Quaternions in numpyThis Python module adds a quaternion dtype to NumPy.The code was originally based oncode by Martin
Ling(which he wrote
with help from Mark Wiebe), but was rewritten with ideas fromrationalto work with newer python versions (and to fix a few bugs), andgreatlyexpands the applications of quaternions.See also the pure-python packagequaternionic.Quickstartcondainstall-cconda-forgequaternionorpython-mpipinstall--upgrade--force-reinstallnumpy-quaternionOptionally add--userafterinstallin the second command if
you're not using a python environment — though you should start.DependenciesThe basic requirements for this code are reasonably current versions
ofpythonandnumpy.  In particular,pythonversions 3.8 through
3.11 are routinely tested.  Earlierpythonversions, including 2.7,
will work with older versions of this package; theymightstill work
with more recent versions of this package, but even numpy no longer
supportspythonprevious to 3.8, so your mileage may vary.  Also,
anynumpyversiongreater than
1.13.0should work,
but the tests are run on the most recent release at the time of the
test.However, certain advanced functions in this package (includingsquad,mean_rotor_in_intrinsic_metric,integrate_angular_velocity, and related functions) requirescipyand can automatically usenumba.Scipyis a standard python
package for scientific computation, and implements interfaces to C and
Fortran codes for optimization (among other things) need for finding
mean and optimal rotors.NumbausesLLVMto
compile python code to machine code, accelerating many numerical
functions by factors of anywhere from 2 to 2000.  It ispossibleto
run all the code withoutnumba, but these particular functions can
be anywhere from 4 to 400 times slower without it.Bothscipyandnumbacan be installed withpiporconda.
However, becausecondais specifically geared toward scientific
python, it is generally more robust for these more complicated
packages.  In fact, the mainanacondapackage
comes with bothnumbaandscipy.  If you prefer the smaller
download size ofminiconda(which comes with minimal extras), you'll also have to run this
command:condainstallnumpyscipynumbaInstallationAssuming you usecondato manage your python installation (which is
currently the preferred choice for science and engineering with
python), you can install this package simply ascondainstall-cconda-forgequaternionIf you prefer to usepip, you can instead dopython-mpipinstall--upgrade--force-reinstallnumpy-quaternion(Seeherefor a
veteran python core contributor's explanation of why you should always
usepython -m pipinstead of justpiporpip3.)  The--upgrade --force-reinstalloptions are not always necessary, but will ensure
that pip will update numpy if it has to.If you refuse to useconda, you might want to install inside your
home directory without root privileges.  (Conda does this by default
anyway.)  This is done by adding--userto the above command:python-mpipinstall--user--upgrade--force-reinstallnumpy-quaternionNote that pip will attempt to compile the code — which requires a
workingCcompiler.Finally, there's also the fully manual option of just downloading the
code, changing to the code directory, and runningpython-mpipinstall--upgrade--force-reinstall.This should work regardless of the installation method, as long as you
have a compiler hanging around.Basic usageThe full documentation can be found onRead the
Docs, and most functions have
docstrings that should explain the relevant points.  The following are
mostly for the purposes of example.>>>importnumpyasnp>>>importquaternion>>>np.quaternion(1,0,0,0)quaternion(1,0,0,0)>>>q1=np.quaternion(1,2,3,4)>>>q2=np.quaternion(5,6,7,8)>>>q1*q2quaternion(-60,12,30,24)>>>a=np.array([q1,q2])>>>aarray([quaternion(1,2,3,4),quaternion(5,6,7,8)],dtype=quaternion)>>>np.exp(a)array([quaternion(1.69392,-0.78956,-1.18434,-1.57912),quaternion(138.909,-25.6861,-29.9671,-34.2481)],dtype=quaternion)Note that this package represents a quaternion as a scalar, followed
by thexcomponent of the vector part, followed byy, followed byz.  These components can be accessed directly:>>>q1.w,q1.x,q1.y,q1.z(1.0,2.0,3.0,4.0)However, this only works on an individualquaternion; for arrays it
is better to use "vectorized" operations likeas_float_array.The following ufuncs are implemented (which means they run fast on
numpy arrays):add,subtract,multiply,divide,log,exp,power,negative,conjugate,copysign,equal,not_equal,less,less_equal,isnan,isinf,isfinite,absoluteQuaternion components are stored as double-precision floating point
numbers —floats, in python language, orfloat64in more precise
numpy language.  Numpy arrays withdtype=quaternioncan be accessed
as arrays of doubles without any (slow, memory-consuming) copying of
data; rather, aviewof the exact same memory space can be created
within a microsecond, regardless of the shape or size of the
quaternion array.Comparison operations follow the same lexicographic ordering as
tuples.The unary tests isnan and isinf return true if they would return true
for any individual component; isfinite returns true if it would return
true for all components.Real types may be cast to quaternions, giving quaternions with zero
for all three imaginary components. Complex types may also be cast to
quaternions, with their single imaginary component becoming the first
imaginary component of the quaternion. Quaternions may not be cast to
real or complex types.Several array-conversion functions are also included.  For example, to
convert an Nx4 array of floats to an N-dimensional array of
quaternions, useas_quat_array:>>>importnumpyasnp>>>importquaternion>>>a=np.random.rand(7,4)>>>aarray([[0.93138726,0.46972279,0.18706385,0.86605021],[0.70633523,0.69982741,0.93303559,0.61440879],[0.79334456,0.65912598,0.0711557,0.46622885],[0.88185987,0.9391296,0.73670503,0.27115149],[0.49176628,0.56688076,0.13216632,0.33309146],[0.11951624,0.86804078,0.77968826,0.37229404],[0.33187593,0.53391165,0.8577846,0.18336855]])>>>qs=quaternion.as_quat_array(a)>>>qsarray([quaternion(0.931387262880247,0.469722787598354,0.187063852060487,0.866050210100621),quaternion(0.706335233363319,0.69982740767353,0.933035590130247,0.614408786768725),quaternion(0.793344561317281,0.659125976566815,0.0711557025000925,0.466228847713644),quaternion(0.881859869074069,0.939129602918467,0.736705031709562,0.271151494174001),quaternion(0.491766284854505,0.566880763189927,0.132166320200012,0.333091463422536),quaternion(0.119516238634238,0.86804077992676,0.779688263524229,0.372294043850009),quaternion(0.331875925159073,0.533911652483908,0.857784598617977,0.183368547490701)],dtype=quaternion)[Note that quaternions are printed with full precision, unlike floats,
which is why you see extra digits above.  But the actual data is
identical in the two cases.]  To convert an N-dimensional array of
quaternions to an Nx4 array of floats, useas_float_array:>>>b=quaternion.as_float_array(qs)>>>barray([[0.93138726,0.46972279,0.18706385,0.86605021],[0.70633523,0.69982741,0.93303559,0.61440879],[0.79334456,0.65912598,0.0711557,0.46622885],[0.88185987,0.9391296,0.73670503,0.27115149],[0.49176628,0.56688076,0.13216632,0.33309146],[0.11951624,0.86804078,0.77968826,0.37229404],[0.33187593,0.53391165,0.8577846,0.18336855]])It is also possible to convert a quaternion to or from a 3x3 array of
floats representing a rotation matrix, or an array of N quaternions to
or from an Nx3x3 array of floats representing N rotation matrices,
usingas_rotation_matrixandfrom_rotation_matrix.  Similar
conversions are possible for rotation vectors usingas_rotation_vectorandfrom_rotation_vector, and for spherical
coordinates usingas_spherical_coordsandfrom_spherical_coords.
Finally, it is possible to derive the Euler angles from a quaternion
usingas_euler_angles, or create a quaternion from Euler angles
usingfrom_euler_angles— though be aware that Euler angles are
basically the worst things
ever.1Before you complain
about those functions using something other than your favorite
conventions, please readthis
page.Bug reports and feature requestsBug reports and feature requests are entirely welcome (withvery few
exceptions).
The best way to do this is to open anissue on this code's github
page.  For bug reports,
please try to include a minimal working example demonstrating the
problem.Pull requestsare also entirely welcome, of course, if you have an idea where the
code is going wrong, or have an idea for a new feature that you know
how to implement.This code is routinely tested on recent versions of both python (3.8
though 3.11) and numpy (>=1.13).  But the test coverage is not
necessarily as complete as it could be, so bugs may certainly be
present, especially in the higher-level functions likemean_rotor_....AcknowledgmentsThis code is, of course, hosted on github.  Because it is an
open-source project, the hosting is free, and all the wonderful
features of github are available, including free wiki space and web
page hosting, pull requests, a nice interface to the git logs, etc.
Github user Hannes Ovrén (hovren) pointed out some errors in a
previous version of this code and suggested some nice utility
functions for rotation matrices, etc.  Github user Stijn van Drongelen
(rhymoid) contributed some code that makes compilation work with
MSVC++.  Github user Jon Long (longjon) has provided some elegant
contributions to substantially improve several tricky parts of this
code.  Rebecca Turner (9999years) and Leo Stein (duetosymmetry) did
all the work in getting the documentation ontoRead the
Docs.Every change in this code isautomatically
testedon Github
Actions.  The code is downloaded and installed fresh each time, and
then tested, on each of the different supported versions of python, on
each of the supported platforms.  This ensures that no change I make
to the code breaks either installation or any of the features that I
have written tests for.  Github Actions also automatically builds thepipversions of the code hosted onpypi.  Conda-forge
also uses Github Actions to buildthe conda/mamba
versionhosted
onanaconda.org.  These
are all free services for open-source projects like this one.The work of creating this code was supported in part by the Sherman
Fairchild Foundation and by NSF Grants No. PHY-1306125 and
AST-1333129.1Euler angles are awfulEuler angles are pretty muchthe worst things
everand it
makes me feel bad even supporting them.  Quaternions are faster, more
accurate, basically free of singularities, more intuitive, and
generally easier to understand.  You can work entirely without Euler
angles (I certainly do).  You absolutely never need them.  But if
you really can't give them up, they are mildly supported.