# Euler Angles in PyChemia¶

## Short Version¶

You can use the following routines to obtain the $$k(k-1)/2$$ Generalized Euler angles from a orhogonal matrix of dimension k and for building the orthogonal matrix from a set of angles:

>>> angles_list = pychemia.utils.mathematics.gea_all_angles(ortho_matrix)

>>> ortho_matrix = gea_orthogonal_from_angles(angles_list)


Remember that the list of angles matters. The SO(k) group is non-abelian.

The algorithm is based on the paper:

Generalization of Euler Angles to N-Dimensional Orthogonal Matrices
David K. Hoffman, Richard C. Raffenetti, and Klaus Ruedenberg
Journal of Mathematical Physics 13, 528 (1972)
doi: 10.1063/1.1666011


## Long Version¶

Rotation on a two-dimensional plane can be described with one angle. For a three dimensional space 3 angles are needed. You can define angles around each axis and general rotation matrices as a product of three single axis rotation matrices.

In general, for k dimensions, the number of angles is $$k(k-1)/2$$. One angle for each plane that you can get from any pair among the k vectors defining the space.

Any orthogonal matrix (with determinant equal to +1) represent a rotation matrix for the space that its dimension. Sometimes could be necessary to obtain the set of independent angles that the orthogonal matrix represents and having a way of regaining the original orthogonal matrix from a given set of angles.

One the reasons for moving between one orthogonal matrix and its angles is reducing an orthogonal matrix to its minimal independent parameters. The paper intitled: “Generalization of Euler Angles to N-Dimensional Orthogonal Matrices” provides an effective way to get the so called Euler angles for matrices of arbitrary dimension and reconstitute the matrix from a given set of angles.

This algorithm is implemented on PyChemia. As an example, lets build first a 7-dimensional orthogonal matrix by a QR decomposition:

In [1]: import pychemia

In [2]: import numpy as np

In [3]: np.set_printoptions(linewidth=200, suppress=True, precision=5)

In [4]: ortho = pychemia.utils.mathematics.gram_smith_qr(7)

In [5]:ortho
Out[5]:

array([[-0.23503793, -0.6039233 ,  0.31346146,  0.56383925,  0.18441349, -0.35292927,  0.07275729],
[-0.31380685, -0.21108679, -0.25878856, -0.40710624, -0.23657101, -0.54173578, -0.52423003],
[-0.48237691,  0.1056854 , -0.2376831 ,  0.11195934,  0.63817833,  0.3621268 , -0.38562619],
[-0.44643339, -0.33091574,  0.37743259, -0.27151849, -0.39852265,  0.56178535,  0.02431587],
[-0.46408875,  0.67693995,  0.31398053,  0.30715275, -0.28175741, -0.23147005, -0.02194835],
[-0.43149085,  0.00696596, -0.2664925 , -0.31313612,  0.19768295, -0.20337001,  0.75117024],
[-0.11282486, -0.10838891, -0.68280287,  0.48754035, -0.47483487,  0.20071602,  0.07649819]])


The variable ‘ortho’ is an orthogonal matrix as you can easily show by computing its determinant:

In [6]: np.linalg.det(ortho)
Out[6]: 1.0


Now, for a 7-dimension space we should expect 21 generalized Euler angles. We can get them by calling the function:

In [8]: angles_list = pychemia.utils.mathematics.gea_all_angles(ortho)

In [9]: np.array(angles_list)
Out[9]:

array([ -0.1392 , -0.03975, -0.37052, -0.48339,  0.13503,  0.39547, -0.22866, -0.31214, -0.57967,  0.84238,
-2.66098,  0.05294,  0.3535 , -0.83619, -0.06953, -0.51353, -1.01991,  2.28529, -0.25373, -0.33108,
-2.27736])


In fact we got 21 angles, all the angles in the range $$[-\pi, \pi]$$ We can rebuild the original orthogonal matrix from those angles with:

In [10]: matrix=pychemia.utils.mathematics.gea_orthogonal_from_angles(angles)


In fact, we can verify that we recover the original matrix:

In [11]: np.max(matrix-ortho)
Out[11]: 3.3306690738754696e-16