Skip to content

beignet

beignet.apply_euler_angle

apply_euler_angle(input, rotation, axes, degrees=False, inverse=False)

Rotates vectors in three-dimensional space using Euler angles.

Note

This function interprets the rotation of the original frame to the final frame as either a projection, where it maps the components of vectors from the final frame to the original frame, or as a physical rotation, integrating the vectors into the original frame during the rotation process. Consequently, the vector components are maintained in the original frame’s perspective both before and after the rotation.

Parameters:

Name Type Description Default
input Tensor

Vectors in three-dimensional space with the shape \((\ldots \times 3)\). Euler angles and vectors must conform to PyTorch broadcasting rules.

required
rotation Tensor

Euler angles with the shape \((\ldots \times 3)\), specifying the rotation in three-dimensional space.

required
axes str

Specifies the sequence of axes for the rotations, using one to three characters from the set \({X, Y, Z}\) for intrinsic rotations, or \({x, y, z}\) for extrinsic rotations. Mixing extrinsic and intrinsic rotations raises a ValueError.

required
degrees bool

Indicates whether the Euler angles are provided in degrees. If False, angles are assumed to be in radians. Default, False.

False
inverse bool

If True, applies the inverse rotation using the Euler angles to the input vectors. Default, False.

False

Returns:

Name Type Description
output Tensor

A tensor of the same shape as input, containing the rotated vectors.

Source code in src/beignet/_apply_euler_angle.py
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
def apply_euler_angle(
    input: Tensor,
    rotation: Tensor,
    axes: str,
    degrees: bool = False,
    inverse: bool = False,
) -> Tensor:
    r"""
    Rotates vectors in three-dimensional space using Euler angles.

    Note
    ----
    This function interprets the rotation of the original frame to the final
    frame as either a projection, where it maps the components of vectors from
    the final frame to the original frame, or as a physical rotation,
    integrating the vectors into the original frame during the rotation
    process. Consequently, the vector components are maintained in the original
    frame’s perspective both before and after the rotation.

    Parameters
    ----------
    input : Tensor
        Vectors in three-dimensional space with the shape $(\ldots \times 3)$.
        Euler angles and vectors must conform to PyTorch broadcasting rules.

    rotation : Tensor
        Euler angles with the shape $(\ldots \times 3)$, specifying the
        rotation in three-dimensional space.

    axes : str
        Specifies the sequence of axes for the rotations, using one to three
        characters from the set ${X, Y, Z}$ for intrinsic rotations, or
        ${x, y, z}$ for extrinsic rotations. Mixing extrinsic and intrinsic
        rotations raises a `ValueError`.

    degrees : bool, optional
        Indicates whether the Euler angles are provided in degrees. If `False`,
        angles are assumed to be in radians. Default, `False`.

    inverse : bool, optional
        If `True`, applies the inverse rotation using the Euler angles to the
        input vectors. Default, `False`.

    Returns
    -------
    output : Tensor
        A tensor of the same shape as `input`, containing the rotated vectors.
    """
    return apply_rotation_matrix(
        input,
        euler_angle_to_rotation_matrix(
            rotation,
            axes,
            degrees,
        ),
        inverse,
    )

beignet.apply_quaternion

apply_quaternion(input, rotation, inverse=False)

Rotates vectors in three-dimensional space using rotation quaternions.

Note

This function interprets the rotation of the original frame to the final frame as either a projection, where it maps the components of vectors from the final frame to the original frame, or as a physical rotation, integrating the vectors into the original frame during the rotation process. Consequently, the vector components are maintained in the original frame’s perspective both before and after the rotation.

Parameters:

Name Type Description Default
input (Tensor, shape(..., 3))

Each vector represents a vector in three-dimensional space. The number of rotation quaternions and number of vectors must follow standard broadcasting rules: either one of them equals unity or they both equal each other.

required
rotation (Tensor, shape(..., 4))

Rotation quaternions. Rotation quaternions are normalized to unit norm.

required
inverse bool

If True the inverse of the rotation quaternions are applied to the input vectors. Default, False.

False

Returns:

Name Type Description
output (Tensor, shape(..., 3))

Rotated vectors.

Source code in src/beignet/_apply_quaternion.py
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
def apply_quaternion(
    input: Tensor,
    rotation: Tensor,
    inverse: bool | None = False,
) -> Tensor:
    r"""
    Rotates vectors in three-dimensional space using rotation quaternions.

    Note
    ----
    This function interprets the rotation of the original frame to the final
    frame as either a projection, where it maps the components of vectors from
    the final frame to the original frame, or as a physical rotation,
    integrating the vectors into the original frame during the rotation
    process. Consequently, the vector components are maintained in the original
    frame’s perspective both before and after the rotation.

    Parameters
    ----------
    input : Tensor, shape (..., 3)
        Each vector represents a vector in three-dimensional space. The number
        of rotation quaternions and number of vectors must follow standard
        broadcasting rules: either one of them equals unity or they both equal
        each other.

    rotation : Tensor, shape (..., 4)
        Rotation quaternions. Rotation quaternions are normalized to unit norm.

    inverse : bool, optional
        If `True` the inverse of the rotation quaternions are applied to the
        input vectors. Default, `False`.

    Returns
    -------
    output : Tensor, shape (..., 3)
        Rotated vectors.
    """
    return apply_rotation_matrix(
        input,
        quaternion_to_rotation_matrix(
            rotation,
        ),
        inverse,
    )

beignet.apply_rotation_matrix

apply_rotation_matrix(input, rotation, inverse=False)

Rotates vectors in three-dimensional space using rotation matrices.

Note

This function interprets the rotation of the original frame to the final frame as either a projection, where it maps the components of vectors from the final frame to the original frame, or as a physical rotation, integrating the vectors into the original frame during the rotation process. Consequently, the vector components are maintained in the original frame’s perspective both before and after the rotation.

Parameters:

Name Type Description Default
input (Tensor, shape(..., 3))

Each vector represents a vector in three-dimensional space. The number of rotation matrices and number of vectors must follow standard broadcasting rules: either one of them equals unity or they both equal each other.

required
rotation (Tensor, shape(..., 3, 3))

Rotation matrices.

required
inverse bool

If True the inverse of the rotation matrices are applied to the input vectors. Default, False.

False

Returns:

Name Type Description
rotated_vectors (Tensor, shape(..., 3))

Rotated vectors.

Source code in src/beignet/_apply_rotation_matrix.py
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
def apply_rotation_matrix(
    input: Tensor,
    rotation: Tensor,
    inverse: bool | None = False,
) -> Tensor:
    r"""
    Rotates vectors in three-dimensional space using rotation matrices.

    Note
    ----
    This function interprets the rotation of the original frame to the final
    frame as either a projection, where it maps the components of vectors from
    the final frame to the original frame, or as a physical rotation,
    integrating the vectors into the original frame during the rotation
    process. Consequently, the vector components are maintained in the original
    frame’s perspective both before and after the rotation.

    Parameters
    ----------
    input : Tensor, shape (..., 3)
        Each vector represents a vector in three-dimensional space. The number
        of rotation matrices and number of vectors must follow standard
        broadcasting rules: either one of them equals unity or they both equal
        each other.

    rotation : Tensor, shape (..., 3, 3)
        Rotation matrices.

    inverse : bool, optional
        If `True` the inverse of the rotation matrices are applied to the input
        vectors. Default, `False`.

    Returns
    -------
    rotated_vectors : Tensor, shape (..., 3)
        Rotated vectors.
    """
    if inverse:
        output = torch.einsum("ikj, ik -> ij", rotation, input)
    else:
        output = torch.einsum("ijk, ik -> ij", rotation, input)

    return output

beignet.apply_rotation_vector

apply_rotation_vector(input, rotation, degrees=False, inverse=False)

Rotates vectors in three-dimensional space using rotation vectors.

Note

This function interprets the rotation of the original frame to the final frame as either a projection, where it maps the components of vectors from the final frame to the original frame, or as a physical rotation, integrating the vectors into the original frame during the rotation process. Consequently, the vector components are maintained in the original frame’s perspective both before and after the rotation.

Parameters:

Name Type Description Default
input (Tensor, shape(..., 3))

Each vector represents a vector in three-dimensional space. The number of rotation vectors and number of vectors must follow standard broadcasting rules: either one of them equals unity or they both equal each other.

required
rotation (Tensor, shape(..., 4))

Rotation vectors.

required
degrees bool

If True, rotation vector magnitudes are assumed to be in degrees. Default, False.

False
inverse bool

If True the inverse of the rotation vectors are applied to the input vectors. Default, False.

False

Returns:

Name Type Description
output Tensor, shape=(..., 3)

Rotated vectors.

Source code in src/beignet/_apply_rotation_vector.py
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
def apply_rotation_vector(
    input: Tensor,
    rotation: Tensor,
    degrees: bool | None = False,
    inverse: bool | None = False,
) -> Tensor:
    r"""
    Rotates vectors in three-dimensional space using rotation vectors.

    Note
    ----
    This function interprets the rotation of the original frame to the final
    frame as either a projection, where it maps the components of vectors from
    the final frame to the original frame, or as a physical rotation,
    integrating the vectors into the original frame during the rotation
    process. Consequently, the vector components are maintained in the original
    frame’s perspective both before and after the rotation.

    Parameters
    ----------
    input : Tensor, shape (..., 3)
        Each vector represents a vector in three-dimensional space. The number
        of rotation vectors and number of vectors must follow standard
        broadcasting rules: either one of them equals unity or they both equal
        each other.

    rotation : Tensor, shape (..., 4)
        Rotation vectors.

    degrees : bool, optional
        If `True`, rotation vector magnitudes are assumed to be in degrees.
        Default, `False`.

    inverse : bool, optional
        If `True` the inverse of the rotation vectors are applied to the input
        vectors. Default, `False`.

    Returns
    -------
    output : Tensor, shape=(..., 3)
        Rotated vectors.
    """
    return apply_rotation_matrix(
        input,
        quaternion_to_rotation_matrix(
            rotation_vector_to_quaternion(
                rotation,
                degrees,
            ),
        ),
        inverse,
    )

beignet.compose_euler_angle

compose_euler_angle(input, other, axes, degrees=False)

Compose rotation quaternions.

Parameters:

Name Type Description Default
input Tensor, shape=(..., 3)

Euler angles.

required
other Tensor, shape=(..., 3)

Euler angles.

required
axes str

Axes. One to three characters belonging to the set :math:\{X, Y, Z\} for intrinsic rotations, or :math:\{x, y, z\} for extrinsic rotations. Extrinsic and intrinsic rotations cannot be mixed.

required
degrees bool

If True, Euler angles are assumed to be in degrees. Default, False.

False

Returns:

Name Type Description
output Tensor, shape=(..., 3)

Composed Euler angles.

Source code in src/beignet/_compose_euler_angle.py
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
def compose_euler_angle(
    input: Tensor,
    other: Tensor,
    axes: str,
    degrees: bool | None = False,
) -> Tensor:
    r"""
    Compose rotation quaternions.

    Parameters
    ----------
    input : Tensor, shape=(..., 3)
        Euler angles.

    other : Tensor, shape=(..., 3)
        Euler angles.

    axes : str
        Axes. One to three characters belonging to the set :math:`\{X, Y, Z\}`
        for intrinsic rotations, or :math:`\{x, y, z\}` for extrinsic
        rotations. Extrinsic and intrinsic rotations cannot be mixed.

    degrees : bool, optional
        If `True`, Euler angles are assumed to be in degrees. Default, `False`.

    Returns
    -------
    output : Tensor, shape=(..., 3)
        Composed Euler angles.
    """
    return quaternion_to_euler_angle(
        compose_quaternion(
            euler_angle_to_quaternion(
                input,
                axes,
                degrees,
            ),
            euler_angle_to_quaternion(
                other,
                axes,
                degrees,
            ),
        ),
        axes,
        degrees,
    )

beignet.compose_quaternion

compose_quaternion(input, other, canonical=False)

Compose rotation quaternions.

Parameters:

Name Type Description Default
input Tensor, shape=(..., 4)

Rotation quaternions. Rotation quaternions are normalized to unit norm.

required
other Tensor, shape=(..., 4)

Rotation quaternions. Rotation quaternions are normalized to unit norm.

required
canonical bool

Whether to map the redundant double cover of rotation space to a unique canonical single cover. If True, then the rotation quaternion is chosen from :math:{q, -q} such that the :math:w term is positive. If the :math:w term is :math:0, then the rotation quaternion is chosen such that the first non-zero term of the :math:x, :math:y, and :math:z terms is positive.

False

Returns:

Name Type Description
output Tensor, shape=(..., 4)

Composed rotation quaternions.

Source code in src/beignet/_compose_quaternion.py
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
def compose_quaternion(
    input: Tensor,
    other: Tensor,
    canonical: bool = False,
) -> Tensor:
    r"""
    Compose rotation quaternions.

    Parameters
    ----------
    input : Tensor, shape=(..., 4)
        Rotation quaternions. Rotation quaternions are normalized to unit norm.

    other : Tensor, shape=(..., 4)
        Rotation quaternions. Rotation quaternions are normalized to unit norm.

    canonical : bool, optional
        Whether to map the redundant double cover of rotation space to a unique
        canonical single cover. If `True`, then the rotation quaternion is
        chosen from :math:`{q, -q}` such that the :math:`w` term is positive.
        If the :math:`w` term is :math:`0`, then the rotation quaternion is
        chosen such that the first non-zero term of the :math:`x`, :math:`y`,
        and :math:`z` terms is positive.

    Returns
    -------
    output : Tensor, shape=(..., 4)
        Composed rotation quaternions.
    """
    output = torch.empty(
        [max(input.shape[0], other.shape[0]), 4],
        dtype=input.dtype,
        layout=input.layout,
        device=input.device,
    )

    for j in range(max(input.shape[0], other.shape[0])):
        a = input[j, 0]
        b = input[j, 1]
        c = input[j, 2]
        d = input[j, 3]

        p = other[j, 0]
        q = other[j, 1]
        r = other[j, 2]
        s = other[j, 3]

        t = output[j, 0]
        u = output[j, 1]
        v = output[j, 2]
        w = output[j, 3]

        output[j, 0] = d * p + s * a + b * r - c * q
        output[j, 1] = d * q + s * b + c * p - a * r
        output[j, 2] = d * r + s * c + a * q - b * p
        output[j, 3] = d * s - a * p - b * q - c * r

        x = torch.sqrt(t**2.0 + u**2.0 + v**2.0 + w**2.0)

        if x == 0.0:
            output[j] = torch.nan

        output[j] = output[j] / x

        if canonical:
            if w == 0 and (t == 0 and (u == 0 and v < 0 or u < 0) or t < 0) or w < 0:
                output[j] = -output[j]

    return output

beignet.compose_rotation_matrix

compose_rotation_matrix(input, other)

Compose rotation matrices.

Parameters:

Name Type Description Default
input Tensor, shape=(..., 3, 3)

Rotation matrices.

required
other Tensor, shape=(..., 3, 3)

Rotation matrices.

required

Returns:

Name Type Description
output Tensor, shape=(..., 3, 3)

Composed rotation matrices.

Source code in src/beignet/_compose_rotation_matrix.py
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
def compose_rotation_matrix(
    input: Tensor,
    other: Tensor,
) -> Tensor:
    r"""
    Compose rotation matrices.

    Parameters
    ----------
    input : Tensor, shape=(..., 3, 3)
        Rotation matrices.

    other : Tensor, shape=(..., 3, 3)
        Rotation matrices.

    Returns
    -------
    output : Tensor, shape=(..., 3, 3)
        Composed rotation matrices.
    """
    return quaternion_to_rotation_matrix(
        compose_quaternion(
            rotation_matrix_to_quaternion(input),
            rotation_matrix_to_quaternion(other),
        ),
    )

beignet.compose_rotation_vector

compose_rotation_vector(input, other, degrees=False)

Compose rotation vectors.

Parameters:

Name Type Description Default
input Tensor, shape=(..., 4)

Rotation vectors.

required
other Tensor, shape=(..., 4)

Rotation vectors.

required
degrees bool

If True, rotation vector magnitudes are assumed to be in degrees. Default, False.

False

Returns:

Name Type Description
output Tensor, shape=(..., 4)

Composed rotation vectors.

Source code in src/beignet/_compose_rotation_vector.py
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
def compose_rotation_vector(
    input: Tensor,
    other: Tensor,
    degrees: bool | None = False,
) -> Tensor:
    r"""
    Compose rotation vectors.

    Parameters
    ----------
    input : Tensor, shape=(..., 4)
        Rotation vectors.

    other : Tensor, shape=(..., 4)
        Rotation vectors.

    degrees : bool, optional
        If `True`, rotation vector magnitudes are assumed to be in degrees.
        Default, `False`.

    Returns
    -------
    output : Tensor, shape=(..., 4)
        Composed rotation vectors.
    """
    return quaternion_to_rotation_vector(
        compose_quaternion(
            rotation_vector_to_quaternion(
                input,
                degrees,
            ),
            rotation_vector_to_quaternion(
                other,
                degrees,
            ),
        ),
        degrees,
    )

beignet.euler_angle_identity

euler_angle_identity(size, axes, degrees=False, *, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False)

Identity Euler angles.

Parameters:

Name Type Description Default
size int

Output size.

required
axes str

Axes. 1-3 characters belonging to the set {‘X’, ‘Y’, ‘Z’} for intrinsic rotations, or {‘x’, ‘y’, ‘z’} for extrinsic rotations. Extrinsic and intrinsic rotations cannot be mixed.

required
degrees bool

If True, Euler angles are assumed to be in degrees. Default, False.

False
out Tensor

Output tensor. Default, None.

None
dtype dtype

Type of the returned tensor. Default, global default.

None
layout layout

Layout of the returned tensor. Default, torch.strided.

strided
device device

Device of the returned tensor. Default, current device for the default tensor type.

None
requires_grad bool

Whether autograd records operations on the returned tensor. Default, False.

False

Returns:

Name Type Description
identity_euler_angles (Tensor, shape(size, 3))

Identity Euler angles.

Source code in src/beignet/_euler_angle_identity.py
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
def euler_angle_identity(
    size: int,
    axes: str,
    degrees: bool | None = False,
    *,
    out: Tensor | None = None,
    dtype: torch.dtype | None = None,
    layout: torch.layout | None = torch.strided,
    device: torch.device | None = None,
    requires_grad: bool | None = False,
) -> Tensor:
    r"""
    Identity Euler angles.

    Parameters
    ----------
    size : int
        Output size.

    axes : str
        Axes. 1-3 characters belonging to the set {‘X’, ‘Y’, ‘Z’} for intrinsic
        rotations, or {‘x’, ‘y’, ‘z’} for extrinsic rotations. Extrinsic and
        intrinsic rotations cannot be mixed.

    degrees : bool, optional
        If `True`, Euler angles are assumed to be in degrees. Default, `False`.

    out : Tensor, optional
        Output tensor. Default, `None`.

    dtype : torch.dtype, optional
        Type of the returned tensor. Default, global default.

    layout : torch.layout, optional
        Layout of the returned tensor. Default, `torch.strided`.

    device : torch.device, optional
        Device of the returned tensor. Default, current device for the default
        tensor type.

    requires_grad : bool, optional
        Whether autograd records operations on the returned tensor. Default,
        `False`.

    Returns
    -------
    identity_euler_angles : Tensor, shape (size, 3)
        Identity Euler angles.
    """
    return quaternion_to_euler_angle(
        quaternion_identity(
            size,
            out=out,
            dtype=dtype,
            layout=layout,
            device=device,
            requires_grad=requires_grad,
        ),
        axes,
        degrees,
    )

beignet.euler_angle_magnitude

euler_angle_magnitude(input, axes, degrees=False)

Euler angle magnitudes.

Parameters:

Name Type Description Default
input (Tensor, shape(..., 3))

Euler angles.

required
axes str

Axes. 1-3 characters belonging to the set {‘X’, ‘Y’, ‘Z’} for intrinsic rotations, or {‘x’, ‘y’, ‘z’} for extrinsic rotations. Extrinsic and intrinsic rotations cannot be mixed.

required
degrees bool

If True, Euler angles are assumed to be in degrees. Default, False.

False

Returns:

Name Type Description
euler_angle_magnitudes (Tensor, shape(...))

Angles in radians. Magnitudes will be in the range :math:[0, \pi].

Source code in src/beignet/_euler_angle_magnitude.py
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
def euler_angle_magnitude(
    input: Tensor,
    axes: str,
    degrees: bool | None = False,
) -> Tensor:
    r"""
    Euler angle magnitudes.

    Parameters
    ----------
    input : Tensor, shape (..., 3)
        Euler angles.

    axes : str
        Axes. 1-3 characters belonging to the set {‘X’, ‘Y’, ‘Z’} for intrinsic
        rotations, or {‘x’, ‘y’, ‘z’} for extrinsic rotations. Extrinsic and
        intrinsic rotations cannot be mixed.

    degrees : bool, optional
        If `True`, Euler angles are assumed to be in degrees. Default, `False`.

    Returns
    -------
    euler_angle_magnitudes: Tensor, shape (...)
        Angles in radians. Magnitudes will be in the range :math:`[0, \pi]`.
    """
    return quaternion_magnitude(
        euler_angle_to_quaternion(
            input,
            axes,
            degrees,
        ),
    )

beignet.euler_angle_mean

euler_angle_mean(input, weight=None, axes=None, degrees=False)

Euler angle mean.

Parameters:

Name Type Description Default
input Tensor, shape=(..., 3)

Euler angles.

required
weight Tensor, shape=(..., 4)

Relative importance of rotation quaternions.

None
axes str

Axes. One to three characters belonging to the set :math:\{X, Y, Z\} for intrinsic rotations, or :math:\{x, y, z\} for extrinsic rotations. Extrinsic and intrinsic rotations cannot be mixed.

None
degrees bool

If True, Euler angles are assumed to be in degrees. Default, False.

False

Returns:

Name Type Description
output Tensor, shape=(..., 3)

Euler angle mean.

Source code in src/beignet/_euler_angle_mean.py
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
def euler_angle_mean(
    input: Tensor,
    weight: Tensor | None = None,
    axes: str | None = None,
    degrees: bool | None = False,
) -> Tensor:
    r"""
    Euler angle mean.

    Parameters
    ----------
    input : Tensor, shape=(..., 3)
        Euler angles.

    weight : Tensor, shape=(..., 4), optional
        Relative importance of rotation quaternions.

    axes : str
        Axes. One to three characters belonging to the set :math:`\{X, Y, Z\}`
        for intrinsic rotations, or :math:`\{x, y, z\}` for extrinsic
        rotations. Extrinsic and intrinsic rotations cannot be mixed.

    degrees : bool, optional
        If `True`, Euler angles are assumed to be in degrees. Default, `False`.

    Returns
    -------
    output : Tensor, shape=(..., 3)
        Euler angle mean.
    """
    return quaternion_to_euler_angle(
        quaternion_mean(
            euler_angle_to_quaternion(
                input,
                axes,
                degrees,
            ),
            weight,
        ),
        axes,
        degrees,
    )

beignet.euler_angle_to_quaternion

euler_angle_to_quaternion(input, axes, degrees=False, canonical=False)

Convert Euler angles to rotation quaternions.

Parameters:

Name Type Description Default
input Tensor, shape=(..., 3)

Euler angles.

required
axes str

Axes. One to three characters belonging to the set :math:\{X, Y, Z\} for intrinsic rotations, or :math:\{x, y, z\} for extrinsic rotations. Extrinsic and intrinsic rotations cannot be mixed.

required
degrees bool

If True, Euler angles are assumed to be in degrees. Default, False.

False
canonical bool

Whether to map the redundant double cover of rotation space to a unique canonical single cover. If True, then the rotation quaternion is chosen from :math:{q, -q} such that the :math:w term is positive. If the :math:w term is :math:0, then the rotation quaternion is chosen such that the first non-zero term of the :math:x, :math:y, and :math:z terms is positive.

False

Returns:

Name Type Description
output Tensor, shape=(..., 4)

Rotation quaternions.

Source code in src/beignet/_euler_angle_to_quaternion.py
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
def euler_angle_to_quaternion(
    input: Tensor,
    axes: str,
    degrees: bool = False,
    canonical: bool | None = False,
) -> Tensor:
    r"""
    Convert Euler angles to rotation quaternions.

    Parameters
    ----------
    input : Tensor, shape=(..., 3)
        Euler angles.

    axes : str
        Axes. One to three characters belonging to the set :math:`\{X, Y, Z\}`
        for intrinsic rotations, or :math:`\{x, y, z\}` for extrinsic
        rotations. Extrinsic and intrinsic rotations cannot be mixed.

    degrees : bool, optional
        If `True`, Euler angles are assumed to be in degrees. Default, `False`.

    canonical : bool, optional
        Whether to map the redundant double cover of rotation space to a unique
        canonical single cover. If `True`, then the rotation quaternion is
        chosen from :math:`{q, -q}` such that the :math:`w` term is positive.
        If the :math:`w` term is :math:`0`, then the rotation quaternion is
        chosen such that the first non-zero term of the :math:`x`, :math:`y`,
        and :math:`z` terms is positive.

    Returns
    -------
    output : Tensor, shape=(..., 4)
        Rotation quaternions.
    """
    intrinsic = re.match(r"^[XYZ]{1,3}$", axes) is not None

    if degrees:
        input = torch.deg2rad(input)

    if len(axes) == 1:
        if input.ndim == 0:
            input = input.reshape([1, 1])
        elif input.ndim == 1:
            input = input[:, None]
        elif input.ndim == 2 and input.shape[-1] != 1:
            raise ValueError
        elif input.ndim > 2:
            raise ValueError
    else:
        if input.ndim not in [1, 2] or input.shape[-1] != len(axes):
            raise ValueError

        if input.ndim == 1:
            input = input[None, :]

    if input.ndim != 2 or input.shape[-1] != len(axes):
        raise ValueError

    output = torch.zeros(
        [input.shape[0], 4],
        dtype=input.dtype,
        layout=input.layout,
        device=input.device,
    )

    match axes.lower()[0]:
        case "x":
            k = 0
        case "y":
            k = 1
        case "z":
            k = 2
        case _:
            raise ValueError

    for j in range(input[:, 0].shape[0]):
        output[j, 3] = torch.cos(input[:, 0][j] / 2)
        output[j, k] = torch.sin(input[:, 0][j] / 2)

    z = output

    c = torch.empty(
        [3],
        dtype=input.dtype,
        layout=input.layout,
        device=input.device,
    )

    for j in range(1, len(axes.lower())):
        y = torch.zeros(
            [input.shape[0], 4],
            dtype=input.dtype,
            layout=input.layout,
            device=input.device,
        )

        r = torch.empty(
            [max(y.shape[0], z.shape[0]), 4],
            dtype=input.dtype,
            layout=input.layout,
            device=input.device,
        )

        match axes.lower()[j]:
            case "x":
                p = 0
            case "y":
                p = 1
            case "z":
                p = 2
            case _:
                raise ValueError

        for k in range(input[:, j].shape[0]):
            y[k, 3] = torch.cos(input[:, j][k] / 2)
            y[k, p] = torch.sin(input[:, j][k] / 2)

        if intrinsic:
            for k in range(max(y.shape[0], z.shape[0])):
                c[0] = z[k, 1] * y[k, 2] - z[k, 2] * y[k, 1]
                c[1] = z[k, 2] * y[k, 0] - z[k, 0] * y[k, 2]
                c[2] = z[k, 0] * y[k, 1] - z[k, 1] * y[k, 0]

                t = z[k, 0]
                u = z[k, 1]
                v = z[k, 2]
                w = z[k, 3]

                r[k, 0] = w * y[k, 0] + y[k, 3] * t + c[0]
                r[k, 1] = w * y[k, 1] + y[k, 3] * u + c[1]
                r[k, 2] = w * y[k, 2] + y[k, 3] * v + c[2]
                r[k, 3] = w * y[k, 3] - t * y[k, 0] - u * y[k, 1] - v * y[k, 2]

            z = r
        else:
            for k in range(max(y.shape[0], z.shape[0])):
                c[0] = y[k, 1] * z[k, 2] - y[k, 2] * z[k, 1]
                c[1] = y[k, 2] * z[k, 0] - y[k, 0] * z[k, 2]
                c[2] = y[k, 0] * z[k, 1] - y[k, 1] * z[k, 0]

                t = z[k, 0]
                u = z[k, 1]
                v = z[k, 2]
                w = z[k, 3]

                r[k, 0] = y[k, 3] * t + w * y[k, 0] + c[0]
                r[k, 1] = y[k, 3] * u + w * y[k, 1] + c[1]
                r[k, 2] = y[k, 3] * v + w * y[k, 2] + c[2]
                r[k, 3] = y[k, 3] * w - y[k, 0] * t - y[k, 1] * u - y[k, 2] * v

            z = r

    if canonical:
        for j in range(z.shape[0]):
            a = z[j, 0]
            b = z[j, 1]
            c = z[j, 2]
            d = z[j, 3]

            if d == 0 and (a == 0 & (b == 0 & c < 0 | b < 0) | a < 0) | d < 0:
                z[j] = -z[j]

    return z

beignet.euler_angle_to_rotation_matrix

euler_angle_to_rotation_matrix(input, axes, degrees=False)

Convert Euler angles to rotation matrices.

Parameters:

Name Type Description Default
input Tensor, shape=(..., 3)

Euler angles.

required
axes str

Axes. One to three characters belonging to the set :math:\{X, Y, Z\} for intrinsic rotations, or :math:\{x, y, z\} for extrinsic rotations. Extrinsic and intrinsic rotations cannot be mixed.

required
degrees bool

If True, Euler angles are assumed to be in degrees. Default, False.

False

Returns:

Name Type Description
output Tensor, shape=(..., 3, 3)

Rotation matrices.

Source code in src/beignet/_euler_angle_to_rotation_matrix.py
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
def euler_angle_to_rotation_matrix(
    input: Tensor,
    axes: str,
    degrees: bool = False,
) -> Tensor:
    r"""
    Convert Euler angles to rotation matrices.

    Parameters
    ----------
    input : Tensor, shape=(..., 3)
        Euler angles.

    axes : str
        Axes. One to three characters belonging to the set :math:`\{X, Y, Z\}`
        for intrinsic rotations, or :math:`\{x, y, z\}` for extrinsic
        rotations. Extrinsic and intrinsic rotations cannot be mixed.

    degrees : bool, optional
        If `True`, Euler angles are assumed to be in degrees. Default, `False`.

    Returns
    -------
    output : Tensor, shape=(..., 3, 3)
        Rotation matrices.
    """
    if degrees:
        input = torch.deg2rad(input)

    output = torch.empty(
        [input.shape[0], 3, 3],
        dtype=input.dtype,
        layout=input.layout,
        device=input.device,
    )

    for j, axis in enumerate(axes):
        a = torch.cos(input[..., j])
        b = torch.sin(input[..., j])

        p = torch.full_like(a, 1.0)
        q = torch.full_like(a, 0.0)

        match axis.lower():
            case "x":
                x = [
                    torch.stack([+p, +q, +q], dim=-1),
                    torch.stack([+q, +a, -b], dim=-1),
                    torch.stack([+q, +b, +a], dim=-1),
                ]
            case "y":
                x = [
                    torch.stack([+a, +q, +b], dim=-1),
                    torch.stack([+q, +p, +q], dim=-1),
                    torch.stack([-b, +q, +a], dim=-1),
                ]
            case "z":
                x = [
                    torch.stack([+a, -b, +q], dim=-1),
                    torch.stack([+b, +a, +q], dim=-1),
                    torch.stack([+q, +q, +p], dim=-1),
                ]
            case _:
                raise ValueError

        x = torch.stack(x, dim=-2)

        if j == 0:
            output = x
        else:
            if axes.islower():
                output = x @ output
            else:
                output = output @ x

    return output

beignet.euler_angle_to_rotation_vector

euler_angle_to_rotation_vector(input, axes, degrees=False)

Convert Euler angles to rotation vectors.

Parameters:

Name Type Description Default
input Tensor, shape=(..., 3)

Euler angles.

required
axes str

Axes. One to three characters belonging to the set :math:\{X, Y, Z\} for intrinsic rotations, or :math:\{x, y, z\} for extrinsic rotations. Extrinsic and intrinsic rotations cannot be mixed.

required
degrees bool

If True, Euler angles are assumed to be in degrees and returned rotation vector magnitudes are in degrees. Default, False.

False

Returns:

Name Type Description
output Tensor, shape=(..., 3)

Rotation vectors.

Source code in src/beignet/_euler_angle_to_rotation_vector.py
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
def euler_angle_to_rotation_vector(
    input: Tensor,
    axes: str,
    degrees: bool = False,
) -> Tensor:
    r"""
    Convert Euler angles to rotation vectors.

    Parameters
    ----------
    input : Tensor, shape=(..., 3)
        Euler angles.

    axes : str
        Axes. One to three characters belonging to the set :math:`\{X, Y, Z\}`
        for intrinsic rotations, or :math:`\{x, y, z\}` for extrinsic
        rotations. Extrinsic and intrinsic rotations cannot be mixed.

    degrees : bool, optional
        If `True`, Euler angles are assumed to be in degrees and returned
        rotation vector magnitudes are in degrees. Default, `False`.

    Returns
    -------
    output : Tensor, shape=(..., 3)
        Rotation vectors.
    """
    num_axes = len(axes)

    if num_axes < 1 or num_axes > 3:
        raise ValueError

    intrinsic = re.match(r"^[XYZ]{1,3}$", axes) is not None
    extrinsic = re.match(r"^[xyz]{1,3}$", axes) is not None

    if not (intrinsic or extrinsic):
        raise ValueError

    if any(axes[i] == axes[i + 1] for i in range(num_axes - 1)):
        raise ValueError

    if degrees:
        input = torch.deg2rad(input)

    if len(axes.lower()) == 1:
        match input.ndim:
            case 0:
                input = torch.reshape(input, [1, 1])
            case 1:
                input = input[:, None]
            case 2 if input.shape[-1] != 1:
                raise ValueError
            case _:
                raise ValueError

    else:
        if input.ndim not in [1, 2] or input.shape[-1] != len(axes.lower()):
            raise ValueError

        if input.ndim == 1:
            input = input[None, :]

    if input.ndim != 2 or input.shape[-1] != len(axes.lower()):
        raise ValueError

    x = torch.zeros(
        [input.shape[0], 4],
        dtype=input.dtype,
        layout=input.layout,
        device=input.device,
    )

    match axes.lower()[0]:
        case "x":
            m = 0
        case "y":
            m = 1
        case "z":
            m = 2
        case _:
            raise ValueError

    for j in range(input[:, 0].shape[0]):
        x[j, 3] = torch.cos(input[:, 0][j] / 2)
        x[j, m] = torch.sin(input[:, 0][j] / 2)

    for j in range(1, len(axes)):
        y = torch.zeros(
            [input.shape[0], 4],
            dtype=input.dtype,
            layout=input.layout,
            device=input.device,
        )

        z = torch.empty(
            [max(y.shape[0], x.shape[0]), 4],
            dtype=input.dtype,
            layout=input.layout,
            device=input.device,
        )

        match axes.lower()[j]:
            case "x":
                m = 0
            case "y":
                m = 1
            case "z":
                m = 2
            case _:
                raise ValueError

        for k in range(input[:, j].shape[0]):
            y[k, 3] = torch.cos(input[:, j][k] / 2)
            y[k, m] = torch.sin(input[:, j][k] / 2)

        if intrinsic:
            if x.shape[0] == 1:
                for k in range(max(x.shape[0], y.shape[0])):
                    q = y[k, 1]
                    r = y[k, 2]
                    s = y[k, 3]
                    p = y[k, 0]

                    t = x[0, 0]
                    u = x[0, 1]
                    v = x[0, 2]
                    w = x[0, 3]

                    z[k, 0] = w * p + s * t + u * r - v * q
                    z[k, 1] = w * q + s * u + v * p - t * r
                    z[k, 2] = w * r + s * v + t * q - u * p
                    z[k, 3] = w * s - t * p - u * q - v * r
            elif y.shape[0] == 1:
                for k in range(max(x.shape[0], y.shape[0])):
                    p = y[0, 0]
                    q = y[0, 1]
                    r = y[0, 2]
                    s = y[0, 3]

                    t = x[k, 0]
                    u = x[k, 1]
                    v = x[k, 2]
                    w = x[k, 3]

                    z[k, 0] = w * p + s * t + u * r - v * q
                    z[k, 1] = w * q + s * u + v * p - t * r
                    z[k, 2] = w * r + s * v + t * q - u * p
                    z[k, 3] = w * s - t * p - u * q - v * r
            else:
                for k in range(max(x.shape[0], y.shape[0])):
                    p = y[k, 0]
                    q = y[k, 1]
                    r = y[k, 2]
                    s = y[k, 3]

                    t = x[k, 0]
                    u = x[k, 1]
                    v = x[k, 2]
                    w = x[k, 3]

                    z[k, 0] = w * p + s * t + u * r - v * q
                    z[k, 1] = w * q + s * u + v * p - t * r
                    z[k, 2] = w * r + s * v + t * q - u * p
                    z[k, 3] = w * s - t * p - u * q - v * r

            x = z
        else:
            if y.shape[0] == 1:
                for k in range(max(y.shape[0], x.shape[0])):
                    p = y[0, 0]
                    q = y[0, 1]
                    r = y[0, 2]
                    s = y[0, 3]

                    t = x[k, 0]
                    u = x[k, 1]
                    v = x[k, 2]
                    w = x[k, 3]

                    z[k, 0] = s * t + w * p + q * v - r * u
                    z[k, 1] = s * u + w * q + r * t - p * v
                    z[k, 2] = s * v + w * r + p * u - q * t
                    z[k, 3] = s * w - p * t - q * u - r * v
            elif x.shape[0] == 1:
                for k in range(max(y.shape[0], x.shape[0])):
                    t = x[0, 0]
                    u = x[0, 1]
                    v = x[0, 2]
                    w = x[0, 3]

                    p = y[k, 0]
                    q = y[k, 1]
                    r = y[k, 2]
                    s = y[k, 3]

                    z[k, 0] = s * t + w * p + q * v - r * u
                    z[k, 1] = s * u + w * q + r * t - p * v
                    z[k, 2] = s * v + w * r + p * u - q * t
                    z[k, 3] = s * w - p * t - q * u - r * v
            else:
                for k in range(max(y.shape[0], x.shape[0])):
                    p = y[k, 0]
                    q = y[k, 1]
                    r = y[k, 2]
                    s = y[k, 3]

                    t = x[k, 0]
                    u = x[k, 1]
                    v = x[k, 2]
                    w = x[k, 3]

                    z[k, 0] = s * t + w * p + q * v - r * u
                    z[k, 1] = s * u + w * q + r * t - p * v
                    z[k, 2] = s * v + w * r + p * u - q * t
                    z[k, 3] = s * w - p * t - q * u - r * v

            x = z

    output = torch.empty(
        [x.shape[0], 3],
        dtype=input.dtype,
        layout=input.layout,
        device=input.device,
    )

    for j in range(x.shape[0]):
        a = x[j, 0]
        b = x[j, 1]
        c = x[j, 2]
        d = x[j, 3]

        if d == 0 and (a == 0 and (b == 0 and c < 0 or b < 0) or a < 0) or d < 0:
            x[j] = -x[j]

        y = 2.0 * torch.atan2(torch.sqrt(a**2.0 + b**2.0 + c**2.0), d**1.0)

        if y < 0.001:
            y = 2.0 + y**2.0 / 12.0 + 7.0 * y**2.0 * y**2.0 / 2880.0
        else:
            y = y / torch.sin(y / 2.0)

        output[j] = x[j, :-1] * y

    if degrees:
        output = torch.rad2deg(output)

    return output

beignet.invert_euler_angle

invert_euler_angle(input, axes, degrees=False)

Invert Euler angles.

Parameters:

Name Type Description Default
input (Tensor, shape(..., 3))

Euler angles.

required
axes str

Axes. 1-3 characters belonging to the set {‘X’, ‘Y’, ‘Z’} for intrinsic rotations, or {‘x’, ‘y’, ‘z’} for extrinsic rotations. Extrinsic and intrinsic rotations cannot be mixed.

required
degrees bool

If True, Euler angles are assumed to be in degrees. Default, False.

False

Returns:

Name Type Description
inverted_euler_angles (Tensor, shape(..., 3))

Inverted Euler angles.

Source code in src/beignet/_invert_euler_angle.py
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
def invert_euler_angle(
    input: Tensor,
    axes: str,
    degrees: bool | None = False,
) -> Tensor:
    r"""
    Invert Euler angles.

    Parameters
    ----------
    input : Tensor, shape (..., 3)
        Euler angles.

    axes : str
        Axes. 1-3 characters belonging to the set {‘X’, ‘Y’, ‘Z’} for intrinsic
        rotations, or {‘x’, ‘y’, ‘z’} for extrinsic rotations. Extrinsic and
        intrinsic rotations cannot be mixed.

    degrees : bool, optional
        If `True`, Euler angles are assumed to be in degrees. Default, `False`.

    Returns
    -------
    inverted_euler_angles : Tensor, shape (..., 3)
        Inverted Euler angles.
    """
    return quaternion_to_euler_angle(
        invert_quaternion(
            euler_angle_to_quaternion(
                input,
                axes,
                degrees,
            ),
        ),
        axes,
        degrees,
    )

beignet.invert_quaternion

invert_quaternion(input, canonical=False)

Invert rotation quaternions.

Parameters:

Name Type Description Default
input (Tensor, shape(..., 4))

Rotation quaternions. Rotation quaternions are normalized to unit norm.

required
canonical bool

Whether to map the redundant double cover of rotation space to a unique canonical single cover. If True, then the rotation quaternion is chosen from :math:{q, -q} such that the :math:w term is positive. If the :math:w term is :math:0, then the rotation quaternion is chosen such that the first non-zero term of the :math:x, :math:y, and :math:z terms is positive.

False

Returns:

Name Type Description
inverted_quaternions (Tensor, shape(..., 4))

Inverted rotation quaternions.

Source code in src/beignet/_invert_quaternion.py
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
def invert_quaternion(
    input: Tensor,
    canonical: bool = False,
) -> Tensor:
    r"""
    Invert rotation quaternions.

    Parameters
    ----------
    input : Tensor, shape (..., 4)
        Rotation quaternions. Rotation quaternions are normalized to unit norm.

    canonical : bool, optional
        Whether to map the redundant double cover of rotation space to a unique
        canonical single cover. If `True`, then the rotation quaternion is
        chosen from :math:`{q, -q}` such that the :math:`w` term is positive.
        If the :math:`w` term is :math:`0`, then the rotation quaternion is
        chosen such that the first non-zero term of the :math:`x`, :math:`y`,
        and :math:`z` terms is positive.

    Returns
    -------
    inverted_quaternions : Tensor, shape (..., 4)
        Inverted rotation quaternions.
    """
    input[:, :3] = -input[:, :3]

    return input

beignet.invert_rotation_matrix

invert_rotation_matrix(input)

Invert rotation matrices.

Parameters:

Name Type Description Default
input (Tensor, shape(..., 3, 3))

Rotation matrices.

required

Returns:

Name Type Description
inverted_rotation_matrices (Tensor, shape(..., 3, 3))

Inverted rotation matrices.

Source code in src/beignet/_invert_rotation_matrix.py
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
def invert_rotation_matrix(input: Tensor) -> Tensor:
    r"""
    Invert rotation matrices.

    Parameters
    ----------
    input : Tensor, shape (..., 3, 3)
        Rotation matrices.

    Returns
    -------
    inverted_rotation_matrices : Tensor, shape (..., 3, 3)
        Inverted rotation matrices.
    """
    return torch.transpose(input, -2, -1)

beignet.invert_rotation_vector

invert_rotation_vector(input)

Invert rotation vectors.

Parameters:

Name Type Description Default
input (Tensor, shape(..., 3))

Rotation vectors.

required

Returns:

Name Type Description
inverted_rotation_vectors (Tensor, shape(..., 3))

Inverted rotation vectors.

Source code in src/beignet/_invert_rotation_vector.py
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
def invert_rotation_vector(
    input: Tensor,
) -> Tensor:
    r"""
    Invert rotation vectors.

    Parameters
    ----------
    input : Tensor, shape (..., 3)
        Rotation vectors.

    Returns
    -------
    inverted_rotation_vectors : Tensor, shape (..., 3)
        Inverted rotation vectors.
    """
    return -input

beignet.lennard_jones_potential

lennard_jones_potential(input, sigma, epsilon)

Lennard-Jones potential.

Parameters:

Name Type Description Default
input Tensor, shape=(n, m)

Pairwise distances between particles.

required
sigma float | Tensor, shape=(n, m)

Distance where the potential energy, :math:V, is zero.

required
epsilon float | Tensor, shape=(n, m)

Depth of the potential well.

required

Returns:

Name Type Description
output Tensor, shape=(n, m)

Energies.

Source code in src/beignet/_lennard_jones_potential.py
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
def lennard_jones_potential(
    input: Tensor,
    sigma: float | Tensor,
    epsilon: float | Tensor,
) -> Tensor:
    r"""
    Lennard-Jones potential.

    Parameters
    ----------
    input : Tensor, shape=(n, m)
        Pairwise distances between particles.

    sigma : float | Tensor, shape=(n, m)
        Distance where the potential energy, :math:`V`, is zero.

    epsilon : float | Tensor, shape=(n, m)
        Depth of the potential well.

    Returns
    -------
    output : Tensor, shape=(n, m)
        Energies.
    """
    a = sigma / input

    b = a**6.0
    c = b**2.0

    return 4.0 * epsilon * (c - b)

beignet.quaternion_identity

quaternion_identity(size, canonical=False, *, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False)

Identity rotation quaternions.

Parameters:

Name Type Description Default
size int

Output size.

required
canonical bool

Whether to map the redundant double cover of rotation space to a unique canonical single cover. If True, then the rotation quaternion is chosen from :math:{q, -q} such that the :math:w term is positive. If the :math:w term is :math:0, then the rotation quaternion is chosen such that the first non-zero term of the :math:x, :math:y, and :math:z terms is positive.

False
out Tensor

Output tensor. Default, None.

None
dtype dtype

Type of the returned tensor. Default, global default.

None
layout layout

Layout of the returned tensor. Default, torch.strided.

strided
device device

Device of the returned tensor. Default, current device for the default tensor type.

None
requires_grad bool

Whether autograd records operations on the returned tensor. Default, False.

False

Returns:

Name Type Description
identity_quaternions (Tensor, shape(size, 4))

Identity rotation quaternions.

Source code in src/beignet/_quaternion_identity.py
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
def quaternion_identity(
    size: int,
    canonical: bool | None = False,
    *,
    out: Tensor | None = None,
    dtype: torch.dtype | None = None,
    layout: torch.layout | None = torch.strided,
    device: torch.device | None = None,
    requires_grad: bool | None = False,
) -> Tensor:
    r"""
    Identity rotation quaternions.

    Parameters
    ----------
    size : int
        Output size.

    canonical : bool, optional
        Whether to map the redundant double cover of rotation space to a unique
        canonical single cover. If `True`, then the rotation quaternion is
        chosen from :math:`{q, -q}` such that the :math:`w` term is positive.
        If the :math:`w` term is :math:`0`, then the rotation quaternion is
        chosen such that the first non-zero term of the :math:`x`, :math:`y`,
        and :math:`z` terms is positive.

    out : Tensor, optional
        Output tensor. Default, `None`.

    dtype : torch.dtype, optional
        Type of the returned tensor. Default, global default.

    layout : torch.layout, optional
        Layout of the returned tensor. Default, `torch.strided`.

    device : torch.device, optional
        Device of the returned tensor. Default, current device for the default
        tensor type.

    requires_grad : bool, optional
        Whether autograd records operations on the returned tensor. Default,
        `False`.

    Returns
    -------
    identity_quaternions : Tensor, shape (size, 4)
        Identity rotation quaternions.
    """
    rotation = torch.zeros(
        [size, 4],
        out=out,
        dtype=dtype,
        layout=layout,
        device=device,
        requires_grad=requires_grad,
    )

    rotation[:, 3] = 1.0

    return rotation

beignet.quaternion_magnitude

quaternion_magnitude(input, canonical=False)

Rotation quaternion magnitudes.

Parameters:

Name Type Description Default
input Tensor, shape=(..., 4)

Rotation quaternions.

required

Returns:

Name Type Description
output Tensor, shape=(...)

Angles in radians. Magnitudes will be in the range :math:[0, \pi].

Source code in src/beignet/_quaternion_magnitude.py
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
def quaternion_magnitude(input: Tensor, canonical=False) -> Tensor:
    r"""
    Rotation quaternion magnitudes.

    Parameters
    ----------
    input : Tensor, shape=(..., 4)
        Rotation quaternions.

    Returns
    -------
    output : Tensor, shape=(...)
        Angles in radians. Magnitudes will be in the range :math:`[0, \pi]`.
    """
    output = torch.empty(
        input.shape[0],
        dtype=input.dtype,
        layout=input.layout,
        device=input.device,
        requires_grad=input.requires_grad,
    )

    for j in range(input.shape[0]):
        a = input[j, 0]
        b = input[j, 1]
        c = input[j, 2]
        d = input[j, 3]

        x = torch.atan2(torch.sqrt(a**2 + b**2 + c**2), torch.abs(d))

        output[j] = x * 2.0

    return output

beignet.quaternion_mean

quaternion_mean(input, weight=None)

Mean rotation quaternions.

Parameters:

Name Type Description Default
input Tensor, shape=(..., 4)

Rotation quaternions. Rotation quaternions are normalized to unit norm.

required
weight Tensor, shape=(..., 4)

Relative importance of rotation quaternions.

None

Returns:

Name Type Description
output Tensor, shape=(..., 4)

Rotation quaternions mean.

Source code in src/beignet/_quaternion_mean.py
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
def quaternion_mean(
    input: Tensor,
    weight: Tensor | None = None,
) -> Tensor:
    r"""
    Mean rotation quaternions.

    Parameters
    ----------
    input : Tensor, shape=(..., 4)
        Rotation quaternions. Rotation quaternions are normalized to unit norm.

    weight : Tensor, shape=(..., 4), optional
        Relative importance of rotation quaternions.

    Returns
    -------
    output : Tensor, shape=(..., 4)
        Rotation quaternions mean.
    """
    if weight is None:
        weight = torch.ones(input.shape[0])

    _, output = torch.linalg.eigh((input.T * weight) @ input)

    output = output[:, -1]

    output = torch.unsqueeze(output, dim=0)

    return output

beignet.quaternion_slerp

quaternion_slerp(input, time, rotation)

Interpolate between two or more points on a sphere.

Unlike linear interpolation, which can result in changes in speed when interpolating between orientations or positions on a sphere, spherical linear interpolation ensures that the interpolation occurs at a constant rate and follows the shortest path on the surface of the sphere. The process is useful for rotations and orientation interpolation in three-dimensional spaces, smoothly transitioning between different orientations.

Mathematically, spherical linear interpolation interpolates between two points on a sphere using a parameter \(t\), where \(t = 0\) represents the start point and \(t = n\) represents the end point. For two rotation quaternions \(q_{1}\) and \(q_{2}\) representing the start and end orientations:

\[\text{slerp}(q_{1}, q_{2}; t) = q_{1}\frac{\sin((1 - t)\theta)}{\sin(\theta)} + q_{2}\frac{\sin(t\theta)}{\sin(\theta)}\]

where \(\theta\) is the angle between \(q_{1}\) and \(q_{2}\), and is computed using the dot product of \(q_{1}\) and \(q_{2}\). This formula ensures that the interpolation moves along the shortest path on the four-dimensional sphere of rotation quaternions, resulting in a smooth and constant-speed rotation.

Parameters:

Name Type Description Default
input (Tensor, shape(..., N))

Times.

required
time (Tensor, shape(..., N))

Times of the known rotations. At least 2 times must be specified.

required
rotation (Tensor, shape(..., N, 4))

Rotation quaternions. Rotation quaternions are normalized to unit norm.

required
Source code in src/beignet/_quaternion_slerp.py
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
def quaternion_slerp(
    input: Tensor,
    time: Tensor,
    rotation: Tensor,
) -> Tensor:
    r"""
    Interpolate between two or more points on a sphere.

    Unlike linear interpolation, which can result in changes in speed when
    interpolating between orientations or positions on a sphere, spherical
    linear interpolation ensures that the interpolation occurs at a constant
    rate and follows the shortest path on the surface of the sphere.
    The process is useful for rotations and orientation interpolation in
    three-dimensional spaces, smoothly transitioning between different
    orientations.

    Mathematically, spherical linear interpolation interpolates between two
    points on a sphere using a parameter $t$, where $t = 0$ represents the
    start point and $t = n$ represents the end point. For two rotation
    quaternions $q_{1}$ and $q_{2}$ representing the start and end
    orientations:

    $$\text{slerp}(q_{1}, q_{2}; t) = q_{1}\frac{\sin((1 - t)\theta)}{\sin(\theta)} + q_{2}\frac{\sin(t\theta)}{\sin(\theta)}$$

    where $\theta$ is the angle between $q_{1}$ and $q_{2}$, and is computed
    using the dot product of $q_{1}$ and $q_{2}$. This formula ensures that the
    interpolation moves along the shortest path on the four-dimensional sphere
    of rotation quaternions, resulting in a smooth and constant-speed rotation.

    Parameters
    ----------
    input : Tensor, shape (..., N)
        Times.

    time : Tensor, shape (..., N)
        Times of the known rotations. At least 2 times must be specified.

    rotation : Tensor, shape (..., N, 4)
        Rotation quaternions. Rotation quaternions are normalized to unit norm.
    """  # noqa: E501
    if time.shape[-1] != rotation.shape[-2]:
        raise ValueError

    output = torch.empty(
        [*input.shape, 4],
        dtype=input.dtype,
        layout=input.layout,
        device=input.device,
    )

    for index, t in enumerate(input):
        b = torch.min(torch.nonzero(torch.greater_equal(time, t)))

        if b > 0:
            a = b - 1
        else:
            a = b

        if time[b] == t or b == a:
            output[index] = rotation[b]

            continue

        p, q = time[a], time[b]

        r = (t - p) / (q - p)

        t = rotation[a]
        u = rotation[b]

        v = torch.dot(t, u)

        if v < 0.0:
            u = -u
            v = -v

        if v > 0.9995:
            z = (1.0 - r) * t + r * u
        else:
            x = torch.sqrt(1.0 - v**2.0)

            y = torch.atan2(x, v)

            z = t * torch.sin((1.0 - r) * y) / x + u * torch.sin(r * y) / x

        output[index] = z / torch.linalg.norm(z)

    return output

beignet.quaternion_to_euler_angle

quaternion_to_euler_angle(input, axes, degrees=False)

Convert rotation quaternions to Euler angles.

Parameters:

Name Type Description Default
input Tensor, shape=(..., 4)

Rotation quaternions. Rotation quaternions are normalized to unit norm.

required
axes str

Axes. 1-3 characters belonging to the set {‘X’, ‘Y’, ‘Z’} for intrinsic rotations, or {‘x’, ‘y’, ‘z’} for extrinsic rotations. Extrinsic and intrinsic rotations cannot be mixed.

required
degrees bool

If True, Euler angles are assumed to be in degrees. Default, False.

False

Returns:

Name Type Description
output Tensor, shape=(..., 3)

Euler angles. The returned Euler angles are in the range:

* First angle: :math:`(-180, 180]` degrees (inclusive)
* Second angle:
    * :math:`[-90, 90]` degrees if all axes are different
      (e.g., :math:`xyz`)
    * :math:`[0, 180]` degrees if first and third axes are the same
      (e.g., :math:`zxz`)
* Third angle: :math:`[-180, 180]` degrees (inclusive)
Source code in src/beignet/_quaternion_to_euler_angle.py
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
def quaternion_to_euler_angle(
    input: Tensor,
    axes: str,
    degrees: bool = False,
) -> Tensor:
    r"""
    Convert rotation quaternions to Euler angles.

    Parameters
    ----------
    input : Tensor, shape=(..., 4)
        Rotation quaternions. Rotation quaternions are normalized to unit norm.

    axes : str
        Axes. 1-3 characters belonging to the set {‘X’, ‘Y’, ‘Z’} for intrinsic
        rotations, or {‘x’, ‘y’, ‘z’} for extrinsic rotations. Extrinsic and
        intrinsic rotations cannot be mixed.

    degrees : bool, optional
        If `True`, Euler angles are assumed to be in degrees. Default, `False`.

    Returns
    -------
    output : Tensor, shape=(..., 3)
        Euler angles. The returned Euler angles are in the range:

            * First angle: :math:`(-180, 180]` degrees (inclusive)
            * Second angle:
                * :math:`[-90, 90]` degrees if all axes are different
                  (e.g., :math:`xyz`)
                * :math:`[0, 180]` degrees if first and third axes are the same
                  (e.g., :math:`zxz`)
            * Third angle: :math:`[-180, 180]` degrees (inclusive)
    """
    epsilon = torch.finfo(input.dtype).eps

    output = torch.empty(
        [input.shape[0], 3],
        dtype=input.dtype,
        layout=input.layout,
        device=input.device,
    )

    extrinsic = re.match(r"^[xyz]{1,3}$", axes) is not None

    axes = axes.lower()

    if not extrinsic:
        axes = axes[::-1]

    match axes[0]:
        case "x":
            p = 0
        case "y":
            p = 1
        case "z":
            p = 2
        case _:
            raise ValueError

    match axes[1]:
        case "x":
            q = 0
        case "y":
            q = 1
        case "z":
            q = 2
        case _:
            raise ValueError

    match axes[2]:
        case "x":
            r = 0
        case "y":
            r = 1
        case "z":
            r = 2
        case _:
            raise ValueError

    if p == r:
        r = 3 - p - q

    s = (p - q) * (q - r) * (r - p) // 2

    for j in range(input.shape[0]):
        if p == r:
            t = input[j, 3]
            u = input[j, p]
            v = input[j, q]
            w = input[j, r] * s
        else:
            t = input[j, 3] - input[j, q]
            u = input[j, p] + input[j, r] * s
            v = input[j, q] + input[j, 3]
            w = input[j, r] * s - input[j, p]

        if extrinsic:
            a = 0
            c = 2
        else:
            a = 2
            c = 0

        output[j, 1] = 2.0 * torch.atan2(torch.hypot(v, w), torch.hypot(t, u))

        match output[j, 1]:
            case _ if abs(output[j, 1]) < epsilon:
                output[j, 0] = 2.0 * torch.atan2(u, t)
                output[j, 2] = 0.0
            case _ if abs(output[j, 1] - math.pi) < epsilon:
                if extrinsic:
                    output[j, 0] = 2.0 * -torch.atan2(w, v)
                else:
                    output[j, 0] = 2.0 * +torch.atan2(w, v)

                output[j, 2] = 0.0
            case _:
                output[j, a] = torch.atan2(u, t) - torch.atan2(w, v)
                output[j, c] = torch.atan2(u, t) + torch.atan2(w, v)

        if not p == r:
            output[j, 1] = output[j, 1] - math.pi / 2.0
            output[j, c] = output[j, c] * s

        for k in range(3):
            if output[j, k] <= -math.pi:
                output[j, k] = output[j, k] + math.tau

            if output[j, k] >= +math.pi:
                output[j, k] = output[j, k] - math.tau

    if degrees:
        output = torch.rad2deg(output)

    return output

beignet.quaternion_to_rotation_matrix

quaternion_to_rotation_matrix(input)

Convert rotation quaternions to rotation matrices.

Parameters:

Name Type Description Default
input Tensor, shape=(..., 4)

Rotation quaternions. Rotation quaternions are normalized to unit norm.

required

Returns:

Name Type Description
output Tensor, shape=(..., 3, 3)

Rotation matrices.

Source code in src/beignet/_quaternion_to_rotation_matrix.py
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
def quaternion_to_rotation_matrix(input: Tensor) -> Tensor:
    r"""
    Convert rotation quaternions to rotation matrices.

    Parameters
    ----------
    input : Tensor, shape=(..., 4)
        Rotation quaternions. Rotation quaternions are normalized to unit norm.

    Returns
    -------
    output : Tensor, shape=(..., 3, 3)
        Rotation matrices.
    """
    output = torch.empty(
        [input.shape[0], 3, 3],
        dtype=input.dtype,
        layout=input.layout,
        device=input.device,
    )

    for j in range(input.shape[0]):
        a = input[j, 0]
        b = input[j, 1]
        c = input[j, 2]
        d = input[j, 3]

        output[j, 0, 0] = +(a**2.0) - b**2.0 - c**2.0 + d**2.0
        output[j, 1, 1] = -(a**2.0) + b**2.0 - c**2.0 + d**2.0
        output[j, 2, 2] = -(a**2.0) - b**2.0 + c**2.0 + d**2.0

        output[j, 0, 1] = 2.0 * (a * b) - 2.0 * (c * d)
        output[j, 0, 2] = 2.0 * (a * c) + 2.0 * (b * d)
        output[j, 1, 0] = 2.0 * (a * b) + 2.0 * (c * d)
        output[j, 1, 2] = 2.0 * (b * c) - 2.0 * (a * d)
        output[j, 2, 0] = 2.0 * (a * c) - 2.0 * (b * d)
        output[j, 2, 1] = 2.0 * (b * c) + 2.0 * (a * d)

    return output

beignet.quaternion_to_rotation_vector

quaternion_to_rotation_vector(input, degrees=False)

Convert rotation quaternions to rotation vectors.

Parameters:

Name Type Description Default
input Tensor, shape=(..., 4)

Rotation quaternions. Rotation quaternions are normalized to unit norm.

required
degrees bool
False

Returns:

Name Type Description
output Tensor, shape=(..., 3)

Rotation vectors.

Source code in src/beignet/_quaternion_to_rotation_vector.py
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
def quaternion_to_rotation_vector(
    input: Tensor,
    degrees: bool | None = False,
) -> Tensor:
    r"""
    Convert rotation quaternions to rotation vectors.

    Parameters
    ----------
    input : Tensor, shape=(..., 4)
        Rotation quaternions. Rotation quaternions are normalized to unit norm.

    degrees : bool, optional

    Returns
    -------
    output : Tensor, shape=(..., 3)
        Rotation vectors.
    """
    output = torch.empty(
        [input.shape[0], 3],
        dtype=input.dtype,
        layout=input.layout,
        device=input.device,
    )

    for j in range(input.shape[0]):
        a = input[j, 0]
        b = input[j, 1]
        c = input[j, 2]
        d = input[j, 3]

        if d == 0 and (a == 0 and (b == 0 and c < 0 or b < 0) or a < 0) or d < 0:
            input[j] = -input[j]

        t = input[j, 0] ** 2.0
        u = input[j, 1] ** 2.0
        v = input[j, 2] ** 2.0
        w = input[j, 3] ** 1.0

        y = 2.0 * torch.atan2(torch.sqrt(t + u + v), w)

        if y < 0.001:
            y = 2.0 + y**2.0 / 12 + 7 * y**2.0 * y**2.0 / 2880
        else:
            y = y / torch.sin(y / 2.0)

        output[j] = input[j, :-1] * y

    if degrees:
        output = torch.rad2deg(output)

    return output

beignet.random_euler_angle

random_euler_angle(size, axes, degrees=False, *, generator=None, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False, pin_memory=False)

Generate random Euler angles.

Parameters:

Name Type Description Default
size int

Output size.

required
axes str

Axes. 1-3 characters belonging to the set {‘X’, ‘Y’, ‘Z’} for intrinsic rotations, or {‘x’, ‘y’, ‘z’} for extrinsic rotations. Extrinsic and intrinsic rotations cannot be mixed.

required
degrees bool

If True, Euler angles are assumed to be in degrees. Default, False.

False
generator Generator

Psuedo-random number generator. Default, None.

None
out Tensor

Output tensor. Default, None.

None
dtype dtype

Type of the returned tensor. Default, global default.

None
layout layout

Layout of the returned tensor. Default, torch.strided.

strided
device device

Device of the returned tensor. Default, current device for the default tensor type.

None
requires_grad bool

Whether autograd records operations on the returned tensor. Default, False.

False
pin_memory bool

If True, returned tensor is allocated in pinned memory. Default, False.

False

Returns:

Name Type Description
random_euler_angles (Tensor, shape(..., 3))

Random Euler angles.

The returned Euler angles are in the range:

*   First angle: :math:`(-180, 180]` degrees (inclusive)
*   Second angle:
        *   :math:`[-90, 90]` degrees if all axes are different
            (e.g., :math:`xyz`)
        *   :math:`[0, 180]` degrees if first and third axes are
            the same (e.g., :math:`zxz`)
*   Third angle: :math:`[-180, 180]` degrees (inclusive)
Source code in src/beignet/_random_euler_angle.py
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
def random_euler_angle(
    size: int,
    axes: str,
    degrees: bool | None = False,
    *,
    generator: Generator | None = None,
    out: Tensor | None = None,
    dtype: torch.dtype | None = None,
    layout: torch.layout | None = torch.strided,
    device: torch.device | None = None,
    requires_grad: bool | None = False,
    pin_memory: bool | None = False,
) -> Tensor:
    r"""
    Generate random Euler angles.

    Parameters
    ----------
    size : int
        Output size.

    axes : str
        Axes. 1-3 characters belonging to the set {‘X’, ‘Y’, ‘Z’} for intrinsic
        rotations, or {‘x’, ‘y’, ‘z’} for extrinsic rotations. Extrinsic and
        intrinsic rotations cannot be mixed.

    degrees : bool, optional
        If `True`, Euler angles are assumed to be in degrees. Default, `False`.

    generator : torch.Generator, optional
        Psuedo-random number generator. Default, `None`.

    out : Tensor, optional
        Output tensor. Default, `None`.

    dtype : torch.dtype, optional
        Type of the returned tensor. Default, global default.

    layout : torch.layout, optional
        Layout of the returned tensor. Default, `torch.strided`.

    device : torch.device, optional
        Device of the returned tensor. Default, current device for the default
        tensor type.

    requires_grad : bool, optional
        Whether autograd records operations on the returned tensor. Default,
        `False`.

    pin_memory : bool, optional
        If `True`, returned tensor is allocated in pinned memory. Default,
        `False`.

    Returns
    -------
    random_euler_angles : Tensor, shape (..., 3)
        Random Euler angles.

        The returned Euler angles are in the range:

            *   First angle: :math:`(-180, 180]` degrees (inclusive)
            *   Second angle:
                    *   :math:`[-90, 90]` degrees if all axes are different
                        (e.g., :math:`xyz`)
                    *   :math:`[0, 180]` degrees if first and third axes are
                        the same (e.g., :math:`zxz`)
            *   Third angle: :math:`[-180, 180]` degrees (inclusive)
    """
    return quaternion_to_euler_angle(
        random_quaternion(
            size,
            generator=generator,
            out=out,
            dtype=dtype,
            layout=layout,
            device=device,
            requires_grad=requires_grad,
            pin_memory=pin_memory,
        ),
        axes,
        degrees,
    )

beignet.random_quaternion

random_quaternion(size, canonical=False, *, generator=None, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False, pin_memory=False)

Generate random rotation quaternions.

Parameters:

Name Type Description Default
size int

Output size.

required
canonical bool

Whether to map the redundant double cover of rotation space to a unique canonical single cover. If True, then the rotation quaternion is chosen from :math:{q, -q} such that the :math:w term is positive. If the :math:w term is :math:0, then the rotation quaternion is chosen such that the first non-zero term of the :math:x, :math:y, and :math:z terms is positive.

False
generator Generator

Psuedo-random number generator. Default, None.

None
out Tensor

Output tensor. Default, None.

None
dtype dtype

Type of the returned tensor. Default, global default.

None
layout layout

Layout of the returned tensor. Default, torch.strided.

strided
device device

Device of the returned tensor. Default, current device for the default tensor type.

None
requires_grad bool

Whether autograd records operations on the returned tensor. Default, False.

False
pin_memory bool

If True, returned tensor is allocated in pinned memory. Default, False.

False

Returns:

Name Type Description
random_quaternions (Tensor, shape(..., 4))

Random rotation quaternions.

Source code in src/beignet/_random_quaternion.py
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
def random_quaternion(
    size: int,
    canonical: bool = False,
    *,
    generator: Generator | None = None,
    out: Tensor | None = None,
    dtype: torch.dtype | None = None,
    layout: torch.layout | None = torch.strided,
    device: torch.device | None = None,
    requires_grad: bool | None = False,
    pin_memory: bool | None = False,
) -> Tensor:
    r"""
    Generate random rotation quaternions.

    Parameters
    ----------
    size : int
        Output size.

    canonical : bool, optional
        Whether to map the redundant double cover of rotation space to a unique
        canonical single cover. If `True`, then the rotation quaternion is
        chosen from :math:`{q, -q}` such that the :math:`w` term is positive.
        If the :math:`w` term is :math:`0`, then the rotation quaternion is
        chosen such that the first non-zero term of the :math:`x`, :math:`y`,
        and :math:`z` terms is positive.

    generator : torch.Generator, optional
        Psuedo-random number generator. Default, `None`.

    out : Tensor, optional
        Output tensor. Default, `None`.

    dtype : torch.dtype, optional
        Type of the returned tensor. Default, global default.

    layout : torch.layout, optional
        Layout of the returned tensor. Default, `torch.strided`.

    device : torch.device, optional
        Device of the returned tensor. Default, current device for the default
        tensor type.

    requires_grad : bool, optional
        Whether autograd records operations on the returned tensor. Default,
        `False`.

    pin_memory : bool, optional
        If `True`, returned tensor is allocated in pinned memory. Default,
        `False`.

    Returns
    -------
    random_quaternions : Tensor, shape (..., 4)
        Random rotation quaternions.
    """
    quaternions = torch.rand(
        [size, 4],
        generator=generator,
        out=out,
        dtype=dtype,
        layout=layout,
        device=device,
        requires_grad=requires_grad,
        pin_memory=pin_memory,
    )

    if canonical:
        for index in range(quaternions.size(0)):
            if (
                (quaternions[index][3] < 0)
                or (quaternions[index][3] == 0 and quaternions[index][0] < 0)
                or (
                    quaternions[index][3] == 0
                    and quaternions[index][0] == 0
                    and quaternions[index][1] < 0
                )
                or (
                    quaternions[index][3] == 0
                    and quaternions[index][0] == 0
                    and quaternions[index][1] == 0
                    and quaternions[index][2] < 0
                )
            ):
                quaternions[index][0] *= -1.0
                quaternions[index][1] *= -1.0
                quaternions[index][2] *= -1.0
                quaternions[index][3] *= -1.0

    return quaternions

beignet.random_rotation_matrix

random_rotation_matrix(size, *, generator=None, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False, pin_memory=False)

Generate random rotation matrices.

Parameters:

Name Type Description Default
size int

Output size.

required
generator Generator

Psuedo-random number generator. Default, None.

None
out Tensor

Output tensor. Default, None.

None
dtype dtype

Type of the returned tensor. Default, global default.

None
layout layout

Layout of the returned tensor. Default, torch.strided.

strided
device device

Device of the returned tensor. Default, current device for the default tensor type.

None
requires_grad bool

Whether autograd records operations on the returned tensor. Default, False.

False
pin_memory bool

If True, returned tensor is allocated in pinned memory. Default, False.

False

Returns:

Name Type Description
random_rotation_matrices (Tensor, shape(..., 3, 3))

Random rotation matrices.

Source code in src/beignet/_random_rotation_matrix.py
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
def random_rotation_matrix(
    size: int,
    *,
    generator: Generator | None = None,
    out: Tensor | None = None,
    dtype: torch.dtype | None = None,
    layout: torch.layout | None = torch.strided,
    device: torch.device | None = None,
    requires_grad: bool | None = False,
    pin_memory: bool | None = False,
) -> Tensor:
    r"""
    Generate random rotation matrices.

    Parameters
    ----------
    size : int
        Output size.

    generator : torch.Generator, optional
        Psuedo-random number generator. Default, `None`.

    out : Tensor, optional
        Output tensor. Default, `None`.

    dtype : torch.dtype, optional
        Type of the returned tensor. Default, global default.

    layout : torch.layout, optional
        Layout of the returned tensor. Default, `torch.strided`.

    device : torch.device, optional
        Device of the returned tensor. Default, current device for the default
        tensor type.

    requires_grad : bool, optional
        Whether autograd records operations on the returned tensor. Default,
        `False`.

    pin_memory : bool, optional
        If `True`, returned tensor is allocated in pinned memory. Default,
        `False`.

    Returns
    -------
    random_rotation_matrices : Tensor, shape (..., 3, 3)
        Random rotation matrices.
    """
    return quaternion_to_rotation_matrix(
        random_quaternion(
            size,
            generator=generator,
            out=out,
            dtype=dtype,
            layout=layout,
            device=device,
            requires_grad=requires_grad,
            pin_memory=pin_memory,
        ),
    )

beignet.random_rotation_vector

random_rotation_vector(size, degrees=False, *, generator=None, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False, pin_memory=False)

Generate random rotation vectors.

Parameters:

Name Type Description Default
size int

Output size.

required
degrees bool
False
generator Generator

Psuedo-random number generator. Default, None.

None
out Tensor

Output tensor. Default, None.

None
dtype dtype

Type of the returned tensor. Default, global default.

None
layout layout

Layout of the returned tensor. Default, torch.strided.

strided
device device

Device of the returned tensor. Default, current device for the default tensor type.

None
requires_grad bool

Whether autograd records operations on the returned tensor. Default, False.

False
pin_memory bool

If True, returned tensor is allocated in pinned memory. Default, False.

False

Returns:

Name Type Description
random_rotation_vectors (Tensor, shape(..., 3))

Random rotation vectors.

Source code in src/beignet/_random_rotation_vector.py
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
def random_rotation_vector(
    size: int,
    degrees: bool = False,
    *,
    generator: Generator | None = None,
    out: Tensor | None = None,
    dtype: torch.dtype | None = None,
    layout: torch.layout | None = torch.strided,
    device: torch.device | None = None,
    requires_grad: bool | None = False,
    pin_memory: bool | None = False,
) -> Tensor:
    r"""
    Generate random rotation vectors.

    Parameters
    ----------
    size : int
        Output size.

    degrees

    generator : torch.Generator, optional
        Psuedo-random number generator. Default, `None`.

    out : Tensor, optional
        Output tensor. Default, `None`.

    dtype : torch.dtype, optional
        Type of the returned tensor. Default, global default.

    layout : torch.layout, optional
        Layout of the returned tensor. Default, `torch.strided`.

    device : torch.device, optional
        Device of the returned tensor. Default, current device for the default
        tensor type.

    requires_grad : bool, optional
        Whether autograd records operations on the returned tensor. Default,
        `False`.

    pin_memory : bool, optional
        If `True`, returned tensor is allocated in pinned memory. Default,
        `False`.

    Returns
    -------
    random_rotation_vectors : Tensor, shape (..., 3)
        Random rotation vectors.
    """
    return quaternion_to_rotation_vector(
        random_quaternion(
            size,
            generator=generator,
            out=out,
            dtype=dtype,
            layout=layout,
            device=device,
            requires_grad=requires_grad,
            pin_memory=pin_memory,
        ),
        degrees,
    )

beignet.rotation_matrix_identity

rotation_matrix_identity(size, *, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False)

Identity rotation matrices.

Parameters:

Name Type Description Default
size int

Output size.

required
out Tensor

Output tensor. Default, None.

None
dtype dtype

Type of the returned tensor. Default, global default.

None
layout layout

Layout of the returned tensor. Default, torch.strided.

strided
device device

Device of the returned tensor. Default, current device for the default tensor type.

None
requires_grad bool

Whether autograd records operations on the returned tensor. Default, False.

False

Returns:

Name Type Description
identity_rotation_matrices (Tensor, shape(size, 3, 3))

Identity rotation matrices.

Source code in src/beignet/_rotation_matrix_identity.py
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
def rotation_matrix_identity(
    size: int,
    *,
    out: Tensor | None = None,
    dtype: torch.dtype | None = None,
    layout: torch.layout | None = torch.strided,
    device: torch.device | None = None,
    requires_grad: bool | None = False,
) -> Tensor:
    r"""
    Identity rotation matrices.

    Parameters
    ----------
    size : int
        Output size.

    out : Tensor, optional
        Output tensor. Default, `None`.

    dtype : torch.dtype, optional
        Type of the returned tensor. Default, global default.

    layout : torch.layout, optional
        Layout of the returned tensor. Default, `torch.strided`.

    device : torch.device, optional
        Device of the returned tensor. Default, current device for the default
        tensor type.

    requires_grad : bool, optional
        Whether autograd records operations on the returned tensor. Default,
        `False`.

    Returns
    -------
    identity_rotation_matrices : Tensor, shape (size, 3, 3)
        Identity rotation matrices.
    """
    return quaternion_to_rotation_matrix(
        quaternion_identity(
            size,
            out=out,
            dtype=dtype,
            layout=layout,
            device=device,
            requires_grad=requires_grad,
        ),
    )

beignet.rotation_matrix_magnitude

rotation_matrix_magnitude(input)

Rotation matrix magnitudes.

Parameters:

Name Type Description Default
input (Tensor, shape(..., 3, 3))

Rotation matrices.

required

Returns:

Name Type Description
rotation_matrix_magnitudes (Tensor, shape(...))

Angles in radians. Magnitudes will be in the range :math:[0, \pi].

Source code in src/beignet/_rotation_matrix_magnitude.py
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
def rotation_matrix_magnitude(input: Tensor) -> Tensor:
    r"""
    Rotation matrix magnitudes.

    Parameters
    ----------
    input : Tensor, shape (..., 3, 3)
        Rotation matrices.

    Returns
    -------
    rotation_matrix_magnitudes: Tensor, shape (...)
        Angles in radians. Magnitudes will be in the range :math:`[0, \pi]`.
    """
    return quaternion_magnitude(
        rotation_matrix_to_quaternion(
            input,
        ),
    )

beignet.rotation_matrix_mean

rotation_matrix_mean(input, weight=None)

Parameters:

Name Type Description Default
input Tensor, shape=(..., 3, 3)

Rotation matrices.

required
weight Tensor, shape=(..., 4)

Relative importance of rotation matrices.

None

Returns:

Name Type Description
output Tensor, shape=(..., 3, 3)
Source code in src/beignet/_rotation_matrix_mean.py
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
def rotation_matrix_mean(
    input: Tensor,
    weight: Tensor | None = None,
) -> Tensor:
    r"""
    Parameters
    ----------
    input : Tensor, shape=(..., 3, 3)
        Rotation matrices.

    weight : Tensor, shape=(..., 4), optional
        Relative importance of rotation matrices.

    Returns
    -------
    output : Tensor, shape=(..., 3, 3)
    """
    return quaternion_to_rotation_matrix(
        quaternion_mean(
            rotation_matrix_to_quaternion(
                input,
            ),
            weight,
        ),
    )

beignet.rotation_matrix_to_euler_angle

rotation_matrix_to_euler_angle(input, axes, degrees=False)

Convert rotation matrices to Euler angles.

Parameters:

Name Type Description Default
input (Tensor, shape(..., 3, 3))

Rotation matrices.

required
axes str

Axes. 1-3 characters belonging to the set {‘X’, ‘Y’, ‘Z’} for intrinsic rotations, or {‘x’, ‘y’, ‘z’} for extrinsic rotations. Extrinsic and intrinsic rotations cannot be mixed.

required
degrees bool

If True, Euler angles are assumed to be in degrees. Default, False.

False

Returns:

Name Type Description
euler_angles (Tensor, shape(..., 3))

Euler angles. The returned Euler angles are in the range:

* First angle: :math:`(-180, 180]` degrees (inclusive)
* Second angle:
    * :math:`[-90, 90]` degrees if all axes are different
      (e.g., :math:`xyz`)
    * :math:`[0, 180]` degrees if first and third axes are the same
      (e.g., :math:`zxz`)
* Third angle: :math:`[-180, 180]` degrees (inclusive)
Source code in src/beignet/_rotation_matrix_to_euler_angle.py
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
def rotation_matrix_to_euler_angle(
    input: Tensor,
    axes: str,
    degrees: bool = False,
) -> Tensor:
    r"""
    Convert rotation matrices to Euler angles.

    Parameters
    ----------
    input : Tensor, shape (..., 3, 3)
        Rotation matrices.

    axes : str
        Axes. 1-3 characters belonging to the set {‘X’, ‘Y’, ‘Z’} for intrinsic
        rotations, or {‘x’, ‘y’, ‘z’} for extrinsic rotations. Extrinsic and
        intrinsic rotations cannot be mixed.

    degrees : bool, optional
        If `True`, Euler angles are assumed to be in degrees. Default, `False`.

    Returns
    -------
    euler_angles : Tensor, shape (..., 3)
        Euler angles. The returned Euler angles are in the range:

            * First angle: :math:`(-180, 180]` degrees (inclusive)
            * Second angle:
                * :math:`[-90, 90]` degrees if all axes are different
                  (e.g., :math:`xyz`)
                * :math:`[0, 180]` degrees if first and third axes are the same
                  (e.g., :math:`zxz`)
            * Third angle: :math:`[-180, 180]` degrees (inclusive)
    """
    return quaternion_to_euler_angle(
        rotation_matrix_to_quaternion(
            input,
        ),
        axes,
        degrees,
    )

beignet.rotation_matrix_to_quaternion

rotation_matrix_to_quaternion(input, canonical=False)

Convert rotation matrices to rotation quaternions.

Parameters:

Name Type Description Default
input Tensor, shape=(..., 3, 3)

Rotation matrices.

required
canonical bool

Whether to map the redundant double cover of rotation space to a unique canonical single cover. If True, then the rotation quaternion is chosen from :math:{q, -q} such that the :math:w term is positive. If the :math:w term is :math:0, then the rotation quaternion is chosen such that the first non-zero term of the :math:x, :math:y, and :math:z terms is positive.

False

Returns:

Name Type Description
output Tensor, shape=(..., 4)

Rotation quaternion.

Source code in src/beignet/_rotation_matrix_to_quaternion.py
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
def rotation_matrix_to_quaternion(
    input: Tensor,
    canonical: bool | None = False,
) -> Tensor:
    r"""
    Convert rotation matrices to rotation quaternions.

    Parameters
    ----------
    input : Tensor, shape=(..., 3, 3)
        Rotation matrices.

    canonical : bool, optional
        Whether to map the redundant double cover of rotation space to a unique
        canonical single cover. If `True`, then the rotation quaternion is
        chosen from :math:`{q, -q}` such that the :math:`w` term is positive.
        If the :math:`w` term is :math:`0`, then the rotation quaternion is
        chosen such that the first non-zero term of the :math:`x`, :math:`y`,
        and :math:`z` terms is positive.

    Returns
    -------
    output : Tensor, shape=(..., 4)
        Rotation quaternion.
    """
    indexes = torch.empty(
        [4],
        dtype=input.dtype,
        layout=input.layout,
        device=input.device,
    )

    output = torch.empty(
        [input.shape[0], 4],
        dtype=input.dtype,
        layout=input.layout,
        device=input.device,
    )

    for j in range(input.shape[0]):
        indexes[0] = input[j, 0, 0]
        indexes[1] = input[j, 1, 1]
        indexes[2] = input[j, 2, 2]
        indexes[3] = input[j, 0, 0] + input[j, 1, 1] + input[j, 2, 2]

        index, maximum = 0, indexes[0]

        for k in range(1, 4):
            if indexes[k] > maximum:
                index, maximum = k, indexes[k]

        if index == 3:
            output[j, 0] = input[j, 2, 1] - input[j, 1, 2]
            output[j, 1] = input[j, 0, 2] - input[j, 2, 0]
            output[j, 2] = input[j, 1, 0] - input[j, 0, 1]
            output[j, 3] = 1.0 + indexes[3]
        else:
            t = index
            u = (t + 1) % 3
            v = (u + 1) % 3

            output[j, t] = 1.0 - indexes[3] + 2.0 * input[j, t, t]
            output[j, u] = input[j, u, t] + input[j, t, u]
            output[j, v] = input[j, v, t] + input[j, t, v]
            output[j, 3] = input[j, v, u] - input[j, u, v]

        a = output[j, 0] ** 2.0
        b = output[j, 1] ** 2.0
        c = output[j, 2] ** 2.0
        d = output[j, 3] ** 2.0

        output[j] = output[j] / torch.sqrt(a + b + c + d)

    if canonical:
        for j in range(output.shape[0]):
            a = output[j, 0]
            b = output[j, 1]
            c = output[j, 2]
            d = output[j, 3]

            if d == 0 and (a == 0 & (b == 0 & c < 0 | b < 0) | a < 0) | d < 0:
                output[j] = -output[j]

    return output

beignet.rotation_matrix_to_rotation_vector

rotation_matrix_to_rotation_vector(input, degrees=False)

Convert rotation matrices to rotation vectors.

Parameters:

Name Type Description Default
input Tensor, shape=(..., 3, 3)

Rotation matrices.

required
degrees bool

If True, rotation vector magnitudes are assumed to be in degrees. Default, False.

False

Returns:

Name Type Description
output Tensor, shape=(..., 3)

Rotation vectors.

Source code in src/beignet/_rotation_matrix_to_rotation_vector.py
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
def rotation_matrix_to_rotation_vector(
    input: Tensor,
    degrees: bool = False,
) -> Tensor:
    r"""
    Convert rotation matrices to rotation vectors.

    Parameters
    ----------
    input : Tensor, shape=(..., 3, 3)
        Rotation matrices.

    degrees : bool
        If `True`, rotation vector magnitudes are assumed to be in degrees.
        Default, `False`.

    Returns
    -------
    output : Tensor, shape=(..., 3)
        Rotation vectors.
    """
    return quaternion_to_rotation_vector(
        rotation_matrix_to_quaternion(
            input,
        ),
        degrees,
    )

beignet.rotation_vector_identity

rotation_vector_identity(size, degrees=False, *, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False)

Identity rotation vectors.

Parameters:

Name Type Description Default
size int

Output size.

required
degrees bool

If True, rotation vector magnitudes are assumed to be in degrees. Default, False.

False
out Tensor

Output tensor. Default, None.

None
dtype dtype

Type of the returned tensor. Default, global default.

None
layout layout

Layout of the returned tensor. Default, torch.strided.

strided
device device

Device of the returned tensor. Default, current device for the default tensor type.

None
requires_grad bool

Whether autograd records operations on the returned tensor. Default, False.

False

Returns:

Name Type Description
identity_rotation_vectors (Tensor, shape(size, 3))

Identity rotation vectors.

Source code in src/beignet/_rotation_vector_identity.py
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
def rotation_vector_identity(
    size: int,
    degrees: bool = False,
    *,
    out: Tensor | None = None,
    dtype: torch.dtype | None = None,
    layout: torch.layout | None = torch.strided,
    device: torch.device | None = None,
    requires_grad: bool | None = False,
) -> Tensor:
    r"""
    Identity rotation vectors.

    Parameters
    ----------
    size : int
        Output size.

    degrees : bool
        If `True`, rotation vector magnitudes are assumed to be in degrees.
        Default, `False`.

    out : Tensor, optional
        Output tensor. Default, `None`.

    dtype : torch.dtype, optional
        Type of the returned tensor. Default, global default.

    layout : torch.layout, optional
        Layout of the returned tensor. Default, `torch.strided`.

    device : torch.device, optional
        Device of the returned tensor. Default, current device for the default
        tensor type.

    requires_grad : bool, optional
        Whether autograd records operations on the returned tensor. Default,
        `False`.

    Returns
    -------
    identity_rotation_vectors : Tensor, shape (size, 3)
        Identity rotation vectors.
    """
    return quaternion_to_rotation_vector(
        quaternion_identity(
            size,
            out=out,
            dtype=dtype,
            layout=layout,
            device=device,
            requires_grad=requires_grad,
        ),
        degrees,
    )

beignet.rotation_vector_magnitude

rotation_vector_magnitude(input, degrees=False)

Rotation vector magnitudes.

Parameters:

Name Type Description Default
input (Tensor, shape(..., 3))

Rotation vectors.

required
degrees bool

If True, magnitudes are assumed to be in degrees. Default, False.

False

Returns:

Name Type Description
rotation_vector_magnitudes (Tensor, shape(...))

Angles in radians. Magnitudes will be in the range :math:[0, \pi].

Source code in src/beignet/_rotation_vector_magnitude.py
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
def rotation_vector_magnitude(
    input: Tensor,
    degrees: bool | None = False,
) -> Tensor:
    r"""
    Rotation vector magnitudes.

    Parameters
    ----------
    input : Tensor, shape (..., 3)
        Rotation vectors.

    degrees : bool, optional
        If `True`, magnitudes are assumed to be in degrees. Default, `False`.

    Returns
    -------
    rotation_vector_magnitudes : Tensor, shape (...)
        Angles in radians. Magnitudes will be in the range :math:`[0, \pi]`.
    """
    return quaternion_magnitude(
        rotation_vector_to_quaternion(
            input,
            degrees,
        ),
    )

beignet.rotation_vector_mean

rotation_vector_mean(input, weight=None, degrees=False)

Compose rotation vectors.

Parameters:

Name Type Description Default
input Tensor, shape=(..., 4)

Rotation vectors.

required
weight Tensor, shape=(..., 4)

Relative importance of rotation matrices.

None
degrees bool

If True, rotation vector magnitudes are assumed to be in degrees. Default, False.

False

Returns:

Name Type Description
output Tensor, shape=(..., 4)

Rotation vectors mean.

Source code in src/beignet/_rotation_vector_mean.py
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
def rotation_vector_mean(
    input: Tensor,
    weight: Tensor | None = None,
    degrees: bool | None = False,
) -> Tensor:
    r"""
    Compose rotation vectors.

    Parameters
    ----------
    input : Tensor, shape=(..., 4)
        Rotation vectors.

    weight : Tensor, shape=(..., 4), optional
        Relative importance of rotation matrices.

    degrees : bool, optional
        If `True`, rotation vector magnitudes are assumed to be in degrees.
        Default, `False`.

    Returns
    -------
    output : Tensor, shape=(..., 4)
        Rotation vectors mean.
    """
    return quaternion_to_rotation_vector(
        quaternion_mean(
            rotation_vector_to_quaternion(
                input,
                degrees,
            ),
            weight,
        ),
        degrees,
    )

beignet.rotation_vector_to_euler_angle

rotation_vector_to_euler_angle(input, axes, degrees=False)

Convert rotation vectors to Euler angles.

Parameters:

Name Type Description Default
input Tensor, shape=(..., 3)

Rotation vectors.

required
degrees bool

If True, rotation vector magnitudes are assumed to be in degrees. Default, False.

False

Returns:

Name Type Description
output Tensor, shape=(..., 3)

Euler angles. The returned Euler angles are in the range:

* First angle: :math:`(-180, 180]` degrees (inclusive)
* Second angle:
    * :math:`[-90, 90]` degrees if all axes are different
      (e.g., :math:`xyz`)
    * :math:`[0, 180]` degrees if first and third axes are the same
      (e.g., :math:`zxz`)
* Third angle: :math:`[-180, 180]` degrees (inclusive)
Source code in src/beignet/_rotation_vector_to_euler_angle.py
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
def rotation_vector_to_euler_angle(
    input: Tensor,
    axes: str,
    degrees: bool = False,
) -> Tensor:
    r"""
    Convert rotation vectors to Euler angles.

    Parameters
    ----------
    input : Tensor, shape=(..., 3)
        Rotation vectors.

    degrees : bool, optional
        If `True`, rotation vector magnitudes are assumed to be in degrees.
        Default, `False`.

    Returns
    -------
    output : Tensor, shape=(..., 3)
        Euler angles. The returned Euler angles are in the range:

            * First angle: :math:`(-180, 180]` degrees (inclusive)
            * Second angle:
                * :math:`[-90, 90]` degrees if all axes are different
                  (e.g., :math:`xyz`)
                * :math:`[0, 180]` degrees if first and third axes are the same
                  (e.g., :math:`zxz`)
            * Third angle: :math:`[-180, 180]` degrees (inclusive)
    """
    return quaternion_to_euler_angle(
        rotation_vector_to_quaternion(
            input,
            degrees,
        ),
        axes,
        degrees,
    )

beignet.rotation_vector_to_quaternion

rotation_vector_to_quaternion(input, degrees=False, canonical=False)

Convert rotation vector to rotation quaternion.

Parameters:

Name Type Description Default
input Tensor, shape=(..., 3)

Rotation vector.

required
degrees bool

If True, rotation vector magnitudes are assumed to be in degrees. Default, False.

False
canonical bool

Whether to map the redundant double cover of rotation space to a unique canonical single cover. If True, then the rotation quaternion is chosen from :math:{q, -q} such that the :math:w term is positive. If the :math:w term is :math:0, then the rotation quaternion is chosen such that the first non-zero term of the :math:x, :math:y, and :math:z terms is positive.

False

Returns:

Name Type Description
output Tensor, shape=(..., 4)

Rotation quaternion.

Source code in src/beignet/_rotation_vector_to_quaternion.py
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
def rotation_vector_to_quaternion(
    input: Tensor,
    degrees: bool | None = False,
    canonical: bool | None = False,
) -> Tensor:
    r"""
    Convert rotation vector to rotation quaternion.

    Parameters
    ----------
    input : Tensor, shape=(..., 3)
        Rotation vector.

    degrees : bool, optional
        If `True`, rotation vector magnitudes are assumed to be in degrees.
        Default, `False`.

    canonical : bool, optional
        Whether to map the redundant double cover of rotation space to a unique
        canonical single cover. If `True`, then the rotation quaternion is
        chosen from :math:`{q, -q}` such that the :math:`w` term is positive.
        If the :math:`w` term is :math:`0`, then the rotation quaternion is
        chosen such that the first non-zero term of the :math:`x`, :math:`y`,
        and :math:`z` terms is positive.

    Returns
    -------
    output : Tensor, shape=(..., 4)
        Rotation quaternion.
    """
    if degrees:
        input = torch.deg2rad(input)

    output = torch.empty(
        [input.shape[0], 4],
        dtype=input.dtype,
        layout=input.layout,
        device=input.device,
    )

    for j in range(input.shape[0]):
        t = input[j, 0] ** 2.0
        u = input[j, 1] ** 2.0
        v = input[j, 2] ** 2.0

        y = torch.sqrt(t + u + v)

        if y < 0.001:
            scale = 0.5 - y**2.0 / 48.0 + y**2.0 * y**2.0 / 3840.0
        else:
            scale = torch.sin(y / 2) / y

        output[j, :-1] = input[j] * scale

        output[j, 3] = torch.cos(y / 2)

    if canonical:
        for j in range(output.shape[0]):
            a = output[j, 0]
            b = output[j, 1]
            c = output[j, 2]
            d = output[j, 3]

            if d == 0 and (a == 0 & (b == 0 & c < 0 | b < 0) | a < 0) | d < 0:
                output[j] = -output[j]

    return output

beignet.rotation_vector_to_rotation_matrix

rotation_vector_to_rotation_matrix(input, degrees=False)

Convert rotation vectors to rotation matrices.

Parameters:

Name Type Description Default
input Tensor, shape=(..., 3)

Rotation vectors.

required
degrees bool

If True, rotation vector magnitudes are assumed to be in degrees. Default, False.

False

Returns:

Name Type Description
output Tensor, shape=(..., 3, 3)

Rotation matrices.

Source code in src/beignet/_rotation_vector_to_rotation_matrix.py
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
def rotation_vector_to_rotation_matrix(
    input: Tensor,
    degrees: bool | None = False,
) -> Tensor:
    r"""
    Convert rotation vectors to rotation matrices.

    Parameters
    ----------
    input : Tensor, shape=(..., 3)
        Rotation vectors.

    degrees : bool, optional
        If `True`, rotation vector magnitudes are assumed to be in degrees.
        Default, `False`.

    Returns
    -------
    output : Tensor, shape=(..., 3, 3)
        Rotation matrices.
    """
    return quaternion_to_rotation_matrix(
        rotation_vector_to_quaternion(
            input,
            degrees,
        ),
    )

beignet.translation_identity

translation_identity(size, *, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False)

Identity translation vectors.

Parameters:

Name Type Description Default
size int

Output size.

required
out Tensor

Output tensor. Default, None.

None
dtype dtype

Type of the returned tensor. Default, global default.

None
layout layout

Layout of the returned tensor. Default, torch.strided.

strided
device device

Device of the returned tensor. Default, current device for the default tensor type.

None
requires_grad bool

Whether autograd records operations on the returned tensor. Default, False.

False

Returns:

Name Type Description
output Tensor, shape=(size, 3)

Identity rotation quaternions.

Source code in src/beignet/_translation_identity.py
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
def translation_identity(
    size: int,
    *,
    out: Tensor | None = None,
    dtype: torch.dtype | None = None,
    layout: torch.layout | None = torch.strided,
    device: torch.device | None = None,
    requires_grad: bool | None = False,
) -> Tensor:
    """
    Identity translation vectors.

    Parameters
    ----------
    size : int
        Output size.

    out : Tensor, optional
        Output tensor. Default, `None`.

    dtype : torch.dtype, optional
        Type of the returned tensor. Default, global default.

    layout : torch.layout, optional
        Layout of the returned tensor. Default, `torch.strided`.

    device : torch.device, optional
        Device of the returned tensor. Default, current device for the default
        tensor type.

    requires_grad : bool, optional
        Whether autograd records operations on the returned tensor. Default,
        `False`.

    Returns
    -------
    output : Tensor, shape=(size, 3)
        Identity rotation quaternions.
    """
    return torch.zeros(
        [size, 3],
        out=out,
        dtype=dtype,
        layout=layout,
        device=device,
        requires_grad=requires_grad,
    )