From 87af20bb9d3946c91b74b31618f18cc8af4e9253 Mon Sep 17 00:00:00 2001 From: Allen Goodman Date: Wed, 17 Apr 2024 10:17:24 -0400 Subject: [PATCH 01/14] sequence alignment operators --- .gitignore | 2 + .pre-commit-config.yaml | 4 +- docs/beignet.ops.md | 11 + pyproject.toml | 5 + src/beignet/constants/__init__.py | 119 ++ .../constants/_substitution_matrices.py | 1434 +++++++++++++++++ src/beignet/datasets/_msa_dataset.py | 104 ++ src/beignet/lightning/__init__.py | 1 + .../lightning/_msa_lightning_module.py | 27 + src/beignet/nn/__init__.py | 1 + src/beignet/nn/_msa.py | 56 + src/beignet/operators/__init__.py | 7 + src/beignet/operators/_needleman_wunsch.py | 194 +++ src/beignet/operators/_smith_waterman.py | 199 +++ src/beignet/ops/__init__.py | 89 + src/beignet/ops/_geometry/__init__.py | 44 + .../_geometry/_transformations/__init__.py | 60 + .../_transformations/_apply_euler_angle.py | 63 + .../_transformations/_apply_quaternion.py | 52 + .../_apply_rotation_matrix.py | 47 + .../_apply_rotation_vector.py | 63 + .../_transformations/_compose_euler_angle.py | 53 + .../_transformations/_compose_quaternion.py | 73 + .../_compose_rotation_matrix.py | 33 + .../_compose_rotation_vector.py | 45 + .../_transformations/_euler_angle_identity.py | 70 + .../_euler_angle_magnitude.py | 41 + .../_transformations/_euler_angle_mean.py | 49 + .../_euler_angle_to_quaternion.py | 170 ++ .../_euler_angle_to_rotation_matrix.py | 80 + .../_euler_angle_to_rotation_vector.py | 253 +++ .../_transformations/_invert_euler_angle.py | 48 + .../_transformations/_invert_quaternion.py | 31 + .../_invert_rotation_matrix.py | 19 + .../_invert_rotation_vector.py | 20 + .../_transformations/_quaternion_identity.py | 64 + .../_transformations/_quaternion_magnitude.py | 37 + .../_transformations/_quaternion_mean.py | 34 + .../_transformations/_quaternion_slerp.py | 93 ++ .../_quaternion_to_euler_angle.py | 143 ++ .../_quaternion_to_rotation_matrix.py | 43 + .../_quaternion_to_rotation_vector.py | 57 + .../_transformations/_random_euler_angle.py | 91 ++ .../_transformations/_random_quaternion.py | 95 ++ .../_random_rotation_matrix.py | 69 + .../_random_rotation_vector.py | 73 + .../_rotation_matrix_identity.py | 58 + .../_rotation_matrix_magnitude.py | 27 + .../_transformations/_rotation_matrix_mean.py | 32 + .../_rotation_matrix_to_euler_angle.py | 51 + .../_rotation_matrix_to_quaternion.py | 88 + .../_rotation_matrix_to_rotation_vector.py | 37 + .../_rotation_vector_identity.py | 64 + .../_rotation_vector_magnitude.py | 34 + .../_transformations/_rotation_vector_mean.py | 42 + .../_rotation_vector_to_euler_angle.py | 48 + .../_rotation_vector_to_quaternion.py | 71 + .../_rotation_vector_to_rotation_matrix.py | 37 + .../_transformations/_translation_identity.py | 51 + .../operators/test__needleman_wunsch.py | 0 .../beignet/operators/test__smith_waterman.py | 0 .../test__apply_euler_angle.py | 94 ++ .../test__apply_quaternion.py | 53 + .../test__apply_rotation_matrix.py | 65 + .../test__apply_rotation_vector.py | 54 + .../test__compose_euler_angle.py | 60 + .../test__compose_quaternion.py | 40 + .../test__compose_rotation_matrix.py | 37 + .../test__compose_rotation_vector.py | 40 + .../test__euler_angle_identity.py | 11 + .../test__euler_angle_magnitude.py | 56 + .../test__euler_angle_mean.py | 61 + .../test__euler_angle_to_quaternion.py | 75 + .../test__euler_angle_to_rotation_matrix.py | 65 + .../test__euler_angle_to_rotation_vector.py | 63 + .../test__invert_euler_angle.py | 56 + .../test__invert_quaternion.py | 36 + .../test__invert_rotation_matrix.py | 33 + .../test__invert_rotation_vector.py | 35 + .../test__quaternion_identity.py | 37 + .../test__quaternion_magnitude.py | 36 + .../_transformations/test__quaternion_mean.py | 50 + .../test__quaternion_to_euler_angle.py | 67 + .../test__quaternion_to_rotation_matrix.py | 41 + .../test__quaternion_to_rotation_vector.py | 46 + .../test__random_euler_angle.py | 51 + .../test__random_quaternion.py | 31 + .../test__random_rotation_matrix.py | 28 + .../test__random_rotation_vector.py | 31 + .../test__rotation_matrix_identity.py | 34 + .../test__rotation_matrix_magnitude.py | 33 + .../test__rotation_matrix_mean.py | 33 + .../test__rotation_matrix_to_euler_angle.py | 65 + .../test__rotation_matrix_to_quaternion.py | 49 + ...est__rotation_matrix_to_rotation_vector.py | 45 + .../test__rotation_vector_identity.py | 36 + .../test__rotation_vector_magnitude.py | 36 + .../test__rotation_vector_mean.py | 39 + .../test__rotation_vector_to_euler_angle.py | 67 + .../test__rotation_vector_to_quaternion.py | 54 + ...est__rotation_vector_to_rotation_matrix.py | 42 + .../_geometry/_transformations/test__slerp.py | 151 ++ 102 files changed, 7040 insertions(+), 2 deletions(-) create mode 100644 docs/beignet.ops.md create mode 100644 src/beignet/constants/__init__.py create mode 100644 src/beignet/constants/_substitution_matrices.py create mode 100644 src/beignet/datasets/_msa_dataset.py create mode 100644 src/beignet/lightning/__init__.py create mode 100644 src/beignet/lightning/_msa_lightning_module.py create mode 100644 src/beignet/nn/__init__.py create mode 100644 src/beignet/nn/_msa.py create mode 100644 src/beignet/operators/__init__.py create mode 100644 src/beignet/operators/_needleman_wunsch.py create mode 100644 src/beignet/operators/_smith_waterman.py create mode 100644 src/beignet/ops/__init__.py create mode 100644 src/beignet/ops/_geometry/__init__.py create mode 100644 src/beignet/ops/_geometry/_transformations/__init__.py create mode 100644 src/beignet/ops/_geometry/_transformations/_apply_euler_angle.py create mode 100644 src/beignet/ops/_geometry/_transformations/_apply_quaternion.py create mode 100644 src/beignet/ops/_geometry/_transformations/_apply_rotation_matrix.py create mode 100644 src/beignet/ops/_geometry/_transformations/_apply_rotation_vector.py create mode 100644 src/beignet/ops/_geometry/_transformations/_compose_euler_angle.py create mode 100644 src/beignet/ops/_geometry/_transformations/_compose_quaternion.py create mode 100644 src/beignet/ops/_geometry/_transformations/_compose_rotation_matrix.py create mode 100644 src/beignet/ops/_geometry/_transformations/_compose_rotation_vector.py create mode 100644 src/beignet/ops/_geometry/_transformations/_euler_angle_identity.py create mode 100644 src/beignet/ops/_geometry/_transformations/_euler_angle_magnitude.py create mode 100644 src/beignet/ops/_geometry/_transformations/_euler_angle_mean.py create mode 100644 src/beignet/ops/_geometry/_transformations/_euler_angle_to_quaternion.py create mode 100644 src/beignet/ops/_geometry/_transformations/_euler_angle_to_rotation_matrix.py create mode 100644 src/beignet/ops/_geometry/_transformations/_euler_angle_to_rotation_vector.py create mode 100644 src/beignet/ops/_geometry/_transformations/_invert_euler_angle.py create mode 100644 src/beignet/ops/_geometry/_transformations/_invert_quaternion.py create mode 100644 src/beignet/ops/_geometry/_transformations/_invert_rotation_matrix.py create mode 100644 src/beignet/ops/_geometry/_transformations/_invert_rotation_vector.py create mode 100644 src/beignet/ops/_geometry/_transformations/_quaternion_identity.py create mode 100644 src/beignet/ops/_geometry/_transformations/_quaternion_magnitude.py create mode 100644 src/beignet/ops/_geometry/_transformations/_quaternion_mean.py create mode 100644 src/beignet/ops/_geometry/_transformations/_quaternion_slerp.py create mode 100644 src/beignet/ops/_geometry/_transformations/_quaternion_to_euler_angle.py create mode 100644 src/beignet/ops/_geometry/_transformations/_quaternion_to_rotation_matrix.py create mode 100644 src/beignet/ops/_geometry/_transformations/_quaternion_to_rotation_vector.py create mode 100644 src/beignet/ops/_geometry/_transformations/_random_euler_angle.py create mode 100644 src/beignet/ops/_geometry/_transformations/_random_quaternion.py create mode 100644 src/beignet/ops/_geometry/_transformations/_random_rotation_matrix.py create mode 100644 src/beignet/ops/_geometry/_transformations/_random_rotation_vector.py create mode 100644 src/beignet/ops/_geometry/_transformations/_rotation_matrix_identity.py create mode 100644 src/beignet/ops/_geometry/_transformations/_rotation_matrix_magnitude.py create mode 100644 src/beignet/ops/_geometry/_transformations/_rotation_matrix_mean.py create mode 100644 src/beignet/ops/_geometry/_transformations/_rotation_matrix_to_euler_angle.py create mode 100644 src/beignet/ops/_geometry/_transformations/_rotation_matrix_to_quaternion.py create mode 100644 src/beignet/ops/_geometry/_transformations/_rotation_matrix_to_rotation_vector.py create mode 100644 src/beignet/ops/_geometry/_transformations/_rotation_vector_identity.py create mode 100644 src/beignet/ops/_geometry/_transformations/_rotation_vector_magnitude.py create mode 100644 src/beignet/ops/_geometry/_transformations/_rotation_vector_mean.py create mode 100644 src/beignet/ops/_geometry/_transformations/_rotation_vector_to_euler_angle.py create mode 100644 src/beignet/ops/_geometry/_transformations/_rotation_vector_to_quaternion.py create mode 100644 src/beignet/ops/_geometry/_transformations/_rotation_vector_to_rotation_matrix.py create mode 100644 src/beignet/ops/_geometry/_transformations/_translation_identity.py create mode 100644 tests/beignet/operators/test__needleman_wunsch.py create mode 100644 tests/beignet/operators/test__smith_waterman.py create mode 100644 tests/beignet/ops/_geometry/_transformations/test__apply_euler_angle.py create mode 100644 tests/beignet/ops/_geometry/_transformations/test__apply_quaternion.py create mode 100644 tests/beignet/ops/_geometry/_transformations/test__apply_rotation_matrix.py create mode 100644 tests/beignet/ops/_geometry/_transformations/test__apply_rotation_vector.py create mode 100644 tests/beignet/ops/_geometry/_transformations/test__compose_euler_angle.py create mode 100644 tests/beignet/ops/_geometry/_transformations/test__compose_quaternion.py create mode 100644 tests/beignet/ops/_geometry/_transformations/test__compose_rotation_matrix.py create mode 100644 tests/beignet/ops/_geometry/_transformations/test__compose_rotation_vector.py create mode 100644 tests/beignet/ops/_geometry/_transformations/test__euler_angle_identity.py create mode 100644 tests/beignet/ops/_geometry/_transformations/test__euler_angle_magnitude.py create mode 100644 tests/beignet/ops/_geometry/_transformations/test__euler_angle_mean.py create mode 100644 tests/beignet/ops/_geometry/_transformations/test__euler_angle_to_quaternion.py create mode 100644 tests/beignet/ops/_geometry/_transformations/test__euler_angle_to_rotation_matrix.py create mode 100644 tests/beignet/ops/_geometry/_transformations/test__euler_angle_to_rotation_vector.py create mode 100644 tests/beignet/ops/_geometry/_transformations/test__invert_euler_angle.py create mode 100644 tests/beignet/ops/_geometry/_transformations/test__invert_quaternion.py create mode 100644 tests/beignet/ops/_geometry/_transformations/test__invert_rotation_matrix.py create mode 100644 tests/beignet/ops/_geometry/_transformations/test__invert_rotation_vector.py create mode 100644 tests/beignet/ops/_geometry/_transformations/test__quaternion_identity.py create mode 100644 tests/beignet/ops/_geometry/_transformations/test__quaternion_magnitude.py create mode 100644 tests/beignet/ops/_geometry/_transformations/test__quaternion_mean.py create mode 100644 tests/beignet/ops/_geometry/_transformations/test__quaternion_to_euler_angle.py create mode 100644 tests/beignet/ops/_geometry/_transformations/test__quaternion_to_rotation_matrix.py create mode 100644 tests/beignet/ops/_geometry/_transformations/test__quaternion_to_rotation_vector.py create mode 100644 tests/beignet/ops/_geometry/_transformations/test__random_euler_angle.py create mode 100644 tests/beignet/ops/_geometry/_transformations/test__random_quaternion.py create mode 100644 tests/beignet/ops/_geometry/_transformations/test__random_rotation_matrix.py create mode 100644 tests/beignet/ops/_geometry/_transformations/test__random_rotation_vector.py create mode 100644 tests/beignet/ops/_geometry/_transformations/test__rotation_matrix_identity.py create mode 100644 tests/beignet/ops/_geometry/_transformations/test__rotation_matrix_magnitude.py create mode 100644 tests/beignet/ops/_geometry/_transformations/test__rotation_matrix_mean.py create mode 100644 tests/beignet/ops/_geometry/_transformations/test__rotation_matrix_to_euler_angle.py create mode 100644 tests/beignet/ops/_geometry/_transformations/test__rotation_matrix_to_quaternion.py create mode 100644 tests/beignet/ops/_geometry/_transformations/test__rotation_matrix_to_rotation_vector.py create mode 100644 tests/beignet/ops/_geometry/_transformations/test__rotation_vector_identity.py create mode 100644 tests/beignet/ops/_geometry/_transformations/test__rotation_vector_magnitude.py create mode 100644 tests/beignet/ops/_geometry/_transformations/test__rotation_vector_mean.py create mode 100644 tests/beignet/ops/_geometry/_transformations/test__rotation_vector_to_euler_angle.py create mode 100644 tests/beignet/ops/_geometry/_transformations/test__rotation_vector_to_quaternion.py create mode 100644 tests/beignet/ops/_geometry/_transformations/test__rotation_vector_to_rotation_matrix.py create mode 100644 tests/beignet/ops/_geometry/_transformations/test__slerp.py diff --git a/.gitignore b/.gitignore index 7dca454ba6..41d7c8dacc 100644 --- a/.gitignore +++ b/.gitignore @@ -7,9 +7,11 @@ .coverage .hypothesis/ .idea/ +.ipynb_checkpoints/ .pytest_cache/ .ruff_cache/ __pycache__/ build/ dist/ +notebooks/ venv/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 32e8d38b71..bbdd2e8098 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -3,11 +3,11 @@ repos: - id: "check-toml" - id: "check-yaml" repo: "https://github.com/pre-commit/pre-commit-hooks" - rev: "v4.5.0" + rev: "v4.6.0" - hooks: - args: - "--fix" id: "ruff" - id: "ruff-format" repo: "https://github.com/astral-sh/ruff-pre-commit" - rev: "v0.3.5" + rev: "v0.3.7" diff --git a/docs/beignet.ops.md b/docs/beignet.ops.md new file mode 100644 index 0000000000..f660c46747 --- /dev/null +++ b/docs/beignet.ops.md @@ -0,0 +1,11 @@ +# beignet.ops + +## Geometry + +### Transformations + +#### Rotations + +#### Translations + +## Interpolation diff --git a/pyproject.toml b/pyproject.toml index 4edb35cebb..b14277f13d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,6 +26,11 @@ test = [ "scipy", ] +[tool.ruff] +exclude = [ + "./src/beignet/constants/_substitution_matrices.py", +] + [tool.ruff] select = [ "B", # FLAKE8-BUGBEAR diff --git a/src/beignet/constants/__init__.py b/src/beignet/constants/__init__.py new file mode 100644 index 0000000000..1b5b0b67e1 --- /dev/null +++ b/src/beignet/constants/__init__.py @@ -0,0 +1,119 @@ +from ._substitution_matrices import ( + BLOSUM45, + BLOSUM50, + BLOSUM62, + BLOSUM80, + BLOSUM90, + BLOSUM_VOCABULARY, + PAM10, + PAM20, + PAM30, + PAM40, + PAM50, + PAM60, + PAM70, + PAM80, + PAM90, + PAM100, + PAM110, + PAM120, + PAM130, + PAM140, + PAM150, + PAM160, + PAM170, + PAM180, + PAM190, + PAM200, + PAM210, + PAM220, + PAM230, + PAM240, + PAM250, + PAM260, + PAM270, + PAM280, + PAM290, + PAM300, + PAM310, + PAM320, + PAM330, + PAM340, + PAM350, + PAM360, + PAM370, + PAM380, + PAM390, + PAM400, + PAM410, + PAM420, + PAM430, + PAM440, + PAM450, + PAM460, + PAM470, + PAM480, + PAM490, + PAM500, + PAM_VOCABULARY, +) + +__all__ = [ + "BLOSUM45", + "BLOSUM50", + "BLOSUM62", + "BLOSUM80", + "BLOSUM90", + "BLOSUM_VOCABULARY", + "PAM10", + "PAM20", + "PAM30", + "PAM40", + "PAM50", + "PAM60", + "PAM70", + "PAM80", + "PAM90", + "PAM100", + "PAM110", + "PAM120", + "PAM130", + "PAM140", + "PAM150", + "PAM160", + "PAM170", + "PAM180", + "PAM190", + "PAM200", + "PAM210", + "PAM220", + "PAM230", + "PAM240", + "PAM250", + "PAM260", + "PAM270", + "PAM280", + "PAM290", + "PAM300", + "PAM310", + "PAM320", + "PAM330", + "PAM340", + "PAM350", + "PAM360", + "PAM370", + "PAM380", + "PAM390", + "PAM400", + "PAM410", + "PAM420", + "PAM430", + "PAM440", + "PAM450", + "PAM460", + "PAM470", + "PAM480", + "PAM490", + "PAM500", + "PAM_VOCABULARY", +] diff --git a/src/beignet/constants/_substitution_matrices.py b/src/beignet/constants/_substitution_matrices.py new file mode 100644 index 0000000000..88a927c137 --- /dev/null +++ b/src/beignet/constants/_substitution_matrices.py @@ -0,0 +1,1434 @@ +BLOSUM45 = [[+0x05, -0x02, -0x01, -0x02, -0x01, -0x01, -0x01, -0x00, -0x02, -0x01, -0x01, -0x01, -0x01, -0x02, -0x01, +0x01, -0x00, -0x02, -0x02, -0x00, -0x01, -0x01, -0x01, -0x01, -0x05], + [-0x02, +0x07, -0x00, -0x01, -0x03, +0x01, -0x00, -0x02, -0x00, -0x03, -0x02, +0x03, -0x01, -0x02, -0x02, -0x01, -0x01, -0x02, -0x01, -0x02, -0x01, -0x03, +0x01, -0x01, -0x05], + [-0x01, -0x00, +0x06, +0x02, -0x02, -0x00, -0x00, -0x00, +0x01, -0x02, -0x03, -0x00, -0x02, -0x02, -0x02, +0x01, -0x00, -0x04, -0x02, -0x03, +0x05, -0x03, -0x00, -0x01, -0x05], + [-0x02, -0x01, +0x02, +0x07, -0x03, -0x00, +0x02, -0x01, -0x00, -0x04, -0x03, -0x00, -0x03, -0x04, -0x01, -0x00, -0x01, -0x04, -0x02, -0x03, +0x06, -0x03, +0x01, -0x01, -0x05], + [-0x01, -0x03, -0x02, -0x03, +0x0c, -0x03, -0x03, -0x03, -0x03, -0x03, -0x02, -0x03, -0x02, -0x02, -0x04, -0x01, -0x01, -0x05, -0x03, -0x01, -0x02, -0x02, -0x03, -0x01, -0x05], + [-0x01, +0x01, -0x00, -0x00, -0x03, +0x06, +0x02, -0x02, +0x01, -0x02, -0x02, +0x01, -0x00, -0x04, -0x01, -0x00, -0x01, -0x02, -0x01, -0x03, -0x00, -0x02, +0x04, -0x01, -0x05], + [-0x01, -0x00, -0x00, +0x02, -0x03, +0x02, +0x06, -0x02, -0x00, -0x03, -0x02, +0x01, -0x02, -0x03, -0x00, -0x00, -0x01, -0x03, -0x02, -0x03, +0x01, -0x03, +0x05, -0x01, -0x05], + [-0x00, -0x02, -0x00, -0x01, -0x03, -0x02, -0x02, +0x07, -0x02, -0x04, -0x03, -0x02, -0x02, -0x03, -0x02, -0x00, -0x02, -0x02, -0x03, -0x03, -0x01, -0x04, -0x02, -0x01, -0x05], + [-0x02, -0x00, +0x01, -0x00, -0x03, +0x01, -0x00, -0x02, +0x0a, -0x03, -0x02, -0x01, -0x00, -0x02, -0x02, -0x01, -0x02, -0x03, +0x02, -0x03, -0x00, -0x02, -0x00, -0x01, -0x05], + [-0x01, -0x03, -0x02, -0x04, -0x03, -0x02, -0x03, -0x04, -0x03, +0x05, +0x02, -0x03, +0x02, -0x00, -0x02, -0x02, -0x01, -0x02, -0x00, +0x03, -0x03, +0x04, -0x03, -0x01, -0x05], + [-0x01, -0x02, -0x03, -0x03, -0x02, -0x02, -0x02, -0x03, -0x02, +0x02, +0x05, -0x03, +0x02, +0x01, -0x03, -0x03, -0x01, -0x02, -0x00, +0x01, -0x03, +0x04, -0x02, -0x01, -0x05], + [-0x01, +0x03, -0x00, -0x00, -0x03, +0x01, +0x01, -0x02, -0x01, -0x03, -0x03, +0x05, -0x01, -0x03, -0x01, -0x01, -0x01, -0x02, -0x01, -0x02, -0x00, -0x03, +0x01, -0x01, -0x05], + [-0x01, -0x01, -0x02, -0x03, -0x02, -0x00, -0x02, -0x02, -0x00, +0x02, +0x02, -0x01, +0x06, -0x00, -0x02, -0x02, -0x01, -0x02, -0x00, +0x01, -0x02, +0x02, -0x01, -0x01, -0x05], + [-0x02, -0x02, -0x02, -0x04, -0x02, -0x04, -0x03, -0x03, -0x02, -0x00, +0x01, -0x03, -0x00, +0x08, -0x03, -0x02, -0x01, +0x01, +0x03, -0x00, -0x03, +0x01, -0x03, -0x01, -0x05], + [-0x01, -0x02, -0x02, -0x01, -0x04, -0x01, -0x00, -0x02, -0x02, -0x02, -0x03, -0x01, -0x02, -0x03, +0x09, -0x01, -0x01, -0x03, -0x03, -0x03, -0x02, -0x03, -0x01, -0x01, -0x05], + [+0x01, -0x01, +0x01, -0x00, -0x01, -0x00, -0x00, -0x00, -0x01, -0x02, -0x03, -0x01, -0x02, -0x02, -0x01, +0x04, +0x02, -0x04, -0x02, -0x01, -0x00, -0x02, -0x00, -0x01, -0x05], + [-0x00, -0x01, -0x00, -0x01, -0x01, -0x01, -0x01, -0x02, -0x02, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, +0x02, +0x05, -0x03, -0x01, -0x00, -0x00, -0x01, -0x01, -0x01, -0x05], + [-0x02, -0x02, -0x04, -0x04, -0x05, -0x02, -0x03, -0x02, -0x03, -0x02, -0x02, -0x02, -0x02, +0x01, -0x03, -0x04, -0x03, +0x0f, +0x03, -0x03, -0x04, -0x02, -0x02, -0x01, -0x05], + [-0x02, -0x01, -0x02, -0x02, -0x03, -0x01, -0x02, -0x03, +0x02, -0x00, -0x00, -0x01, -0x00, +0x03, -0x03, -0x02, -0x01, +0x03, +0x08, -0x01, -0x02, -0x00, -0x02, -0x01, -0x05], + [-0x00, -0x02, -0x03, -0x03, -0x01, -0x03, -0x03, -0x03, -0x03, +0x03, +0x01, -0x02, +0x01, -0x00, -0x03, -0x01, -0x00, -0x03, -0x01, +0x05, -0x03, +0x02, -0x03, -0x01, -0x05], + [-0x01, -0x01, +0x05, +0x06, -0x02, -0x00, +0x01, -0x01, -0x00, -0x03, -0x03, -0x00, -0x02, -0x03, -0x02, -0x00, -0x00, -0x04, -0x02, -0x03, +0x05, -0x03, +0x01, -0x01, -0x05], + [-0x01, -0x03, -0x03, -0x03, -0x02, -0x02, -0x03, -0x04, -0x02, +0x04, +0x04, -0x03, +0x02, +0x01, -0x03, -0x02, -0x01, -0x02, -0x00, +0x02, -0x03, +0x04, -0x02, -0x01, -0x05], + [-0x01, +0x01, -0x00, +0x01, -0x03, +0x04, +0x05, -0x02, -0x00, -0x03, -0x02, +0x01, -0x01, -0x03, -0x01, -0x00, -0x01, -0x02, -0x02, -0x03, +0x01, -0x02, +0x05, -0x01, -0x05], + [-0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x05], + [-0x05, -0x05, -0x05, -0x05, -0x05, -0x05, -0x05, -0x05, -0x05, -0x05, -0x05, -0x05, -0x05, -0x05, -0x05, -0x05, -0x05, -0x05, -0x05, -0x05, -0x05, -0x05, -0x05, -0x05, +0x01]] + +BLOSUM50 = [[+0x05, -0x02, -0x01, -0x02, -0x01, -0x01, -0x01, -0x00, -0x02, -0x01, -0x02, -0x01, -0x01, -0x03, -0x01, +0x01, -0x00, -0x03, -0x02, -0x00, -0x02, -0x02, -0x01, -0x01, -0x05], + [-0x02, +0x07, -0x01, -0x02, -0x04, +0x01, -0x00, -0x03, -0x00, -0x04, -0x03, +0x03, -0x02, -0x03, -0x03, -0x01, -0x01, -0x03, -0x01, -0x03, -0x01, -0x03, -0x00, -0x01, -0x05], + [-0x01, -0x01, +0x07, +0x02, -0x02, -0x00, -0x00, -0x00, +0x01, -0x03, -0x04, -0x00, -0x02, -0x04, -0x02, +0x01, -0x00, -0x04, -0x02, -0x03, +0x05, -0x04, -0x00, -0x01, -0x05], + [-0x02, -0x02, +0x02, +0x08, -0x04, -0x00, +0x02, -0x01, -0x01, -0x04, -0x04, -0x01, -0x04, -0x05, -0x01, -0x00, -0x01, -0x05, -0x03, -0x04, +0x06, -0x04, +0x01, -0x01, -0x05], + [-0x01, -0x04, -0x02, -0x04, +0x0d, -0x03, -0x03, -0x03, -0x03, -0x02, -0x02, -0x03, -0x02, -0x02, -0x04, -0x01, -0x01, -0x05, -0x03, -0x01, -0x03, -0x02, -0x03, -0x01, -0x05], + [-0x01, +0x01, -0x00, -0x00, -0x03, +0x07, +0x02, -0x02, +0x01, -0x03, -0x02, +0x02, -0x00, -0x04, -0x01, -0x00, -0x01, -0x01, -0x01, -0x03, -0x00, -0x03, +0x04, -0x01, -0x05], + [-0x01, -0x00, -0x00, +0x02, -0x03, +0x02, +0x06, -0x03, -0x00, -0x04, -0x03, +0x01, -0x02, -0x03, -0x01, -0x01, -0x01, -0x03, -0x02, -0x03, +0x01, -0x03, +0x05, -0x01, -0x05], + [-0x00, -0x03, -0x00, -0x01, -0x03, -0x02, -0x03, +0x08, -0x02, -0x04, -0x04, -0x02, -0x03, -0x04, -0x02, -0x00, -0x02, -0x03, -0x03, -0x04, -0x01, -0x04, -0x02, -0x01, -0x05], + [-0x02, -0x00, +0x01, -0x01, -0x03, +0x01, -0x00, -0x02, +0x0a, -0x04, -0x03, -0x00, -0x01, -0x01, -0x02, -0x01, -0x02, -0x03, +0x02, -0x04, -0x00, -0x03, -0x00, -0x01, -0x05], + [-0x01, -0x04, -0x03, -0x04, -0x02, -0x03, -0x04, -0x04, -0x04, +0x05, +0x02, -0x03, +0x02, -0x00, -0x03, -0x03, -0x01, -0x03, -0x01, +0x04, -0x04, +0x04, -0x03, -0x01, -0x05], + [-0x02, -0x03, -0x04, -0x04, -0x02, -0x02, -0x03, -0x04, -0x03, +0x02, +0x05, -0x03, +0x03, +0x01, -0x04, -0x03, -0x01, -0x02, -0x01, +0x01, -0x04, +0x04, -0x03, -0x01, -0x05], + [-0x01, +0x03, -0x00, -0x01, -0x03, +0x02, +0x01, -0x02, -0x00, -0x03, -0x03, +0x06, -0x02, -0x04, -0x01, -0x00, -0x01, -0x03, -0x02, -0x03, -0x00, -0x03, +0x01, -0x01, -0x05], + [-0x01, -0x02, -0x02, -0x04, -0x02, -0x00, -0x02, -0x03, -0x01, +0x02, +0x03, -0x02, +0x07, -0x00, -0x03, -0x02, -0x01, -0x01, -0x00, +0x01, -0x03, +0x02, -0x01, -0x01, -0x05], + [-0x03, -0x03, -0x04, -0x05, -0x02, -0x04, -0x03, -0x04, -0x01, -0x00, +0x01, -0x04, -0x00, +0x08, -0x04, -0x03, -0x02, +0x01, +0x04, -0x01, -0x04, +0x01, -0x04, -0x01, -0x05], + [-0x01, -0x03, -0x02, -0x01, -0x04, -0x01, -0x01, -0x02, -0x02, -0x03, -0x04, -0x01, -0x03, -0x04, +0x0a, -0x01, -0x01, -0x04, -0x03, -0x03, -0x02, -0x03, -0x01, -0x01, -0x05], + [+0x01, -0x01, +0x01, -0x00, -0x01, -0x00, -0x01, -0x00, -0x01, -0x03, -0x03, -0x00, -0x02, -0x03, -0x01, +0x05, +0x02, -0x04, -0x02, -0x02, -0x00, -0x03, -0x00, -0x01, -0x05], + [-0x00, -0x01, -0x00, -0x01, -0x01, -0x01, -0x01, -0x02, -0x02, -0x01, -0x01, -0x01, -0x01, -0x02, -0x01, +0x02, +0x05, -0x03, -0x02, -0x00, -0x00, -0x01, -0x01, -0x01, -0x05], + [-0x03, -0x03, -0x04, -0x05, -0x05, -0x01, -0x03, -0x03, -0x03, -0x03, -0x02, -0x03, -0x01, +0x01, -0x04, -0x04, -0x03, +0x0f, +0x02, -0x03, -0x05, -0x02, -0x02, -0x01, -0x05], + [-0x02, -0x01, -0x02, -0x03, -0x03, -0x01, -0x02, -0x03, +0x02, -0x01, -0x01, -0x02, -0x00, +0x04, -0x03, -0x02, -0x02, +0x02, +0x08, -0x01, -0x03, -0x01, -0x02, -0x01, -0x05], + [-0x00, -0x03, -0x03, -0x04, -0x01, -0x03, -0x03, -0x04, -0x04, +0x04, +0x01, -0x03, +0x01, -0x01, -0x03, -0x02, -0x00, -0x03, -0x01, +0x05, -0x03, +0x02, -0x03, -0x01, -0x05], + [-0x02, -0x01, +0x05, +0x06, -0x03, -0x00, +0x01, -0x01, -0x00, -0x04, -0x04, -0x00, -0x03, -0x04, -0x02, -0x00, -0x00, -0x05, -0x03, -0x03, +0x06, -0x04, +0x01, -0x01, -0x05], + [-0x02, -0x03, -0x04, -0x04, -0x02, -0x03, -0x03, -0x04, -0x03, +0x04, +0x04, -0x03, +0x02, +0x01, -0x03, -0x03, -0x01, -0x02, -0x01, +0x02, -0x04, +0x04, -0x03, -0x01, -0x05], + [-0x01, -0x00, -0x00, +0x01, -0x03, +0x04, +0x05, -0x02, -0x00, -0x03, -0x03, +0x01, -0x01, -0x04, -0x01, -0x00, -0x01, -0x02, -0x02, -0x03, +0x01, -0x03, +0x05, -0x01, -0x05], + [-0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x05], + [-0x05, -0x05, -0x05, -0x05, -0x05, -0x05, -0x05, -0x05, -0x05, -0x05, -0x05, -0x05, -0x05, -0x05, -0x05, -0x05, -0x05, -0x05, -0x05, -0x05, -0x05, -0x05, -0x05, -0x05, +0x01]] + +BLOSUM62 = [[+0x04, -0x01, -0x02, -0x02, -0x00, -0x01, -0x01, -0x00, -0x02, -0x01, -0x01, -0x01, -0x01, -0x02, -0x01, +0x01, -0x00, -0x03, -0x02, -0x00, -0x02, -0x01, -0x01, -0x01, -0x04], + [-0x01, +0x05, -0x00, -0x02, -0x03, +0x01, -0x00, -0x02, -0x00, -0x03, -0x02, +0x02, -0x01, -0x03, -0x02, -0x01, -0x01, -0x03, -0x02, -0x03, -0x01, -0x02, -0x00, -0x01, -0x04], + [-0x02, -0x00, +0x06, +0x01, -0x03, -0x00, -0x00, -0x00, +0x01, -0x03, -0x03, -0x00, -0x02, -0x03, -0x02, +0x01, -0x00, -0x04, -0x02, -0x03, +0x04, -0x03, -0x00, -0x01, -0x04], + [-0x02, -0x02, +0x01, +0x06, -0x03, -0x00, +0x02, -0x01, -0x01, -0x03, -0x04, -0x01, -0x03, -0x03, -0x01, -0x00, -0x01, -0x04, -0x03, -0x03, +0x04, -0x03, +0x01, -0x01, -0x04], + [-0x00, -0x03, -0x03, -0x03, +0x09, -0x03, -0x04, -0x03, -0x03, -0x01, -0x01, -0x03, -0x01, -0x02, -0x03, -0x01, -0x01, -0x02, -0x02, -0x01, -0x03, -0x01, -0x03, -0x01, -0x04], + [-0x01, +0x01, -0x00, -0x00, -0x03, +0x05, +0x02, -0x02, -0x00, -0x03, -0x02, +0x01, -0x00, -0x03, -0x01, -0x00, -0x01, -0x02, -0x01, -0x02, -0x00, -0x02, +0x04, -0x01, -0x04], + [-0x01, -0x00, -0x00, +0x02, -0x04, +0x02, +0x05, -0x02, -0x00, -0x03, -0x03, +0x01, -0x02, -0x03, -0x01, -0x00, -0x01, -0x03, -0x02, -0x02, +0x01, -0x03, +0x04, -0x01, -0x04], + [-0x00, -0x02, -0x00, -0x01, -0x03, -0x02, -0x02, +0x06, -0x02, -0x04, -0x04, -0x02, -0x03, -0x03, -0x02, -0x00, -0x02, -0x02, -0x03, -0x03, -0x01, -0x04, -0x02, -0x01, -0x04], + [-0x02, -0x00, +0x01, -0x01, -0x03, -0x00, -0x00, -0x02, +0x08, -0x03, -0x03, -0x01, -0x02, -0x01, -0x02, -0x01, -0x02, -0x02, +0x02, -0x03, -0x00, -0x03, -0x00, -0x01, -0x04], + [-0x01, -0x03, -0x03, -0x03, -0x01, -0x03, -0x03, -0x04, -0x03, +0x04, +0x02, -0x03, +0x01, -0x00, -0x03, -0x02, -0x01, -0x03, -0x01, +0x03, -0x03, +0x03, -0x03, -0x01, -0x04], + [-0x01, -0x02, -0x03, -0x04, -0x01, -0x02, -0x03, -0x04, -0x03, +0x02, +0x04, -0x02, +0x02, -0x00, -0x03, -0x02, -0x01, -0x02, -0x01, +0x01, -0x04, +0x03, -0x03, -0x01, -0x04], + [-0x01, +0x02, -0x00, -0x01, -0x03, +0x01, +0x01, -0x02, -0x01, -0x03, -0x02, +0x05, -0x01, -0x03, -0x01, -0x00, -0x01, -0x03, -0x02, -0x02, -0x00, -0x03, +0x01, -0x01, -0x04], + [-0x01, -0x01, -0x02, -0x03, -0x01, -0x00, -0x02, -0x03, -0x02, +0x01, +0x02, -0x01, +0x05, -0x00, -0x02, -0x01, -0x01, -0x01, -0x01, +0x01, -0x03, +0x02, -0x01, -0x01, -0x04], + [-0x02, -0x03, -0x03, -0x03, -0x02, -0x03, -0x03, -0x03, -0x01, -0x00, -0x00, -0x03, -0x00, +0x06, -0x04, -0x02, -0x02, +0x01, +0x03, -0x01, -0x03, -0x00, -0x03, -0x01, -0x04], + [-0x01, -0x02, -0x02, -0x01, -0x03, -0x01, -0x01, -0x02, -0x02, -0x03, -0x03, -0x01, -0x02, -0x04, +0x07, -0x01, -0x01, -0x04, -0x03, -0x02, -0x02, -0x03, -0x01, -0x01, -0x04], + [+0x01, -0x01, +0x01, -0x00, -0x01, -0x00, -0x00, -0x00, -0x01, -0x02, -0x02, -0x00, -0x01, -0x02, -0x01, +0x04, +0x01, -0x03, -0x02, -0x02, -0x00, -0x02, -0x00, -0x01, -0x04], + [-0x00, -0x01, -0x00, -0x01, -0x01, -0x01, -0x01, -0x02, -0x02, -0x01, -0x01, -0x01, -0x01, -0x02, -0x01, +0x01, +0x05, -0x02, -0x02, -0x00, -0x01, -0x01, -0x01, -0x01, -0x04], + [-0x03, -0x03, -0x04, -0x04, -0x02, -0x02, -0x03, -0x02, -0x02, -0x03, -0x02, -0x03, -0x01, +0x01, -0x04, -0x03, -0x02, +0x0b, +0x02, -0x03, -0x04, -0x02, -0x02, -0x01, -0x04], + [-0x02, -0x02, -0x02, -0x03, -0x02, -0x01, -0x02, -0x03, +0x02, -0x01, -0x01, -0x02, -0x01, +0x03, -0x03, -0x02, -0x02, +0x02, +0x07, -0x01, -0x03, -0x01, -0x02, -0x01, -0x04], + [-0x00, -0x03, -0x03, -0x03, -0x01, -0x02, -0x02, -0x03, -0x03, +0x03, +0x01, -0x02, +0x01, -0x01, -0x02, -0x02, -0x00, -0x03, -0x01, +0x04, -0x03, +0x02, -0x02, -0x01, -0x04], + [-0x02, -0x01, +0x04, +0x04, -0x03, -0x00, +0x01, -0x01, -0x00, -0x03, -0x04, -0x00, -0x03, -0x03, -0x02, -0x00, -0x01, -0x04, -0x03, -0x03, +0x04, -0x03, -0x00, -0x01, -0x04], + [-0x01, -0x02, -0x03, -0x03, -0x01, -0x02, -0x03, -0x04, -0x03, +0x03, +0x03, -0x03, +0x02, -0x00, -0x03, -0x02, -0x01, -0x02, -0x01, +0x02, -0x03, +0x03, -0x03, -0x01, -0x04], + [-0x01, -0x00, -0x00, +0x01, -0x03, +0x04, +0x04, -0x02, -0x00, -0x03, -0x03, +0x01, -0x01, -0x03, -0x01, -0x00, -0x01, -0x02, -0x02, -0x02, -0x00, -0x03, +0x04, -0x01, -0x04], + [-0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x04], + [-0x04, -0x04, -0x04, -0x04, -0x04, -0x04, -0x04, -0x04, -0x04, -0x04, -0x04, -0x04, -0x04, -0x04, -0x04, -0x04, -0x04, -0x04, -0x04, -0x04, -0x04, -0x04, -0x04, -0x04, +0x01]] + +BLOSUM80 = [[+0x05, -0x02, -0x02, -0x02, -0x01, -0x01, -0x01, -0x00, -0x02, -0x02, -0x02, -0x01, -0x01, -0x03, -0x01, +0x01, -0x00, -0x03, -0x02, -0x00, -0x02, -0x02, -0x01, -0x01, -0x06], + [-0x02, +0x06, -0x01, -0x02, -0x04, +0x01, -0x01, -0x03, -0x00, -0x03, -0x03, +0x02, -0x02, -0x04, -0x02, -0x01, -0x01, -0x04, -0x03, -0x03, -0x01, -0x03, -0x00, -0x01, -0x06], + [-0x02, -0x01, +0x06, +0x01, -0x03, -0x00, -0x01, -0x01, -0x00, -0x04, -0x04, -0x00, -0x03, -0x04, -0x03, -0x00, -0x00, -0x04, -0x03, -0x04, +0x05, -0x04, -0x00, -0x01, -0x06], + [-0x02, -0x02, +0x01, +0x06, -0x04, -0x01, +0x01, -0x02, -0x02, -0x04, -0x05, -0x01, -0x04, -0x04, -0x02, -0x01, -0x01, -0x06, -0x04, -0x04, +0x05, -0x05, +0x01, -0x01, -0x06], + [-0x01, -0x04, -0x03, -0x04, +0x09, -0x04, -0x05, -0x04, -0x04, -0x02, -0x02, -0x04, -0x02, -0x03, -0x04, -0x02, -0x01, -0x03, -0x03, -0x01, -0x04, -0x02, -0x04, -0x01, -0x06], + [-0x01, +0x01, -0x00, -0x01, -0x04, +0x06, +0x02, -0x02, +0x01, -0x03, -0x03, +0x01, -0x00, -0x04, -0x02, -0x00, -0x01, -0x03, -0x02, -0x03, -0x00, -0x03, +0x04, -0x01, -0x06], + [-0x01, -0x01, -0x01, +0x01, -0x05, +0x02, +0x06, -0x03, -0x00, -0x04, -0x04, +0x01, -0x02, -0x04, -0x02, -0x00, -0x01, -0x04, -0x03, -0x03, +0x01, -0x04, +0x05, -0x01, -0x06], + [-0x00, -0x03, -0x01, -0x02, -0x04, -0x02, -0x03, +0x06, -0x03, -0x05, -0x04, -0x02, -0x04, -0x04, -0x03, -0x01, -0x02, -0x04, -0x04, -0x04, -0x01, -0x05, -0x03, -0x01, -0x06], + [-0x02, -0x00, -0x00, -0x02, -0x04, +0x01, -0x00, -0x03, +0x08, -0x04, -0x03, -0x01, -0x02, -0x02, -0x03, -0x01, -0x02, -0x03, +0x02, -0x04, -0x01, -0x04, -0x00, -0x01, -0x06], + [-0x02, -0x03, -0x04, -0x04, -0x02, -0x03, -0x04, -0x05, -0x04, +0x05, +0x01, -0x03, +0x01, -0x01, -0x04, -0x03, -0x01, -0x03, -0x02, +0x03, -0x04, +0x03, -0x04, -0x01, -0x06], + [-0x02, -0x03, -0x04, -0x05, -0x02, -0x03, -0x04, -0x04, -0x03, +0x01, +0x04, -0x03, +0x02, -0x00, -0x03, -0x03, -0x02, -0x02, -0x02, +0x01, -0x04, +0x03, -0x03, -0x01, -0x06], + [-0x01, +0x02, -0x00, -0x01, -0x04, +0x01, +0x01, -0x02, -0x01, -0x03, -0x03, +0x05, -0x02, -0x04, -0x01, -0x01, -0x01, -0x04, -0x03, -0x03, -0x01, -0x03, +0x01, -0x01, -0x06], + [-0x01, -0x02, -0x03, -0x04, -0x02, -0x00, -0x02, -0x04, -0x02, +0x01, +0x02, -0x02, +0x06, -0x00, -0x03, -0x02, -0x01, -0x02, -0x02, +0x01, -0x03, +0x02, -0x01, -0x01, -0x06], + [-0x03, -0x04, -0x04, -0x04, -0x03, -0x04, -0x04, -0x04, -0x02, -0x01, -0x00, -0x04, -0x00, +0x06, -0x04, -0x03, -0x02, -0x00, +0x03, -0x01, -0x04, -0x00, -0x04, -0x01, -0x06], + [-0x01, -0x02, -0x03, -0x02, -0x04, -0x02, -0x02, -0x03, -0x03, -0x04, -0x03, -0x01, -0x03, -0x04, +0x08, -0x01, -0x02, -0x05, -0x04, -0x03, -0x02, -0x04, -0x02, -0x01, -0x06], + [+0x01, -0x01, -0x00, -0x01, -0x02, -0x00, -0x00, -0x01, -0x01, -0x03, -0x03, -0x01, -0x02, -0x03, -0x01, +0x05, +0x01, -0x04, -0x02, -0x02, -0x00, -0x03, -0x00, -0x01, -0x06], + [-0x00, -0x01, -0x00, -0x01, -0x01, -0x01, -0x01, -0x02, -0x02, -0x01, -0x02, -0x01, -0x01, -0x02, -0x02, +0x01, +0x05, -0x04, -0x02, -0x00, -0x01, -0x01, -0x01, -0x01, -0x06], + [-0x03, -0x04, -0x04, -0x06, -0x03, -0x03, -0x04, -0x04, -0x03, -0x03, -0x02, -0x04, -0x02, -0x00, -0x05, -0x04, -0x04, +0x0b, +0x02, -0x03, -0x05, -0x03, -0x03, -0x01, -0x06], + [-0x02, -0x03, -0x03, -0x04, -0x03, -0x02, -0x03, -0x04, +0x02, -0x02, -0x02, -0x03, -0x02, +0x03, -0x04, -0x02, -0x02, +0x02, +0x07, -0x02, -0x03, -0x02, -0x03, -0x01, -0x06], + [-0x00, -0x03, -0x04, -0x04, -0x01, -0x03, -0x03, -0x04, -0x04, +0x03, +0x01, -0x03, +0x01, -0x01, -0x03, -0x02, -0x00, -0x03, -0x02, +0x04, -0x04, +0x02, -0x03, -0x01, -0x06], + [-0x02, -0x01, +0x05, +0x05, -0x04, -0x00, +0x01, -0x01, -0x01, -0x04, -0x04, -0x01, -0x03, -0x04, -0x02, -0x00, -0x01, -0x05, -0x03, -0x04, +0x05, -0x04, -0x00, -0x01, -0x06], + [-0x02, -0x03, -0x04, -0x05, -0x02, -0x03, -0x04, -0x05, -0x04, +0x03, +0x03, -0x03, +0x02, -0x00, -0x04, -0x03, -0x01, -0x03, -0x02, +0x02, -0x04, +0x03, -0x03, -0x01, -0x06], + [-0x01, -0x00, -0x00, +0x01, -0x04, +0x04, +0x05, -0x03, -0x00, -0x04, -0x03, +0x01, -0x01, -0x04, -0x02, -0x00, -0x01, -0x03, -0x03, -0x03, -0x00, -0x03, +0x05, -0x01, -0x06], + [-0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x06], + [-0x06, -0x06, -0x06, -0x06, -0x06, -0x06, -0x06, -0x06, -0x06, -0x06, -0x06, -0x06, -0x06, -0x06, -0x06, -0x06, -0x06, -0x06, -0x06, -0x06, -0x06, -0x06, -0x06, -0x06, +0x01]] + +BLOSUM90 = [[+0x05, -0x02, -0x02, -0x03, -0x01, -0x01, -0x01, -0x00, -0x02, -0x02, -0x02, -0x01, -0x02, -0x03, -0x01, +0x01, -0x00, -0x04, -0x03, -0x01, -0x02, -0x02, -0x01, -0x01, -0x06], + [-0x02, +0x06, -0x01, -0x03, -0x05, +0x01, -0x01, -0x03, -0x00, -0x04, -0x03, +0x02, -0x02, -0x04, -0x03, -0x01, -0x02, -0x04, -0x03, -0x03, -0x02, -0x03, -0x00, -0x01, -0x06], + [-0x02, -0x01, +0x07, +0x01, -0x04, -0x00, -0x01, -0x01, -0x00, -0x04, -0x04, -0x00, -0x03, -0x04, -0x03, -0x00, -0x00, -0x05, -0x03, -0x04, +0x05, -0x04, -0x01, -0x01, -0x06], + [-0x03, -0x03, +0x01, +0x07, -0x05, -0x01, +0x01, -0x02, -0x02, -0x05, -0x05, -0x01, -0x04, -0x05, -0x03, -0x01, -0x02, -0x06, -0x04, -0x05, +0x05, -0x05, +0x01, -0x01, -0x06], + [-0x01, -0x05, -0x04, -0x05, +0x09, -0x04, -0x06, -0x04, -0x05, -0x02, -0x02, -0x04, -0x02, -0x03, -0x04, -0x02, -0x02, -0x04, -0x04, -0x02, -0x04, -0x02, -0x05, -0x01, -0x06], + [-0x01, +0x01, -0x00, -0x01, -0x04, +0x07, +0x02, -0x03, +0x01, -0x04, -0x03, +0x01, -0x00, -0x04, -0x02, -0x01, -0x01, -0x03, -0x03, -0x03, -0x01, -0x03, +0x05, -0x01, -0x06], + [-0x01, -0x01, -0x01, +0x01, -0x06, +0x02, +0x06, -0x03, -0x01, -0x04, -0x04, -0x00, -0x03, -0x05, -0x02, -0x01, -0x01, -0x05, -0x04, -0x03, +0x01, -0x04, +0x05, -0x01, -0x06], + [-0x00, -0x03, -0x01, -0x02, -0x04, -0x03, -0x03, +0x06, -0x03, -0x05, -0x05, -0x02, -0x04, -0x05, -0x03, -0x01, -0x03, -0x04, -0x05, -0x05, -0x02, -0x05, -0x03, -0x01, -0x06], + [-0x02, -0x00, -0x00, -0x02, -0x05, +0x01, -0x01, -0x03, +0x08, -0x04, -0x04, -0x01, -0x03, -0x02, -0x03, -0x02, -0x02, -0x03, +0x01, -0x04, -0x01, -0x04, -0x00, -0x01, -0x06], + [-0x02, -0x04, -0x04, -0x05, -0x02, -0x04, -0x04, -0x05, -0x04, +0x05, +0x01, -0x04, +0x01, -0x01, -0x04, -0x03, -0x01, -0x04, -0x02, +0x03, -0x05, +0x03, -0x04, -0x01, -0x06], + [-0x02, -0x03, -0x04, -0x05, -0x02, -0x03, -0x04, -0x05, -0x04, +0x01, +0x05, -0x03, +0x02, -0x00, -0x04, -0x03, -0x02, -0x03, -0x02, -0x00, -0x05, +0x04, -0x04, -0x01, -0x06], + [-0x01, +0x02, -0x00, -0x01, -0x04, +0x01, -0x00, -0x02, -0x01, -0x04, -0x03, +0x06, -0x02, -0x04, -0x02, -0x01, -0x01, -0x05, -0x03, -0x03, -0x01, -0x03, +0x01, -0x01, -0x06], + [-0x02, -0x02, -0x03, -0x04, -0x02, -0x00, -0x03, -0x04, -0x03, +0x01, +0x02, -0x02, +0x07, -0x01, -0x03, -0x02, -0x01, -0x02, -0x02, -0x00, -0x04, +0x02, -0x02, -0x01, -0x06], + [-0x03, -0x04, -0x04, -0x05, -0x03, -0x04, -0x05, -0x05, -0x02, -0x01, -0x00, -0x04, -0x01, +0x07, -0x04, -0x03, -0x03, -0x00, +0x03, -0x02, -0x04, -0x00, -0x04, -0x01, -0x06], + [-0x01, -0x03, -0x03, -0x03, -0x04, -0x02, -0x02, -0x03, -0x03, -0x04, -0x04, -0x02, -0x03, -0x04, +0x08, -0x02, -0x02, -0x05, -0x04, -0x03, -0x03, -0x04, -0x02, -0x01, -0x06], + [+0x01, -0x01, -0x00, -0x01, -0x02, -0x01, -0x01, -0x01, -0x02, -0x03, -0x03, -0x01, -0x02, -0x03, -0x02, +0x05, +0x01, -0x04, -0x03, -0x02, -0x00, -0x03, -0x01, -0x01, -0x06], + [-0x00, -0x02, -0x00, -0x02, -0x02, -0x01, -0x01, -0x03, -0x02, -0x01, -0x02, -0x01, -0x01, -0x03, -0x02, +0x01, +0x06, -0x04, -0x02, -0x01, -0x01, -0x02, -0x01, -0x01, -0x06], + [-0x04, -0x04, -0x05, -0x06, -0x04, -0x03, -0x05, -0x04, -0x03, -0x04, -0x03, -0x05, -0x02, -0x00, -0x05, -0x04, -0x04, +0x0b, +0x02, -0x03, -0x06, -0x03, -0x04, -0x01, -0x06], + [-0x03, -0x03, -0x03, -0x04, -0x04, -0x03, -0x04, -0x05, +0x01, -0x02, -0x02, -0x03, -0x02, +0x03, -0x04, -0x03, -0x02, +0x02, +0x08, -0x03, -0x04, -0x02, -0x03, -0x01, -0x06], + [-0x01, -0x03, -0x04, -0x05, -0x02, -0x03, -0x03, -0x05, -0x04, +0x03, -0x00, -0x03, -0x00, -0x02, -0x03, -0x02, -0x01, -0x03, -0x03, +0x05, -0x04, +0x01, -0x03, -0x01, -0x06], + [-0x02, -0x02, +0x05, +0x05, -0x04, -0x01, +0x01, -0x02, -0x01, -0x05, -0x05, -0x01, -0x04, -0x04, -0x03, -0x00, -0x01, -0x06, -0x04, -0x04, +0x05, -0x05, -0x00, -0x01, -0x06], + [-0x02, -0x03, -0x04, -0x05, -0x02, -0x03, -0x04, -0x05, -0x04, +0x03, +0x04, -0x03, +0x02, -0x00, -0x04, -0x03, -0x02, -0x03, -0x02, +0x01, -0x05, +0x04, -0x04, -0x01, -0x06], + [-0x01, -0x00, -0x01, +0x01, -0x05, +0x05, +0x05, -0x03, -0x00, -0x04, -0x04, +0x01, -0x02, -0x04, -0x02, -0x01, -0x01, -0x04, -0x03, -0x03, -0x00, -0x04, +0x05, -0x01, -0x06], + [-0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x06]] + +BLOSUM_VOCABULARY = { + "A": 0, + "R": 1, + "N": 2, + "D": 3, + "C": 4, + "Q": 5, + "E": 6, + "G": 7, + "H": 8, + "I": 9, + "L": 10, + "K": 11, + "M": 12, + "F": 13, + "P": 14, + "S": 15, + "T": 16, + "W": 17, + "Y": 18, + "V": 19, + "B": 20, + "J": 21, + "Z": 22, + "X": 23, + "*": 24, +} + +PAM10 = [[+0x07, -0x0A, -0x07, -0x06, -0x0A, -0x07, -0x05, -0x04, -0x0B, -0x08, -0x09, -0x0A, -0x08, -0x0C, -0x04, -0x03, -0x03, -0x14, -0x0B, -0x05, -0x06, -0x06, -0x06, -0x17], + [-0x0A, +0x09, -0x09, -0x11, -0x0B, -0x04, -0x0F, -0x0D, -0x04, -0x08, -0x0C, -0x02, -0x07, -0x0C, -0x07, -0x06, -0x0A, -0x05, -0x0E, -0x0B, -0x0B, -0x07, -0x09, -0x17], + [-0x07, -0x09, +0x09, -0x01, -0x11, -0x07, -0x05, -0x06, -0x02, -0x08, -0x0A, -0x04, -0x0F, -0x0C, -0x09, -0x02, -0x05, -0x0B, -0x07, -0x0C, +0x07, -0x06, -0x06, -0x17], + [-0x06, -0x11, -0x01, +0x08, -0x15, -0x06, +0x00, -0x06, -0x07, -0x0B, -0x13, -0x08, -0x11, -0x15, -0x0C, -0x07, -0x08, -0x15, -0x11, -0x0B, +0x07, -0x01, -0x09, -0x17], + [-0x0A, -0x0B, -0x11, -0x15, +0x0A, -0x14, -0x14, -0x0D, -0x0A, -0x09, -0x15, -0x14, -0x14, -0x13, -0x0B, -0x06, -0x0B, -0x16, -0x07, -0x09, -0x12, -0x14, -0x0D, -0x17], + [-0x07, -0x04, -0x07, -0x06, -0x14, +0x09, -0x01, -0x0A, -0x02, -0x0B, -0x08, -0x06, -0x07, -0x13, -0x06, -0x08, -0x09, -0x13, -0x12, -0x0A, -0x06, +0x07, -0x08, -0x17], + [-0x05, -0x0F, -0x05, +0x00, -0x14, -0x01, +0x08, -0x07, -0x09, -0x08, -0x0D, -0x07, -0x0A, -0x14, -0x09, -0x07, -0x09, -0x17, -0x0B, -0x0A, -0x01, +0x07, -0x08, -0x17], + [-0x04, -0x0D, -0x06, -0x06, -0x0D, -0x0A, -0x07, +0x07, -0x0D, -0x11, -0x0E, -0x0A, -0x0C, -0x0C, -0x0A, -0x04, -0x0A, -0x15, -0x14, -0x09, -0x06, -0x08, -0x08, -0x17], + [-0x0B, -0x04, -0x02, -0x07, -0x0A, -0x02, -0x09, -0x0D, +0x0A, -0x0D, -0x09, -0x0A, -0x11, -0x09, -0x07, -0x09, -0x0B, -0x0A, -0x06, -0x09, -0x04, -0x04, -0x08, -0x17], + [-0x08, -0x08, -0x08, -0x0B, -0x09, -0x0B, -0x08, -0x11, -0x0D, +0x09, -0x04, -0x09, -0x03, -0x05, -0x0C, -0x0A, -0x05, -0x14, -0x09, -0x01, -0x09, -0x09, -0x08, -0x17], + [-0x09, -0x0C, -0x0A, -0x13, -0x15, -0x08, -0x0D, -0x0E, -0x09, -0x04, +0x07, -0x0B, -0x02, -0x05, -0x0A, -0x0C, -0x0A, -0x09, -0x0A, -0x05, -0x0C, -0x0A, -0x09, -0x17], + [-0x0A, -0x02, -0x04, -0x08, -0x14, -0x06, -0x07, -0x0A, -0x0A, -0x09, -0x0B, +0x07, -0x04, -0x14, -0x0A, -0x07, -0x06, -0x12, -0x0C, -0x0D, -0x05, -0x06, -0x08, -0x17], + [-0x08, -0x07, -0x0F, -0x11, -0x14, -0x07, -0x0A, -0x0C, -0x11, -0x03, -0x02, -0x04, +0x0C, -0x07, -0x0B, -0x08, -0x07, -0x13, -0x11, -0x04, -0x10, -0x08, -0x09, -0x17], + [-0x0C, -0x0C, -0x0C, -0x15, -0x13, -0x13, -0x14, -0x0C, -0x09, -0x05, -0x05, -0x14, -0x07, +0x09, -0x0D, -0x09, -0x0C, -0x07, -0x01, -0x0C, -0x0E, -0x14, -0x0C, -0x17], + [-0x04, -0x07, -0x09, -0x0C, -0x0B, -0x06, -0x09, -0x0A, -0x07, -0x0C, -0x0A, -0x0A, -0x0B, -0x0D, +0x08, -0x04, -0x07, -0x14, -0x14, -0x09, -0x0A, -0x07, -0x08, -0x17], + [-0x03, -0x06, -0x02, -0x07, -0x06, -0x08, -0x07, -0x04, -0x09, -0x0A, -0x0C, -0x07, -0x08, -0x09, -0x04, +0x07, -0x02, -0x08, -0x0A, -0x0A, -0x04, -0x08, -0x06, -0x17], + [-0x03, -0x0A, -0x05, -0x08, -0x0B, -0x09, -0x09, -0x0A, -0x0B, -0x05, -0x0A, -0x06, -0x07, -0x0C, -0x07, -0x02, +0x08, -0x13, -0x09, -0x06, -0x06, -0x09, -0x07, -0x17], + [-0x14, -0x05, -0x0B, -0x15, -0x16, -0x13, -0x17, -0x15, -0x0A, -0x14, -0x09, -0x12, -0x13, -0x07, -0x14, -0x08, -0x13, +0x0D, -0x08, -0x16, -0x0D, -0x15, -0x10, -0x17], + [-0x0B, -0x0E, -0x07, -0x11, -0x07, -0x12, -0x0B, -0x14, -0x06, -0x09, -0x0A, -0x0C, -0x11, -0x01, -0x14, -0x0A, -0x09, -0x08, +0x0A, -0x0A, -0x09, -0x0D, -0x0B, -0x17], + [-0x05, -0x0B, -0x0C, -0x0B, -0x09, -0x0A, -0x0A, -0x09, -0x09, -0x01, -0x05, -0x0D, -0x04, -0x0C, -0x09, -0x0A, -0x06, -0x16, -0x0A, +0x08, -0x0B, -0x0A, -0x08, -0x17], + [-0x06, -0x0B, +0x07, +0x07, -0x12, -0x06, -0x01, -0x06, -0x04, -0x09, -0x0C, -0x05, -0x10, -0x0E, -0x0A, -0x04, -0x06, -0x0D, -0x09, -0x0B, +0x07, -0x03, -0x08, -0x17], + [-0x06, -0x07, -0x06, -0x01, -0x14, +0x07, +0x07, -0x08, -0x04, -0x09, -0x0A, -0x06, -0x08, -0x14, -0x07, -0x08, -0x09, -0x15, -0x0D, -0x0A, -0x03, +0x07, -0x08, -0x17], + [-0x06, -0x09, -0x06, -0x09, -0x0D, -0x08, -0x08, -0x08, -0x08, -0x08, -0x09, -0x08, -0x09, -0x0C, -0x08, -0x06, -0x07, -0x10, -0x0B, -0x08, -0x08, -0x08, -0x08, -0x17], + [-0x17, -0x17, -0x17, -0x17, -0x17, -0x17, -0x17, -0x17, -0x17, -0x17, -0x17, -0x17, -0x17, -0x17, -0x17, -0x17, -0x17, -0x17, -0x17, -0x17, -0x17, -0x17, -0x17, +0x01]] + +PAM20 = [[+0x06, -0x08, -0x05, -0x04, -0x08, -0x05, -0x03, -0x03, -0x08, -0x06, -0x07, -0x08, -0x06, -0x09, -0x02, -0x01, -0x01, -0x10, -0x09, -0x03, -0x05, -0x04, -0x04, -0x13], + [-0x08, +0x09, -0x07, -0x0C, -0x09, -0x02, -0x0B, -0x0B, -0x03, -0x06, -0x0A, -0x01, -0x05, -0x0A, -0x05, -0x04, -0x08, -0x03, -0x0B, -0x09, -0x09, -0x05, -0x07, -0x13], + [-0x05, -0x07, +0x08, +0x01, -0x0D, -0x05, -0x03, -0x04, -0x01, -0x06, -0x08, -0x02, -0x0B, -0x0A, -0x07, -0x01, -0x03, -0x09, -0x05, -0x09, +0x06, -0x04, -0x04, -0x13], + [-0x04, -0x0C, +0x01, +0x08, -0x10, -0x04, +0x02, -0x04, -0x05, -0x09, -0x0F, -0x06, -0x0D, -0x11, -0x09, -0x05, -0x06, -0x11, -0x0D, -0x09, +0x06, +0x00, -0x07, -0x13], + [-0x08, -0x09, -0x0D, -0x10, +0x0A, -0x10, -0x10, -0x0B, -0x08, -0x07, -0x11, -0x10, -0x10, -0x0F, -0x09, -0x04, -0x09, -0x12, -0x05, -0x07, -0x0E, -0x10, -0x0B, -0x13], + [-0x05, -0x02, -0x05, -0x04, -0x10, +0x09, +0x00, -0x08, +0x00, -0x09, -0x06, -0x04, -0x05, -0x0F, -0x04, -0x06, -0x07, -0x0F, -0x0E, -0x08, -0x04, +0x07, -0x06, -0x13], + [-0x03, -0x0B, -0x03, +0x02, -0x10, +0x00, +0x08, -0x05, -0x06, -0x06, -0x0A, -0x05, -0x08, -0x10, -0x07, -0x05, -0x07, -0x13, -0x09, -0x08, +0x00, +0x06, -0x06, -0x13], + [-0x03, -0x0B, -0x04, -0x04, -0x0B, -0x08, -0x05, +0x07, -0x0A, -0x0D, -0x0C, -0x08, -0x0A, -0x0A, -0x07, -0x03, -0x07, -0x11, -0x10, -0x07, -0x04, -0x06, -0x06, -0x13], + [-0x08, -0x03, -0x01, -0x05, -0x08, +0x00, -0x06, -0x0A, +0x09, -0x0B, -0x07, -0x08, -0x0D, -0x07, -0x05, -0x07, -0x08, -0x08, -0x04, -0x07, -0x02, -0x02, -0x06, -0x13], + [-0x06, -0x06, -0x06, -0x09, -0x07, -0x09, -0x06, -0x0D, -0x0B, +0x09, -0x02, -0x07, -0x02, -0x03, -0x0A, -0x08, -0x03, -0x10, -0x07, +0x01, -0x07, -0x07, -0x06, -0x13], + [-0x07, -0x0A, -0x08, -0x0F, -0x11, -0x06, -0x0A, -0x0C, -0x07, -0x02, +0x07, -0x09, +0x00, -0x04, -0x08, -0x09, -0x08, -0x07, -0x08, -0x03, -0x0A, -0x08, -0x07, -0x13], + [-0x08, -0x01, -0x02, -0x06, -0x10, -0x04, -0x05, -0x08, -0x08, -0x07, -0x09, +0x07, -0x03, -0x10, -0x08, -0x05, -0x04, -0x0E, -0x0A, -0x0A, -0x03, -0x05, -0x06, -0x13], + [-0x06, -0x05, -0x0B, -0x0D, -0x10, -0x05, -0x08, -0x0A, -0x0D, -0x02, +0x00, -0x03, +0x0B, -0x05, -0x09, -0x06, -0x05, -0x0F, -0x0D, -0x02, -0x0C, -0x06, -0x06, -0x13], + [-0x09, -0x0A, -0x0A, -0x11, -0x0F, -0x0F, -0x10, -0x0A, -0x07, -0x03, -0x04, -0x10, -0x05, +0x09, -0x0B, -0x07, -0x0A, -0x06, +0x01, -0x09, -0x0C, -0x10, -0x09, -0x13], + [-0x02, -0x05, -0x07, -0x09, -0x09, -0x04, -0x07, -0x07, -0x05, -0x0A, -0x08, -0x08, -0x09, -0x0B, +0x08, -0x03, -0x05, -0x10, -0x10, -0x07, -0x08, -0x05, -0x06, -0x13], + [-0x01, -0x04, -0x01, -0x05, -0x04, -0x06, -0x05, -0x03, -0x07, -0x08, -0x09, -0x05, -0x06, -0x07, -0x03, +0x07, +0x00, -0x06, -0x08, -0x08, -0x02, -0x06, -0x04, -0x13], + [-0x01, -0x08, -0x03, -0x06, -0x09, -0x07, -0x07, -0x07, -0x08, -0x03, -0x08, -0x04, -0x05, -0x0A, -0x05, +0x00, +0x07, -0x0F, -0x07, -0x04, -0x04, -0x07, -0x05, -0x13], + [-0x10, -0x03, -0x09, -0x11, -0x12, -0x0F, -0x13, -0x11, -0x08, -0x10, -0x07, -0x0E, -0x0F, -0x06, -0x10, -0x06, -0x0F, +0x0D, -0x06, -0x12, -0x0B, -0x11, -0x0D, -0x13], + [-0x09, -0x0B, -0x05, -0x0D, -0x05, -0x0E, -0x09, -0x10, -0x04, -0x07, -0x08, -0x0A, -0x0D, +0x01, -0x10, -0x08, -0x07, -0x06, +0x0A, -0x08, -0x07, -0x0B, -0x09, -0x13], + [-0x03, -0x09, -0x09, -0x09, -0x07, -0x08, -0x08, -0x07, -0x07, +0x01, -0x03, -0x0A, -0x02, -0x09, -0x07, -0x08, -0x04, -0x12, -0x08, +0x07, -0x09, -0x08, -0x06, -0x13], + [-0x05, -0x09, +0x06, +0x06, -0x0E, -0x04, +0x00, -0x04, -0x02, -0x07, -0x0A, -0x03, -0x0C, -0x0C, -0x08, -0x02, -0x04, -0x0B, -0x07, -0x09, +0x06, -0x01, -0x06, -0x13], + [-0x04, -0x05, -0x04, +0x00, -0x10, +0x07, +0x06, -0x06, -0x02, -0x07, -0x08, -0x05, -0x06, -0x10, -0x05, -0x06, -0x07, -0x11, -0x0B, -0x08, -0x01, +0x06, -0x06, -0x13], + [-0x04, -0x07, -0x04, -0x07, -0x0B, -0x06, -0x06, -0x06, -0x06, -0x06, -0x07, -0x06, -0x06, -0x09, -0x06, -0x04, -0x05, -0x0D, -0x09, -0x06, -0x06, -0x06, -0x06, -0x13], + [-0x13, -0x13, -0x13, -0x13, -0x13, -0x13, -0x13, -0x13, -0x13, -0x13, -0x13, -0x13, -0x13, -0x13, -0x13, -0x13, -0x13, -0x13, -0x13, -0x13, -0x13, -0x13, -0x13, +0x01]] + +PAM30 = [[+0x06, -0x07, -0x04, -0x03, -0x06, -0x04, -0x02, -0x02, -0x07, -0x05, -0x06, -0x07, -0x05, -0x08, -0x02, +0x00, -0x01, -0x0D, -0x08, -0x02, -0x03, -0x03, -0x03, -0x11], + [-0x07, +0x08, -0x06, -0x0A, -0x08, -0x02, -0x09, -0x09, -0x02, -0x05, -0x08, +0x00, -0x04, -0x09, -0x04, -0x03, -0x06, -0x02, -0x0A, -0x08, -0x07, -0x04, -0x06, -0x11], + [-0x04, -0x06, +0x08, +0x02, -0x0B, -0x03, -0x02, -0x03, +0x00, -0x05, -0x07, -0x01, -0x09, -0x09, -0x06, +0x00, -0x02, -0x08, -0x04, -0x08, +0x06, -0x03, -0x03, -0x11], + [-0x03, -0x0A, +0x02, +0x08, -0x0E, -0x02, +0x02, -0x03, -0x04, -0x07, -0x0C, -0x04, -0x0B, -0x0F, -0x08, -0x04, -0x05, -0x0F, -0x0B, -0x08, +0x06, +0x01, -0x05, -0x11], + [-0x06, -0x08, -0x0B, -0x0E, +0x0A, -0x0E, -0x0E, -0x09, -0x07, -0x06, -0x0F, -0x0E, -0x0D, -0x0D, -0x08, -0x03, -0x08, -0x0F, -0x04, -0x06, -0x0C, -0x0E, -0x09, -0x11], + [-0x04, -0x02, -0x03, -0x02, -0x0E, +0x08, +0x01, -0x07, +0x01, -0x08, -0x05, -0x03, -0x04, -0x0D, -0x03, -0x05, -0x05, -0x0D, -0x0C, -0x07, -0x03, +0x06, -0x05, -0x11], + [-0x02, -0x09, -0x02, +0x02, -0x0E, +0x01, +0x08, -0x04, -0x05, -0x05, -0x09, -0x04, -0x07, -0x0E, -0x05, -0x04, -0x06, -0x11, -0x08, -0x06, +0x01, +0x06, -0x05, -0x11], + [-0x02, -0x09, -0x03, -0x03, -0x09, -0x07, -0x04, +0x06, -0x09, -0x0B, -0x0A, -0x07, -0x08, -0x09, -0x06, -0x02, -0x06, -0x0F, -0x0E, -0x05, -0x03, -0x05, -0x05, -0x11], + [-0x07, -0x02, +0x00, -0x04, -0x07, +0x01, -0x05, -0x09, +0x09, -0x09, -0x06, -0x06, -0x0A, -0x06, -0x04, -0x06, -0x07, -0x07, -0x03, -0x06, -0x01, -0x01, -0x05, -0x11], + [-0x05, -0x05, -0x05, -0x07, -0x06, -0x08, -0x05, -0x0B, -0x09, +0x08, -0x01, -0x06, -0x01, -0x02, -0x08, -0x07, -0x02, -0x0E, -0x06, +0x02, -0x06, -0x06, -0x05, -0x11], + [-0x06, -0x08, -0x07, -0x0C, -0x0F, -0x05, -0x09, -0x0A, -0x06, -0x01, +0x07, -0x08, +0x01, -0x03, -0x07, -0x08, -0x07, -0x06, -0x07, -0x02, -0x09, -0x07, -0x06, -0x11], + [-0x07, +0x00, -0x01, -0x04, -0x0E, -0x03, -0x04, -0x07, -0x06, -0x06, -0x08, +0x07, -0x02, -0x0E, -0x06, -0x04, -0x03, -0x0C, -0x09, -0x09, -0x02, -0x04, -0x05, -0x11], + [-0x05, -0x04, -0x09, -0x0B, -0x0D, -0x04, -0x07, -0x08, -0x0A, -0x01, +0x01, -0x02, +0x0B, -0x04, -0x08, -0x05, -0x04, -0x0D, -0x0B, -0x01, -0x0A, -0x05, -0x05, -0x11], + [-0x08, -0x09, -0x09, -0x0F, -0x0D, -0x0D, -0x0E, -0x09, -0x06, -0x02, -0x03, -0x0E, -0x04, +0x09, -0x0A, -0x06, -0x09, -0x04, +0x02, -0x08, -0x0A, -0x0D, -0x08, -0x11], + [-0x02, -0x04, -0x06, -0x08, -0x08, -0x03, -0x05, -0x06, -0x04, -0x08, -0x07, -0x06, -0x08, -0x0A, +0x08, -0x02, -0x04, -0x0E, -0x0D, -0x06, -0x07, -0x04, -0x05, -0x11], + [+0x00, -0x03, +0x00, -0x04, -0x03, -0x05, -0x04, -0x02, -0x06, -0x07, -0x08, -0x04, -0x05, -0x06, -0x02, +0x06, +0x00, -0x05, -0x07, -0x06, -0x01, -0x05, -0x03, -0x11], + [-0x01, -0x06, -0x02, -0x05, -0x08, -0x05, -0x06, -0x06, -0x07, -0x02, -0x07, -0x03, -0x04, -0x09, -0x04, +0x00, +0x07, -0x0D, -0x06, -0x03, -0x03, -0x06, -0x04, -0x11], + [-0x0D, -0x02, -0x08, -0x0F, -0x0F, -0x0D, -0x11, -0x0F, -0x07, -0x0E, -0x06, -0x0C, -0x0D, -0x04, -0x0E, -0x05, -0x0D, +0x0D, -0x05, -0x0F, -0x0A, -0x0E, -0x0B, -0x11], + [-0x08, -0x0A, -0x04, -0x0B, -0x04, -0x0C, -0x08, -0x0E, -0x03, -0x06, -0x07, -0x09, -0x0B, +0x02, -0x0D, -0x07, -0x06, -0x05, +0x0A, -0x07, -0x06, -0x09, -0x07, -0x11], + [-0x02, -0x08, -0x08, -0x08, -0x06, -0x07, -0x06, -0x05, -0x06, +0x02, -0x02, -0x09, -0x01, -0x08, -0x06, -0x06, -0x03, -0x0F, -0x07, +0x07, -0x08, -0x06, -0x05, -0x11], + [-0x03, -0x07, +0x06, +0x06, -0x0C, -0x03, +0x01, -0x03, -0x01, -0x06, -0x09, -0x02, -0x0A, -0x0A, -0x07, -0x01, -0x03, -0x0A, -0x06, -0x08, +0x06, +0x00, -0x05, -0x11], + [-0x03, -0x04, -0x03, +0x01, -0x0E, +0x06, +0x06, -0x05, -0x01, -0x06, -0x07, -0x04, -0x05, -0x0D, -0x04, -0x05, -0x06, -0x0E, -0x09, -0x06, +0x00, +0x06, -0x05, -0x11], + [-0x03, -0x06, -0x03, -0x05, -0x09, -0x05, -0x05, -0x05, -0x05, -0x05, -0x06, -0x05, -0x05, -0x08, -0x05, -0x03, -0x04, -0x0B, -0x07, -0x05, -0x05, -0x05, -0x05, -0x11], + [-0x11, -0x11, -0x11, -0x11, -0x11, -0x11, -0x11, -0x11, -0x11, -0x11, -0x11, -0x11, -0x11, -0x11, -0x11, -0x11, -0x11, -0x11, -0x11, -0x11, -0x11, -0x11, -0x11, +0x01]] + +PAM40 = [[+0x06, -0x06, -0x03, -0x03, -0x06, -0x03, -0x02, -0x01, -0x06, -0x04, -0x05, -0x06, -0x04, -0x07, -0x01, +0x00, +0x00, -0x0C, -0x07, -0x02, -0x03, -0x02, -0x03, -0x0F], + [-0x06, +0x08, -0x05, -0x09, -0x07, -0x01, -0x08, -0x08, -0x01, -0x05, -0x08, +0x01, -0x03, -0x08, -0x03, -0x02, -0x05, -0x01, -0x09, -0x07, -0x06, -0x03, -0x05, -0x0F], + [-0x03, -0x05, +0x07, +0x02, -0x09, -0x03, -0x01, -0x02, +0x01, -0x04, -0x06, +0x00, -0x07, -0x08, -0x05, +0x00, -0x01, -0x07, -0x04, -0x07, +0x06, -0x02, -0x03, -0x0F], + [-0x03, -0x09, +0x02, +0x07, -0x0C, -0x02, +0x03, -0x03, -0x03, -0x06, -0x0B, -0x04, -0x09, -0x0D, -0x07, -0x03, -0x04, -0x0D, -0x0A, -0x07, +0x06, +0x02, -0x05, -0x0F], + [-0x06, -0x07, -0x09, -0x0C, +0x09, -0x0C, -0x0C, -0x08, -0x07, -0x05, -0x0D, -0x0C, -0x0C, -0x0B, -0x07, -0x02, -0x07, -0x0E, -0x03, -0x05, -0x0B, -0x0C, -0x08, -0x0F], + [-0x03, -0x01, -0x03, -0x02, -0x0C, +0x08, +0x02, -0x06, +0x01, -0x07, -0x04, -0x02, -0x03, -0x0B, -0x02, -0x04, -0x05, -0x0B, -0x0A, -0x06, -0x02, +0x06, -0x04, -0x0F], + [-0x02, -0x08, -0x01, +0x03, -0x0C, +0x02, +0x07, -0x03, -0x04, -0x05, -0x08, -0x04, -0x06, -0x0C, -0x05, -0x04, -0x05, -0x0F, -0x08, -0x06, +0x02, +0x06, -0x04, -0x0F], + [-0x01, -0x08, -0x02, -0x03, -0x08, -0x06, -0x03, +0x06, -0x08, -0x09, -0x09, -0x06, -0x07, -0x08, -0x05, -0x01, -0x05, -0x0D, -0x0C, -0x05, -0x02, -0x04, -0x04, -0x0F], + [-0x06, -0x01, +0x01, -0x03, -0x07, +0x01, -0x04, -0x08, +0x09, -0x08, -0x05, -0x05, -0x09, -0x05, -0x03, -0x05, -0x06, -0x06, -0x03, -0x06, -0x01, +0x00, -0x04, -0x0F], + [-0x04, -0x05, -0x04, -0x06, -0x05, -0x07, -0x05, -0x09, -0x08, +0x08, -0x01, -0x05, +0x00, -0x02, -0x07, -0x06, -0x02, -0x0C, -0x05, +0x02, -0x05, -0x05, -0x04, -0x0F], + [-0x05, -0x08, -0x06, -0x0B, -0x0D, -0x04, -0x08, -0x09, -0x05, -0x01, +0x07, -0x07, +0x01, -0x02, -0x06, -0x07, -0x06, -0x05, -0x06, -0x02, -0x08, -0x06, -0x05, -0x0F], + [-0x06, +0x01, +0x00, -0x04, -0x0C, -0x02, -0x04, -0x06, -0x05, -0x05, -0x07, +0x06, -0x01, -0x0C, -0x06, -0x03, -0x02, -0x0A, -0x08, -0x08, -0x02, -0x03, -0x04, -0x0F], + [-0x04, -0x03, -0x07, -0x09, -0x0C, -0x03, -0x06, -0x07, -0x09, +0x00, +0x01, -0x01, +0x0B, -0x03, -0x07, -0x05, -0x03, -0x0B, -0x0A, -0x01, -0x08, -0x04, -0x04, -0x0F], + [-0x07, -0x08, -0x08, -0x0D, -0x0B, -0x0B, -0x0C, -0x08, -0x05, -0x02, -0x02, -0x0C, -0x03, +0x09, -0x09, -0x06, -0x08, -0x04, +0x02, -0x07, -0x09, -0x0C, -0x07, -0x0F], + [-0x01, -0x03, -0x05, -0x07, -0x07, -0x02, -0x05, -0x05, -0x03, -0x07, -0x06, -0x06, -0x07, -0x09, +0x08, -0x01, -0x03, -0x0C, -0x0C, -0x05, -0x06, -0x03, -0x04, -0x0F], + [+0x00, -0x02, +0x00, -0x03, -0x02, -0x04, -0x04, -0x01, -0x05, -0x06, -0x07, -0x03, -0x05, -0x06, -0x01, +0x06, +0x01, -0x04, -0x06, -0x05, -0x01, -0x04, -0x02, -0x0F], + [+0x00, -0x05, -0x01, -0x04, -0x07, -0x05, -0x05, -0x05, -0x06, -0x02, -0x06, -0x02, -0x03, -0x08, -0x03, +0x01, +0x07, -0x0B, -0x06, -0x02, -0x02, -0x05, -0x03, -0x0F], + [-0x0C, -0x01, -0x07, -0x0D, -0x0E, -0x0B, -0x0F, -0x0D, -0x06, -0x0C, -0x05, -0x0A, -0x0B, -0x04, -0x0C, -0x04, -0x0B, +0x0D, -0x04, -0x0E, -0x09, -0x0D, -0x09, -0x0F], + [-0x07, -0x09, -0x04, -0x0A, -0x03, -0x0A, -0x08, -0x0C, -0x03, -0x05, -0x06, -0x08, -0x0A, +0x02, -0x0C, -0x06, -0x06, -0x04, +0x0A, -0x06, -0x06, -0x08, -0x07, -0x0F], + [-0x02, -0x07, -0x07, -0x07, -0x05, -0x06, -0x06, -0x05, -0x06, +0x02, -0x02, -0x08, -0x01, -0x07, -0x05, -0x05, -0x02, -0x0E, -0x06, +0x07, -0x07, -0x06, -0x04, -0x0F], + [-0x03, -0x06, +0x06, +0x06, -0x0B, -0x02, +0x02, -0x02, -0x01, -0x05, -0x08, -0x02, -0x08, -0x09, -0x06, -0x01, -0x02, -0x09, -0x06, -0x07, +0x06, +0x01, -0x04, -0x0F], + [-0x02, -0x03, -0x02, +0x02, -0x0C, +0x06, +0x06, -0x04, +0x00, -0x05, -0x06, -0x03, -0x04, -0x0C, -0x03, -0x04, -0x05, -0x0D, -0x08, -0x06, +0x01, +0x06, -0x04, -0x0F], + [-0x03, -0x05, -0x03, -0x05, -0x08, -0x04, -0x04, -0x04, -0x04, -0x04, -0x05, -0x04, -0x04, -0x07, -0x04, -0x02, -0x03, -0x09, -0x07, -0x04, -0x04, -0x04, -0x04, -0x0F], + [-0x0F, -0x0F, -0x0F, -0x0F, -0x0F, -0x0F, -0x0F, -0x0F, -0x0F, -0x0F, -0x0F, -0x0F, -0x0F, -0x0F, -0x0F, -0x0F, -0x0F, -0x0F, -0x0F, -0x0F, -0x0F, -0x0F, -0x0F, +0x01]] + +PAM50 = [[+0x05, -0x05, -0x02, -0x02, -0x05, -0x03, -0x01, -0x01, -0x05, -0x03, -0x05, -0x05, -0x04, -0x07, +0x00, +0x00, +0x00, -0x0B, -0x06, -0x01, -0x02, -0x02, -0x02, -0x0D], + [-0x05, +0x08, -0x04, -0x07, -0x06, +0x00, -0x07, -0x07, +0x00, -0x04, -0x07, +0x01, -0x03, -0x08, -0x03, -0x02, -0x05, -0x01, -0x08, -0x06, -0x05, -0x02, -0x04, -0x0D], + [-0x02, -0x04, +0x07, +0x02, -0x08, -0x02, -0x01, -0x02, +0x01, -0x04, -0x06, +0x00, -0x06, -0x07, -0x04, +0x01, -0x01, -0x07, -0x03, -0x06, +0x05, -0x01, -0x02, -0x0D], + [-0x02, -0x07, +0x02, +0x07, -0x0B, -0x01, +0x03, -0x02, -0x02, -0x06, -0x0A, -0x03, -0x08, -0x0C, -0x06, -0x02, -0x03, -0x0C, -0x09, -0x06, +0x06, +0x02, -0x04, -0x0D], + [-0x05, -0x06, -0x08, -0x0B, +0x09, -0x0B, -0x0B, -0x07, -0x06, -0x05, -0x0C, -0x0B, -0x0B, -0x0A, -0x06, -0x02, -0x06, -0x0D, -0x03, -0x05, -0x09, -0x0B, -0x07, -0x0D], + [-0x03, +0x00, -0x02, -0x01, -0x0B, +0x08, +0x02, -0x05, +0x02, -0x06, -0x04, -0x02, -0x03, -0x0A, -0x02, -0x04, -0x04, -0x0A, -0x09, -0x05, -0x02, +0x06, -0x03, -0x0D], + [-0x01, -0x07, -0x01, +0x03, -0x0B, +0x02, +0x07, -0x03, -0x03, -0x04, -0x07, -0x03, -0x05, -0x0B, -0x04, -0x03, -0x04, -0x0D, -0x07, -0x05, +0x02, +0x06, -0x03, -0x0D], + [-0x01, -0x07, -0x02, -0x02, -0x07, -0x05, -0x03, +0x06, -0x07, -0x08, -0x09, -0x06, -0x07, -0x08, -0x04, -0x01, -0x04, -0x0C, -0x0B, -0x04, -0x02, -0x04, -0x04, -0x0D], + [-0x05, +0x00, +0x01, -0x02, -0x06, +0x02, -0x03, -0x07, +0x09, -0x07, -0x05, -0x04, -0x08, -0x05, -0x03, -0x04, -0x05, -0x06, -0x02, -0x05, +0x00, +0x00, -0x04, -0x0D], + [-0x03, -0x04, -0x04, -0x06, -0x05, -0x06, -0x04, -0x08, -0x07, +0x08, +0x00, -0x05, +0x00, -0x01, -0x07, -0x05, -0x01, -0x0B, -0x05, +0x03, -0x05, -0x05, -0x03, -0x0D], + [-0x05, -0x07, -0x06, -0x0A, -0x0C, -0x04, -0x07, -0x09, -0x05, +0x00, +0x06, -0x06, +0x02, -0x01, -0x06, -0x07, -0x05, -0x05, -0x05, -0x01, -0x07, -0x05, -0x05, -0x0D], + [-0x05, +0x01, +0x00, -0x03, -0x0B, -0x02, -0x03, -0x06, -0x04, -0x05, -0x06, +0x06, -0x01, -0x0B, -0x05, -0x03, -0x02, -0x09, -0x08, -0x07, -0x01, -0x02, -0x04, -0x0D], + [-0x04, -0x03, -0x06, -0x08, -0x0B, -0x03, -0x05, -0x07, -0x08, +0x00, +0x02, -0x01, +0x0A, -0x03, -0x06, -0x04, -0x03, -0x0A, -0x08, +0x00, -0x07, -0x04, -0x04, -0x0D], + [-0x07, -0x08, -0x07, -0x0C, -0x0A, -0x0A, -0x0B, -0x08, -0x05, -0x01, -0x01, -0x0B, -0x03, +0x09, -0x08, -0x05, -0x07, -0x03, +0x03, -0x06, -0x09, -0x0B, -0x06, -0x0D], + [+0x00, -0x03, -0x04, -0x06, -0x06, -0x02, -0x04, -0x04, -0x03, -0x07, -0x06, -0x05, -0x06, -0x08, +0x08, -0x01, -0x03, -0x0B, -0x0B, -0x04, -0x05, -0x03, -0x04, -0x0D], + [+0x00, -0x02, +0x01, -0x02, -0x02, -0x04, -0x03, -0x01, -0x04, -0x05, -0x07, -0x03, -0x04, -0x05, -0x01, +0x06, +0x01, -0x04, -0x05, -0x04, -0x01, -0x03, -0x02, -0x0D], + [+0x00, -0x05, -0x01, -0x03, -0x06, -0x04, -0x04, -0x04, -0x05, -0x01, -0x05, -0x02, -0x03, -0x07, -0x03, +0x01, +0x06, -0x0A, -0x05, -0x02, -0x02, -0x04, -0x02, -0x0D], + [-0x0B, -0x01, -0x07, -0x0C, -0x0D, -0x0A, -0x0D, -0x0C, -0x06, -0x0B, -0x05, -0x09, -0x0A, -0x03, -0x0B, -0x04, -0x0A, +0x0D, -0x04, -0x0C, -0x08, -0x0B, -0x09, -0x0D], + [-0x06, -0x08, -0x03, -0x09, -0x03, -0x09, -0x07, -0x0B, -0x02, -0x05, -0x05, -0x08, -0x08, +0x03, -0x0B, -0x05, -0x05, -0x04, +0x09, -0x06, -0x05, -0x08, -0x06, -0x0D], + [-0x01, -0x06, -0x06, -0x06, -0x05, -0x05, -0x05, -0x04, -0x05, +0x03, -0x01, -0x07, +0x00, -0x06, -0x04, -0x04, -0x02, -0x0C, -0x06, +0x07, -0x06, -0x05, -0x03, -0x0D], + [-0x02, -0x05, +0x05, +0x06, -0x09, -0x02, +0x02, -0x02, +0x00, -0x05, -0x07, -0x01, -0x07, -0x09, -0x05, -0x01, -0x02, -0x08, -0x05, -0x06, +0x05, +0x01, -0x03, -0x0D], + [-0x02, -0x02, -0x01, +0x02, -0x0B, +0x06, +0x06, -0x04, +0x00, -0x05, -0x05, -0x02, -0x04, -0x0B, -0x03, -0x03, -0x04, -0x0B, -0x08, -0x05, +0x01, +0x06, -0x03, -0x0D], + [-0x02, -0x04, -0x02, -0x04, -0x07, -0x03, -0x03, -0x04, -0x04, -0x03, -0x05, -0x04, -0x04, -0x06, -0x04, -0x02, -0x02, -0x09, -0x06, -0x03, -0x03, -0x03, -0x04, -0x0D], + [-0x0D, -0x0D, -0x0D, -0x0D, -0x0D, -0x0D, -0x0D, -0x0D, -0x0D, -0x0D, -0x0D, -0x0D, -0x0D, -0x0D, -0x0D, -0x0D, -0x0D, -0x0D, -0x0D, -0x0D, -0x0D, -0x0D, -0x0D, +0x01]] + +PAM60 = [[+0x05, -0x05, -0x02, -0x02, -0x05, -0x03, -0x01, +0x00, -0x05, -0x03, -0x04, -0x05, -0x03, -0x06, +0x00, +0x01, +0x01, -0x0A, -0x06, -0x01, -0x02, -0x02, -0x02, -0x0C], + [-0x05, +0x08, -0x03, -0x06, -0x06, +0x00, -0x06, -0x07, +0x00, -0x04, -0x06, +0x02, -0x02, -0x07, -0x02, -0x02, -0x04, +0x00, -0x08, -0x05, -0x05, -0x02, -0x04, -0x0C], + [-0x02, -0x03, +0x06, +0x02, -0x07, -0x02, +0x00, -0x01, +0x01, -0x04, -0x05, +0x00, -0x06, -0x06, -0x04, +0x01, -0x01, -0x06, -0x03, -0x05, +0x05, -0x01, -0x02, -0x0C], + [-0x02, -0x06, +0x02, +0x07, -0x0A, -0x01, +0x03, -0x02, -0x02, -0x05, -0x09, -0x02, -0x07, -0x0B, -0x05, -0x02, -0x03, -0x0B, -0x08, -0x06, +0x05, +0x02, -0x03, -0x0C], + [-0x05, -0x06, -0x07, -0x0A, +0x09, -0x0A, -0x0A, -0x07, -0x06, -0x04, -0x0B, -0x0A, -0x0A, -0x09, -0x06, -0x01, -0x05, -0x0C, -0x02, -0x04, -0x09, -0x0A, -0x06, -0x0C], + [-0x03, +0x00, -0x02, -0x01, -0x0A, +0x07, +0x02, -0x05, +0x02, -0x05, -0x03, -0x01, -0x02, -0x09, -0x01, -0x03, -0x04, -0x09, -0x08, -0x05, -0x01, +0x06, -0x03, -0x0C], + [-0x01, -0x06, +0x00, +0x03, -0x0A, +0x02, +0x07, -0x02, -0x03, -0x04, -0x07, -0x03, -0x05, -0x0A, -0x03, -0x02, -0x04, -0x0C, -0x07, -0x04, +0x02, +0x05, -0x03, -0x0C], + [+0x00, -0x07, -0x01, -0x02, -0x07, -0x05, -0x02, +0x06, -0x06, -0x07, -0x08, -0x05, -0x06, -0x07, -0x04, +0x00, -0x03, -0x0B, -0x0A, -0x04, -0x02, -0x03, -0x03, -0x0C], + [-0x05, +0x00, +0x01, -0x02, -0x06, +0x02, -0x03, -0x06, +0x08, -0x06, -0x04, -0x04, -0x07, -0x04, -0x02, -0x04, -0x05, -0x05, -0x02, -0x05, +0x00, +0x00, -0x03, -0x0C], + [-0x03, -0x04, -0x04, -0x05, -0x04, -0x05, -0x04, -0x07, -0x06, +0x07, +0x00, -0x04, +0x01, -0x01, -0x06, -0x04, -0x01, -0x0A, -0x04, +0x03, -0x04, -0x04, -0x03, -0x0C], + [-0x04, -0x06, -0x05, -0x09, -0x0B, -0x03, -0x07, -0x08, -0x04, +0x00, +0x06, -0x06, +0x02, -0x01, -0x05, -0x06, -0x05, -0x04, -0x05, -0x01, -0x07, -0x05, -0x04, -0x0C], + [-0x05, +0x02, +0x00, -0x02, -0x0A, -0x01, -0x03, -0x05, -0x04, -0x04, -0x06, +0x06, +0x00, -0x0A, -0x04, -0x02, -0x02, -0x08, -0x07, -0x06, -0x01, -0x02, -0x03, -0x0C], + [-0x03, -0x02, -0x06, -0x07, -0x0A, -0x02, -0x05, -0x06, -0x07, +0x01, +0x02, +0x00, +0x0A, -0x02, -0x06, -0x04, -0x02, -0x09, -0x07, +0x00, -0x06, -0x04, -0x03, -0x0C], + [-0x06, -0x07, -0x06, -0x0B, -0x09, -0x09, -0x0A, -0x07, -0x04, -0x01, -0x01, -0x0A, -0x02, +0x08, -0x07, -0x05, -0x06, -0x03, +0x03, -0x05, -0x08, -0x0A, -0x05, -0x0C], + [+0x00, -0x02, -0x04, -0x05, -0x06, -0x01, -0x03, -0x04, -0x02, -0x06, -0x05, -0x04, -0x06, -0x07, +0x07, +0x00, -0x02, -0x0A, -0x0A, -0x04, -0x04, -0x02, -0x03, -0x0C], + [+0x01, -0x02, +0x01, -0x02, -0x01, -0x03, -0x02, +0x00, -0x04, -0x04, -0x06, -0x02, -0x04, -0x05, +0x00, +0x05, +0x01, -0x04, -0x05, -0x04, +0x00, -0x03, -0x02, -0x0C], + [+0x01, -0x04, -0x01, -0x03, -0x05, -0x04, -0x04, -0x03, -0x05, -0x01, -0x05, -0x02, -0x02, -0x06, -0x02, +0x01, +0x06, -0x09, -0x05, -0x01, -0x02, -0x04, -0x02, -0x0C], + [-0x0A, +0x00, -0x06, -0x0B, -0x0C, -0x09, -0x0C, -0x0B, -0x05, -0x0A, -0x04, -0x08, -0x09, -0x03, -0x0A, -0x04, -0x09, +0x0D, -0x03, -0x0B, -0x08, -0x0B, -0x08, -0x0C], + [-0x06, -0x08, -0x03, -0x08, -0x02, -0x08, -0x07, -0x0A, -0x02, -0x04, -0x05, -0x07, -0x07, +0x03, -0x0A, -0x05, -0x05, -0x03, +0x09, -0x05, -0x05, -0x07, -0x05, -0x0C], + [-0x01, -0x05, -0x05, -0x06, -0x04, -0x05, -0x04, -0x04, -0x05, +0x03, -0x01, -0x06, +0x00, -0x05, -0x04, -0x04, -0x01, -0x0B, -0x05, +0x06, -0x05, -0x05, -0x03, -0x0C], + [-0x02, -0x05, +0x05, +0x05, -0x09, -0x01, +0x02, -0x02, +0x00, -0x04, -0x07, -0x01, -0x06, -0x08, -0x04, +0x00, -0x02, -0x08, -0x05, -0x05, +0x05, +0x01, -0x03, -0x0C], + [-0x02, -0x02, -0x01, +0x02, -0x0A, +0x06, +0x05, -0x03, +0x00, -0x04, -0x05, -0x02, -0x04, -0x0A, -0x02, -0x03, -0x04, -0x0B, -0x07, -0x05, +0x01, +0x05, -0x03, -0x0C], + [-0x02, -0x04, -0x02, -0x03, -0x06, -0x03, -0x03, -0x03, -0x03, -0x03, -0x04, -0x03, -0x03, -0x05, -0x03, -0x02, -0x02, -0x08, -0x05, -0x03, -0x03, -0x03, -0x03, -0x0C], + [-0x0C, -0x0C, -0x0C, -0x0C, -0x0C, -0x0C, -0x0C, -0x0C, -0x0C, -0x0C, -0x0C, -0x0C, -0x0C, -0x0C, -0x0C, -0x0C, -0x0C, -0x0C, -0x0C, -0x0C, -0x0C, -0x0C, -0x0C, +0x01]] + +PAM70 = [[+0x05, -0x04, -0x02, -0x01, -0x04, -0x02, -0x01, +0x00, -0x04, -0x02, -0x04, -0x04, -0x03, -0x06, +0x00, +0x01, +0x01, -0x09, -0x05, -0x01, -0x01, -0x01, -0x02, -0x0B], + [-0x04, +0x08, -0x03, -0x06, -0x05, +0x00, -0x05, -0x06, +0x00, -0x03, -0x06, +0x02, -0x02, -0x07, -0x02, -0x01, -0x04, +0x00, -0x07, -0x05, -0x04, -0x02, -0x03, -0x0B], + [-0x02, -0x03, +0x06, +0x03, -0x07, -0x01, +0x00, -0x01, +0x01, -0x03, -0x05, +0x00, -0x05, -0x06, -0x03, +0x01, +0x00, -0x06, -0x03, -0x05, +0x05, -0x01, -0x02, -0x0B], + [-0x01, -0x06, +0x03, +0x06, -0x09, +0x00, +0x03, -0x01, -0x01, -0x05, -0x08, -0x02, -0x07, -0x0A, -0x04, -0x01, -0x02, -0x0A, -0x07, -0x05, +0x05, +0x02, -0x03, -0x0B], + [-0x04, -0x05, -0x07, -0x09, +0x09, -0x09, -0x09, -0x06, -0x05, -0x04, -0x0A, -0x09, -0x09, -0x08, -0x05, -0x01, -0x05, -0x0B, -0x02, -0x04, -0x08, -0x09, -0x06, -0x0B], + [-0x02, +0x00, -0x01, +0x00, -0x09, +0x07, +0x02, -0x04, +0x02, -0x05, -0x03, -0x01, -0x02, -0x09, -0x01, -0x03, -0x03, -0x08, -0x08, -0x04, -0x01, +0x05, -0x02, -0x0B], + [-0x01, -0x05, +0x00, +0x03, -0x09, +0x02, +0x06, -0x02, -0x02, -0x04, -0x06, -0x02, -0x04, -0x09, -0x03, -0x02, -0x03, -0x0B, -0x06, -0x04, +0x02, +0x05, -0x03, -0x0B], + [+0x00, -0x06, -0x01, -0x01, -0x06, -0x04, -0x02, +0x06, -0x06, -0x06, -0x07, -0x05, -0x06, -0x07, -0x03, +0x00, -0x03, -0x0A, -0x09, -0x03, -0x01, -0x03, -0x03, -0x0B], + [-0x04, +0x00, +0x01, -0x01, -0x05, +0x02, -0x02, -0x06, +0x08, -0x06, -0x04, -0x03, -0x06, -0x04, -0x02, -0x03, -0x04, -0x05, -0x01, -0x04, +0x00, +0x01, -0x03, -0x0B], + [-0x02, -0x03, -0x03, -0x05, -0x04, -0x05, -0x04, -0x06, -0x06, +0x07, +0x01, -0x04, +0x01, +0x00, -0x05, -0x04, -0x01, -0x09, -0x04, +0x03, -0x04, -0x04, -0x03, -0x0B], + [-0x04, -0x06, -0x05, -0x08, -0x0A, -0x03, -0x06, -0x07, -0x04, +0x01, +0x06, -0x05, +0x02, -0x01, -0x05, -0x06, -0x04, -0x04, -0x04, +0x00, -0x06, -0x04, -0x04, -0x0B], + [-0x04, +0x02, +0x00, -0x02, -0x09, -0x01, -0x02, -0x05, -0x03, -0x04, -0x05, +0x06, +0x00, -0x09, -0x04, -0x02, -0x01, -0x07, -0x07, -0x06, -0x01, -0x02, -0x03, -0x0B], + [-0x03, -0x02, -0x05, -0x07, -0x09, -0x02, -0x04, -0x06, -0x06, +0x01, +0x02, +0x00, +0x0A, -0x02, -0x05, -0x03, -0x02, -0x08, -0x07, +0x00, -0x06, -0x03, -0x03, -0x0B], + [-0x06, -0x07, -0x06, -0x0A, -0x08, -0x09, -0x09, -0x07, -0x04, +0x00, -0x01, -0x09, -0x02, +0x08, -0x07, -0x04, -0x06, -0x02, +0x04, -0x05, -0x07, -0x09, -0x05, -0x0B], + [+0x00, -0x02, -0x03, -0x04, -0x05, -0x01, -0x03, -0x03, -0x02, -0x05, -0x05, -0x04, -0x05, -0x07, +0x07, +0x00, -0x02, -0x09, -0x09, -0x03, -0x04, -0x02, -0x03, -0x0B], + [+0x01, -0x01, +0x01, -0x01, -0x01, -0x03, -0x02, +0x00, -0x03, -0x04, -0x06, -0x02, -0x03, -0x04, +0x00, +0x05, +0x02, -0x03, -0x05, -0x03, +0x00, -0x02, -0x01, -0x0B], + [+0x01, -0x04, +0x00, -0x02, -0x05, -0x03, -0x03, -0x03, -0x04, -0x01, -0x04, -0x01, -0x02, -0x06, -0x02, +0x02, +0x06, -0x08, -0x04, -0x01, -0x01, -0x03, -0x02, -0x0B], + [-0x09, +0x00, -0x06, -0x0A, -0x0B, -0x08, -0x0B, -0x0A, -0x05, -0x09, -0x04, -0x07, -0x08, -0x02, -0x09, -0x03, -0x08, +0x0D, -0x03, -0x0A, -0x07, -0x0A, -0x07, -0x0B], + [-0x05, -0x07, -0x03, -0x07, -0x02, -0x08, -0x06, -0x09, -0x01, -0x04, -0x04, -0x07, -0x07, +0x04, -0x09, -0x05, -0x04, -0x03, +0x09, -0x05, -0x04, -0x07, -0x05, -0x0B], + [-0x01, -0x05, -0x05, -0x05, -0x04, -0x04, -0x04, -0x03, -0x04, +0x03, +0x00, -0x06, +0x00, -0x05, -0x03, -0x03, -0x01, -0x0A, -0x05, +0x06, -0x05, -0x04, -0x02, -0x0B], + [-0x01, -0x04, +0x05, +0x05, -0x08, -0x01, +0x02, -0x01, +0x00, -0x04, -0x06, -0x01, -0x06, -0x07, -0x04, +0x00, -0x01, -0x07, -0x04, -0x05, +0x05, +0x01, -0x02, -0x0B], + [-0x01, -0x02, -0x01, +0x02, -0x09, +0x05, +0x05, -0x03, +0x01, -0x04, -0x04, -0x02, -0x03, -0x09, -0x02, -0x02, -0x03, -0x0A, -0x07, -0x04, +0x01, +0x05, -0x03, -0x0B], + [-0x02, -0x03, -0x02, -0x03, -0x06, -0x02, -0x03, -0x03, -0x03, -0x03, -0x04, -0x03, -0x03, -0x05, -0x03, -0x01, -0x02, -0x07, -0x05, -0x02, -0x02, -0x03, -0x03, -0x0B], + [-0x0B, -0x0B, -0x0B, -0x0B, -0x0B, -0x0B, -0x0B, -0x0B, -0x0B, -0x0B, -0x0B, -0x0B, -0x0B, -0x0B, -0x0B, -0x0B, -0x0B, -0x0B, -0x0B, -0x0B, -0x0B, -0x0B, -0x0B, +0x01]] + +PAM80 = [[+0x04, -0x04, -0x01, -0x01, -0x04, -0x02, -0x01, +0x00, -0x04, -0x02, -0x04, -0x04, -0x03, -0x05, +0x00, +0x01, +0x01, -0x08, -0x05, +0x00, -0x01, -0x01, -0x01, -0x0B], + [-0x04, +0x07, -0x02, -0x05, -0x05, +0x00, -0x04, -0x06, +0x00, -0x03, -0x05, +0x02, -0x02, -0x06, -0x02, -0x01, -0x03, +0x00, -0x07, -0x05, -0x03, -0x01, -0x03, -0x0B], + [-0x01, -0x02, +0x05, +0x03, -0x06, -0x01, +0x00, -0x01, +0x02, -0x03, -0x05, +0x00, -0x04, -0x05, -0x03, +0x01, +0x00, -0x05, -0x03, -0x04, +0x04, +0x00, -0x01, -0x0B], + [-0x01, -0x05, +0x03, +0x06, -0x09, +0x00, +0x04, -0x01, -0x01, -0x04, -0x07, -0x02, -0x06, -0x09, -0x04, -0x01, -0x02, -0x0A, -0x07, -0x05, +0x05, +0x02, -0x03, -0x0B], + [-0x04, -0x05, -0x06, -0x09, +0x09, -0x09, -0x09, -0x06, -0x05, -0x04, -0x09, -0x09, -0x08, -0x08, -0x05, -0x01, -0x04, -0x0A, -0x02, -0x03, -0x07, -0x09, -0x05, -0x0B], + [-0x02, +0x00, -0x01, +0x00, -0x09, +0x07, +0x02, -0x04, +0x02, -0x04, -0x03, -0x01, -0x02, -0x08, -0x01, -0x03, -0x03, -0x08, -0x07, -0x04, +0x00, +0x05, -0x02, -0x0B], + [-0x01, -0x04, +0x00, +0x04, -0x09, +0x02, +0x06, -0x02, -0x02, -0x03, -0x06, -0x02, -0x04, -0x09, -0x03, -0x02, -0x03, -0x0B, -0x06, -0x04, +0x02, +0x05, -0x02, -0x0B], + [+0x00, -0x06, -0x01, -0x01, -0x06, -0x04, -0x02, +0x06, -0x05, -0x06, -0x07, -0x04, -0x05, -0x06, -0x03, +0x00, -0x02, -0x0A, -0x08, -0x03, -0x01, -0x02, -0x03, -0x0B], + [-0x04, +0x00, +0x02, -0x01, -0x05, +0x02, -0x02, -0x05, +0x08, -0x05, -0x04, -0x03, -0x05, -0x03, -0x02, -0x03, -0x04, -0x04, -0x01, -0x04, +0x00, +0x01, -0x02, -0x0B], + [-0x02, -0x03, -0x03, -0x04, -0x04, -0x04, -0x03, -0x06, -0x05, +0x07, +0x01, -0x04, +0x01, +0x00, -0x05, -0x04, -0x01, -0x08, -0x03, +0x03, -0x04, -0x04, -0x02, -0x0B], + [-0x04, -0x05, -0x05, -0x07, -0x09, -0x03, -0x06, -0x07, -0x04, +0x01, +0x06, -0x05, +0x02, +0x00, -0x04, -0x05, -0x04, -0x03, -0x04, +0x00, -0x06, -0x04, -0x03, -0x0B], + [-0x04, +0x02, +0x00, -0x02, -0x09, -0x01, -0x02, -0x04, -0x03, -0x04, -0x05, +0x06, +0x00, -0x09, -0x04, -0x02, -0x01, -0x07, -0x06, -0x05, -0x01, -0x01, -0x03, -0x0B], + [-0x03, -0x02, -0x04, -0x06, -0x08, -0x02, -0x04, -0x05, -0x05, +0x01, +0x02, +0x00, +0x09, -0x02, -0x05, -0x03, -0x02, -0x07, -0x06, +0x01, -0x05, -0x03, -0x02, -0x0B], + [-0x05, -0x06, -0x05, -0x09, -0x08, -0x08, -0x09, -0x06, -0x03, +0x00, +0x00, -0x09, -0x02, +0x08, -0x07, -0x04, -0x05, -0x02, +0x04, -0x04, -0x07, -0x08, -0x05, -0x0B], + [+0x00, -0x02, -0x03, -0x04, -0x05, -0x01, -0x03, -0x03, -0x02, -0x05, -0x04, -0x04, -0x05, -0x07, +0x07, +0x00, -0x02, -0x09, -0x08, -0x03, -0x03, -0x02, -0x02, -0x0B], + [+0x01, -0x01, +0x01, -0x01, -0x01, -0x03, -0x02, +0x00, -0x03, -0x04, -0x05, -0x02, -0x03, -0x04, +0x00, +0x04, +0x02, -0x03, -0x04, -0x03, +0x00, -0x02, -0x01, -0x0B], + [+0x01, -0x03, +0x00, -0x02, -0x04, -0x03, -0x03, -0x02, -0x04, -0x01, -0x04, -0x01, -0x02, -0x05, -0x02, +0x02, +0x05, -0x08, -0x04, -0x01, -0x01, -0x03, -0x01, -0x0B], + [-0x08, +0x00, -0x05, -0x0A, -0x0A, -0x08, -0x0B, -0x0A, -0x04, -0x08, -0x03, -0x07, -0x07, -0x02, -0x09, -0x03, -0x08, +0x0D, -0x02, -0x0A, -0x07, -0x09, -0x07, -0x0B], + [-0x05, -0x07, -0x03, -0x07, -0x02, -0x07, -0x06, -0x08, -0x01, -0x03, -0x04, -0x06, -0x06, +0x04, -0x08, -0x04, -0x04, -0x02, +0x09, -0x05, -0x04, -0x06, -0x04, -0x0B], + [+0x00, -0x05, -0x04, -0x05, -0x03, -0x04, -0x04, -0x03, -0x04, +0x03, +0x00, -0x05, +0x01, -0x04, -0x03, -0x03, -0x01, -0x0A, -0x05, +0x06, -0x04, -0x04, -0x02, -0x0B], + [-0x01, -0x03, +0x04, +0x05, -0x07, +0x00, +0x02, -0x01, +0x00, -0x04, -0x06, -0x01, -0x05, -0x07, -0x03, +0x00, -0x01, -0x07, -0x04, -0x04, +0x05, +0x02, -0x02, -0x0B], + [-0x01, -0x01, +0x00, +0x02, -0x09, +0x05, +0x05, -0x02, +0x01, -0x04, -0x04, -0x01, -0x03, -0x08, -0x02, -0x02, -0x03, -0x09, -0x06, -0x04, +0x02, +0x05, -0x02, -0x0B], + [-0x01, -0x03, -0x01, -0x03, -0x05, -0x02, -0x02, -0x03, -0x02, -0x02, -0x03, -0x03, -0x02, -0x05, -0x02, -0x01, -0x01, -0x07, -0x04, -0x02, -0x02, -0x02, -0x03, -0x0B], + [-0x0B, -0x0B, -0x0B, -0x0B, -0x0B, -0x0B, -0x0B, -0x0B, -0x0B, -0x0B, -0x0B, -0x0B, -0x0B, -0x0B, -0x0B, -0x0B, -0x0B, -0x0B, -0x0B, -0x0B, -0x0B, -0x0B, -0x0B, +0x01]] + +PAM90 = [[+0x04, -0x04, -0x01, -0x01, -0x03, -0x02, +0x00, +0x00, -0x04, -0x02, -0x03, -0x03, -0x02, -0x05, +0x00, +0x01, +0x01, -0x08, -0x05, +0x00, -0x01, -0x01, -0x01, -0x0A], + [-0x04, +0x07, -0x02, -0x05, -0x05, +0x00, -0x04, -0x05, +0x01, -0x03, -0x05, +0x02, -0x02, -0x06, -0x01, -0x01, -0x03, +0x00, -0x06, -0x04, -0x03, -0x01, -0x02, -0x0A], + [-0x01, -0x02, +0x05, +0x03, -0x06, -0x01, +0x00, -0x01, +0x02, -0x03, -0x04, +0x01, -0x04, -0x05, -0x02, +0x01, +0x00, -0x05, -0x02, -0x04, +0x04, +0x00, -0x01, -0x0A], + [-0x01, -0x05, +0x03, +0x06, -0x08, +0x00, +0x04, -0x01, -0x01, -0x04, -0x07, -0x02, -0x05, -0x08, -0x04, -0x01, -0x02, -0x09, -0x06, -0x04, +0x05, +0x03, -0x02, -0x0A], + [-0x03, -0x05, -0x06, -0x08, +0x09, -0x08, -0x08, -0x05, -0x05, -0x03, -0x09, -0x08, -0x08, -0x07, -0x05, -0x01, -0x04, -0x0A, -0x01, -0x03, -0x07, -0x08, -0x05, -0x0A], + [-0x02, +0x00, -0x01, +0x00, -0x08, +0x06, +0x02, -0x03, +0x02, -0x04, -0x03, -0x01, -0x02, -0x07, -0x01, -0x02, -0x03, -0x07, -0x06, -0x04, +0x00, +0x05, -0x02, -0x0A], + [+0x00, -0x04, +0x00, +0x04, -0x08, +0x02, +0x06, -0x01, -0x01, -0x03, -0x05, -0x02, -0x04, -0x08, -0x02, -0x02, -0x02, -0x0A, -0x06, -0x03, +0x02, +0x05, -0x02, -0x0A], + [+0x00, -0x05, -0x01, -0x01, -0x05, -0x03, -0x01, +0x05, -0x05, -0x05, -0x06, -0x04, -0x05, -0x06, -0x03, +0x00, -0x02, -0x09, -0x08, -0x03, -0x01, -0x02, -0x02, -0x0A], + [-0x04, +0x01, +0x02, -0x01, -0x05, +0x02, -0x01, -0x05, +0x08, -0x05, -0x03, -0x02, -0x05, -0x03, -0x02, -0x03, -0x03, -0x04, -0x01, -0x04, +0x01, +0x01, -0x02, -0x0A], + [-0x02, -0x03, -0x03, -0x04, -0x03, -0x04, -0x03, -0x05, -0x05, +0x06, +0x01, -0x03, +0x01, +0x00, -0x04, -0x03, +0x00, -0x08, -0x03, +0x03, -0x03, -0x03, -0x02, -0x0A], + [-0x03, -0x05, -0x04, -0x07, -0x09, -0x03, -0x05, -0x06, -0x03, +0x01, +0x06, -0x05, +0x02, +0x00, -0x04, -0x05, -0x03, -0x03, -0x03, +0x00, -0x05, -0x04, -0x03, -0x0A], + [-0x03, +0x02, +0x01, -0x02, -0x08, -0x01, -0x02, -0x04, -0x02, -0x03, -0x05, +0x05, +0x00, -0x08, -0x03, -0x01, -0x01, -0x06, -0x06, -0x05, +0x00, -0x01, -0x02, -0x0A], + [-0x02, -0x02, -0x04, -0x05, -0x08, -0x02, -0x04, -0x05, -0x05, +0x01, +0x02, +0x00, +0x09, -0x01, -0x04, -0x03, -0x02, -0x07, -0x06, +0x01, -0x05, -0x03, -0x02, -0x0A], + [-0x05, -0x06, -0x05, -0x08, -0x07, -0x07, -0x08, -0x06, -0x03, +0x00, +0x00, -0x08, -0x01, +0x08, -0x06, -0x04, -0x05, -0x02, +0x04, -0x04, -0x06, -0x08, -0x04, -0x0A], + [+0x00, -0x01, -0x02, -0x04, -0x05, -0x01, -0x02, -0x03, -0x02, -0x04, -0x04, -0x03, -0x04, -0x06, +0x07, +0x00, -0x01, -0x08, -0x08, -0x03, -0x03, -0x02, -0x02, -0x0A], + [+0x01, -0x01, +0x01, -0x01, -0x01, -0x02, -0x02, +0x00, -0x03, -0x03, -0x05, -0x01, -0x03, -0x04, +0x00, +0x04, +0x02, -0x03, -0x04, -0x03, +0x00, -0x02, -0x01, -0x0A], + [+0x01, -0x03, +0x00, -0x02, -0x04, -0x03, -0x02, -0x02, -0x03, +0x00, -0x03, -0x01, -0x02, -0x05, -0x01, +0x02, +0x05, -0x07, -0x04, -0x01, -0x01, -0x02, -0x01, -0x0A], + [-0x08, +0x00, -0x05, -0x09, -0x0A, -0x07, -0x0A, -0x09, -0x04, -0x08, -0x03, -0x06, -0x07, -0x02, -0x08, -0x03, -0x07, +0x0D, -0x02, -0x09, -0x07, -0x08, -0x06, -0x0A], + [-0x05, -0x06, -0x02, -0x06, -0x01, -0x06, -0x06, -0x08, -0x01, -0x03, -0x03, -0x06, -0x06, +0x04, -0x08, -0x04, -0x04, -0x02, +0x09, -0x04, -0x04, -0x06, -0x04, -0x0A], + [+0x00, -0x04, -0x04, -0x04, -0x03, -0x04, -0x03, -0x03, -0x04, +0x03, +0x00, -0x05, +0x01, -0x04, -0x03, -0x03, -0x01, -0x09, -0x04, +0x06, -0x04, -0x03, -0x02, -0x0A], + [-0x01, -0x03, +0x04, +0x05, -0x07, +0x00, +0x02, -0x01, +0x01, -0x03, -0x05, +0x00, -0x05, -0x06, -0x03, +0x00, -0x01, -0x07, -0x04, -0x04, +0x04, +0x02, -0x02, -0x0A], + [-0x01, -0x01, +0x00, +0x03, -0x08, +0x05, +0x05, -0x02, +0x01, -0x03, -0x04, -0x01, -0x03, -0x08, -0x02, -0x02, -0x02, -0x08, -0x06, -0x03, +0x02, +0x05, -0x02, -0x0A], + [-0x01, -0x02, -0x01, -0x02, -0x05, -0x02, -0x02, -0x02, -0x02, -0x02, -0x03, -0x02, -0x02, -0x04, -0x02, -0x01, -0x01, -0x06, -0x04, -0x02, -0x02, -0x02, -0x02, -0x0A], + [-0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, +0x01]] + +PAM100 = [[+0x04, -0x03, -0x01, -0x01, -0x03, -0x02, +0x00, +0x01, -0x03, -0x02, -0x03, -0x03, -0x02, -0x05, +0x01, +0x01, +0x01, -0x07, -0x04, +0x00, -0x01, -0x01, -0x01, -0x09], + [-0x03, +0x07, -0x02, -0x04, -0x05, +0x01, -0x03, -0x05, +0x01, -0x03, -0x05, +0x02, -0x01, -0x06, -0x01, -0x01, -0x03, +0x01, -0x06, -0x04, -0x03, -0x01, -0x02, -0x09], + [-0x01, -0x02, +0x05, +0x03, -0x05, -0x01, +0x01, -0x01, +0x02, -0x03, -0x04, +0x01, -0x04, -0x05, -0x02, +0x01, +0x00, -0x05, -0x02, -0x03, +0x04, +0x00, -0x01, -0x09], + [-0x01, -0x04, +0x03, +0x05, -0x07, +0x00, +0x04, -0x01, -0x01, -0x04, -0x06, -0x01, -0x05, -0x08, -0x03, -0x01, -0x02, -0x09, -0x06, -0x04, +0x04, +0x03, -0x02, -0x09], + [-0x03, -0x05, -0x05, -0x07, +0x09, -0x08, -0x08, -0x05, -0x04, -0x03, -0x08, -0x08, -0x07, -0x07, -0x04, -0x01, -0x04, -0x09, -0x01, -0x03, -0x06, -0x08, -0x05, -0x09], + [-0x02, +0x01, -0x01, +0x00, -0x08, +0x06, +0x02, -0x03, +0x03, -0x04, -0x02, +0x00, -0x02, -0x07, -0x01, -0x02, -0x02, -0x07, -0x06, -0x03, +0x00, +0x05, -0x02, -0x09], + [+0x00, -0x03, +0x01, +0x04, -0x08, +0x02, +0x05, -0x01, -0x01, -0x03, -0x05, -0x01, -0x04, -0x08, -0x02, -0x01, -0x02, -0x09, -0x05, -0x03, +0x03, +0x04, -0x02, -0x09], + [+0x01, -0x05, -0x01, -0x01, -0x05, -0x03, -0x01, +0x05, -0x04, -0x05, -0x06, -0x03, -0x04, -0x06, -0x02, +0x00, -0x02, -0x09, -0x07, -0x03, -0x01, -0x02, -0x02, -0x09], + [-0x03, +0x01, +0x02, -0x01, -0x04, +0x03, -0x01, -0x04, +0x07, -0x04, -0x03, -0x02, -0x04, -0x03, -0x01, -0x02, -0x03, -0x04, -0x01, -0x03, +0x01, +0x01, -0x02, -0x09], + [-0x02, -0x03, -0x03, -0x04, -0x03, -0x04, -0x03, -0x05, -0x04, +0x06, +0x01, -0x03, +0x01, +0x00, -0x04, -0x03, +0x00, -0x07, -0x03, +0x03, -0x03, -0x03, -0x02, -0x09], + [-0x03, -0x05, -0x04, -0x06, -0x08, -0x02, -0x05, -0x06, -0x03, +0x01, +0x06, -0x04, +0x03, +0x00, -0x04, -0x04, -0x03, -0x03, -0x03, +0x00, -0x05, -0x04, -0x03, -0x09], + [-0x03, +0x02, +0x01, -0x01, -0x08, +0x00, -0x01, -0x03, -0x02, -0x03, -0x04, +0x05, +0x00, -0x07, -0x03, -0x01, -0x01, -0x06, -0x06, -0x04, +0x00, -0x01, -0x02, -0x09], + [-0x02, -0x01, -0x04, -0x05, -0x07, -0x02, -0x04, -0x04, -0x04, +0x01, +0x03, +0x00, +0x09, -0x01, -0x04, -0x03, -0x01, -0x06, -0x05, +0x01, -0x04, -0x02, -0x02, -0x09], + [-0x05, -0x06, -0x05, -0x08, -0x07, -0x07, -0x08, -0x06, -0x03, +0x00, +0x00, -0x07, -0x01, +0x08, -0x06, -0x04, -0x05, -0x01, +0x04, -0x03, -0x06, -0x07, -0x04, -0x09], + [+0x01, -0x01, -0x02, -0x03, -0x04, -0x01, -0x02, -0x02, -0x01, -0x04, -0x04, -0x03, -0x04, -0x06, +0x07, +0x00, -0x01, -0x07, -0x07, -0x03, -0x03, -0x01, -0x02, -0x09], + [+0x01, -0x01, +0x01, -0x01, -0x01, -0x02, -0x01, +0x00, -0x02, -0x03, -0x04, -0x01, -0x03, -0x04, +0x00, +0x04, +0x02, -0x03, -0x04, -0x02, +0x00, -0x02, -0x01, -0x09], + [+0x01, -0x03, +0x00, -0x02, -0x04, -0x02, -0x02, -0x02, -0x03, +0x00, -0x03, -0x01, -0x01, -0x05, -0x01, +0x02, +0x05, -0x07, -0x04, +0x00, -0x01, -0x02, -0x01, -0x09], + [-0x07, +0x01, -0x05, -0x09, -0x09, -0x07, -0x09, -0x09, -0x04, -0x07, -0x03, -0x06, -0x06, -0x01, -0x07, -0x03, -0x07, +0x0C, -0x02, -0x09, -0x06, -0x08, -0x06, -0x09], + [-0x04, -0x06, -0x02, -0x06, -0x01, -0x06, -0x05, -0x07, -0x01, -0x03, -0x03, -0x06, -0x05, +0x04, -0x07, -0x04, -0x04, -0x02, +0x09, -0x04, -0x04, -0x06, -0x04, -0x09], + [+0x00, -0x04, -0x03, -0x04, -0x03, -0x03, -0x03, -0x03, -0x03, +0x03, +0x00, -0x04, +0x01, -0x03, -0x03, -0x02, +0x00, -0x09, -0x04, +0x05, -0x04, -0x03, -0x02, -0x09], + [-0x01, -0x03, +0x04, +0x04, -0x06, +0x00, +0x03, -0x01, +0x01, -0x03, -0x05, +0x00, -0x04, -0x06, -0x03, +0x00, -0x01, -0x06, -0x04, -0x04, +0x04, +0x02, -0x02, -0x09], + [-0x01, -0x01, +0x00, +0x03, -0x08, +0x05, +0x04, -0x02, +0x01, -0x03, -0x04, -0x01, -0x02, -0x07, -0x01, -0x02, -0x02, -0x08, -0x06, -0x03, +0x02, +0x05, -0x02, -0x09], + [-0x01, -0x02, -0x01, -0x02, -0x05, -0x02, -0x02, -0x02, -0x02, -0x02, -0x03, -0x02, -0x02, -0x04, -0x02, -0x01, -0x01, -0x06, -0x04, -0x02, -0x02, -0x02, -0x02, -0x09], + [-0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, +0x01]] + +PAM110 = [[+0x03, -0x03, -0x01, -0x01, -0x03, -0x01, +0x00, +0x01, -0x03, -0x01, -0x03, -0x03, -0x02, -0x04, +0x01, +0x01, +0x01, -0x07, -0x04, +0x00, -0x01, -0x01, -0x01, -0x09], + [-0x03, +0x07, -0x01, -0x04, -0x04, +0x01, -0x03, -0x04, +0x01, -0x03, -0x04, +0x02, -0x01, -0x05, -0x01, -0x01, -0x02, +0x01, -0x05, -0x04, -0x02, -0x01, -0x02, -0x09], + [-0x01, -0x01, +0x04, +0x02, -0x05, +0x00, +0x01, +0x00, +0x02, -0x02, -0x04, +0x01, -0x03, -0x04, -0x02, +0x01, +0x00, -0x05, -0x02, -0x03, +0x03, +0x00, -0x01, -0x09], + [-0x01, -0x04, +0x02, +0x05, -0x07, +0x01, +0x04, +0x00, +0x00, -0x03, -0x06, -0x01, -0x05, -0x07, -0x03, -0x01, -0x01, -0x08, -0x05, -0x04, +0x04, +0x03, -0x02, -0x09], + [-0x03, -0x04, -0x05, -0x07, +0x09, -0x07, -0x07, -0x05, -0x04, -0x03, -0x08, -0x07, -0x07, -0x06, -0x04, -0x01, -0x03, -0x09, -0x01, -0x03, -0x06, -0x07, -0x04, -0x09], + [-0x01, +0x01, +0x00, +0x01, -0x07, +0x06, +0x02, -0x03, +0x03, -0x03, -0x02, +0x00, -0x01, -0x06, +0x00, -0x02, -0x02, -0x06, -0x06, -0x03, +0x00, +0x04, -0x01, -0x09], + [+0x00, -0x03, +0x01, +0x04, -0x07, +0x02, +0x05, -0x01, -0x01, -0x03, -0x05, -0x01, -0x03, -0x07, -0x02, -0x01, -0x02, -0x09, -0x05, -0x03, +0x03, +0x04, -0x02, -0x09], + [+0x01, -0x04, +0x00, +0x00, -0x05, -0x03, -0x01, +0x05, -0x04, -0x04, -0x06, -0x03, -0x04, -0x05, -0x02, +0x00, -0x02, -0x08, -0x07, -0x02, +0x00, -0x02, -0x02, -0x09], + [-0x03, +0x01, +0x02, +0x00, -0x04, +0x03, -0x01, -0x04, +0x07, -0x04, -0x03, -0x02, -0x04, -0x03, -0x01, -0x02, -0x03, -0x04, -0x01, -0x03, +0x01, +0x01, -0x02, -0x09], + [-0x01, -0x03, -0x02, -0x03, -0x03, -0x03, -0x03, -0x04, -0x04, +0x06, +0x01, -0x03, +0x01, +0x00, -0x04, -0x03, +0x00, -0x07, -0x02, +0x03, -0x03, -0x03, -0x02, -0x09], + [-0x03, -0x04, -0x04, -0x06, -0x08, -0x02, -0x05, -0x06, -0x03, +0x01, +0x06, -0x04, +0x03, +0x00, -0x04, -0x04, -0x03, -0x03, -0x03, +0x01, -0x05, -0x03, -0x02, -0x09], + [-0x03, +0x02, +0x01, -0x01, -0x07, +0x00, -0x01, -0x03, -0x02, -0x03, -0x04, +0x05, +0x00, -0x07, -0x03, -0x01, -0x01, -0x05, -0x05, -0x04, +0x00, -0x01, -0x02, -0x09], + [-0x02, -0x01, -0x03, -0x05, -0x07, -0x01, -0x03, -0x04, -0x04, +0x01, +0x03, +0x00, +0x08, -0x01, -0x04, -0x02, -0x01, -0x06, -0x05, +0x01, -0x04, -0x02, -0x02, -0x09], + [-0x04, -0x05, -0x04, -0x07, -0x06, -0x06, -0x07, -0x05, -0x03, +0x00, +0x00, -0x07, -0x01, +0x08, -0x06, -0x04, -0x04, -0x01, +0x04, -0x03, -0x06, -0x07, -0x04, -0x09], + [+0x01, -0x01, -0x02, -0x03, -0x04, +0x00, -0x02, -0x02, -0x01, -0x04, -0x04, -0x03, -0x04, -0x06, +0x06, +0x00, -0x01, -0x07, -0x07, -0x02, -0x02, -0x01, -0x02, -0x09], + [+0x01, -0x01, +0x01, -0x01, -0x01, -0x02, -0x01, +0x00, -0x02, -0x03, -0x04, -0x01, -0x02, -0x04, +0x00, +0x03, +0x02, -0x03, -0x03, -0x02, +0x00, -0x01, -0x01, -0x09], + [+0x01, -0x02, +0x00, -0x01, -0x03, -0x02, -0x02, -0x02, -0x03, +0x00, -0x03, -0x01, -0x01, -0x04, -0x01, +0x02, +0x05, -0x06, -0x03, +0x00, -0x01, -0x02, -0x01, -0x09], + [-0x07, +0x01, -0x05, -0x08, -0x09, -0x06, -0x09, -0x08, -0x04, -0x07, -0x03, -0x05, -0x06, -0x01, -0x07, -0x03, -0x06, +0x0C, -0x02, -0x08, -0x06, -0x07, -0x05, -0x09], + [-0x04, -0x05, -0x02, -0x05, -0x01, -0x06, -0x05, -0x07, -0x01, -0x02, -0x03, -0x05, -0x05, +0x04, -0x07, -0x03, -0x03, -0x02, +0x08, -0x04, -0x03, -0x05, -0x03, -0x09], + [+0x00, -0x04, -0x03, -0x04, -0x03, -0x03, -0x03, -0x02, -0x03, +0x03, +0x01, -0x04, +0x01, -0x03, -0x02, -0x02, +0x00, -0x08, -0x04, +0x05, -0x03, -0x03, -0x02, -0x09], + [-0x01, -0x02, +0x03, +0x04, -0x06, +0x00, +0x03, +0x00, +0x01, -0x03, -0x05, +0x00, -0x04, -0x06, -0x02, +0x00, -0x01, -0x06, -0x03, -0x03, +0x04, +0x02, -0x01, -0x09], + [-0x01, -0x01, +0x00, +0x03, -0x07, +0x04, +0x04, -0x02, +0x01, -0x03, -0x03, -0x01, -0x02, -0x07, -0x01, -0x01, -0x02, -0x07, -0x05, -0x03, +0x02, +0x04, -0x02, -0x09], + [-0x01, -0x02, -0x01, -0x02, -0x04, -0x01, -0x02, -0x02, -0x02, -0x02, -0x02, -0x02, -0x02, -0x04, -0x02, -0x01, -0x01, -0x05, -0x03, -0x02, -0x01, -0x02, -0x02, -0x09], + [-0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, +0x01]] + +PAM120 = [[+0x03, -0x03, -0x01, +0x00, -0x03, -0x01, +0x00, +0x01, -0x03, -0x01, -0x03, -0x02, -0x02, -0x04, +0x01, +0x01, +0x01, -0x07, -0x04, +0x00, +0x00, -0x01, -0x01, -0x08], + [-0x03, +0x06, -0x01, -0x03, -0x04, +0x01, -0x03, -0x04, +0x01, -0x02, -0x04, +0x02, -0x01, -0x05, -0x01, -0x01, -0x02, +0x01, -0x05, -0x03, -0x02, -0x01, -0x02, -0x08], + [-0x01, -0x01, +0x04, +0x02, -0x05, +0x00, +0x01, +0x00, +0x02, -0x02, -0x04, +0x01, -0x03, -0x04, -0x02, +0x01, +0x00, -0x04, -0x02, -0x03, +0x03, +0x00, -0x01, -0x08], + [+0x00, -0x03, +0x02, +0x05, -0x07, +0x01, +0x03, +0x00, +0x00, -0x03, -0x05, -0x01, -0x04, -0x07, -0x03, +0x00, -0x01, -0x08, -0x05, -0x03, +0x04, +0x03, -0x02, -0x08], + [-0x03, -0x04, -0x05, -0x07, +0x09, -0x07, -0x07, -0x04, -0x04, -0x03, -0x07, -0x07, -0x06, -0x06, -0x04, +0x00, -0x03, -0x08, -0x01, -0x03, -0x06, -0x07, -0x04, -0x08], + [-0x01, +0x01, +0x00, +0x01, -0x07, +0x06, +0x02, -0x03, +0x03, -0x03, -0x02, +0x00, -0x01, -0x06, +0x00, -0x02, -0x02, -0x06, -0x05, -0x03, +0x00, +0x04, -0x01, -0x08], + [+0x00, -0x03, +0x01, +0x03, -0x07, +0x02, +0x05, -0x01, -0x01, -0x03, -0x04, -0x01, -0x03, -0x07, -0x02, -0x01, -0x02, -0x08, -0x05, -0x03, +0x03, +0x04, -0x01, -0x08], + [+0x01, -0x04, +0x00, +0x00, -0x04, -0x03, -0x01, +0x05, -0x04, -0x04, -0x05, -0x03, -0x04, -0x05, -0x02, +0x01, -0x01, -0x08, -0x06, -0x02, +0x00, -0x02, -0x02, -0x08], + [-0x03, +0x01, +0x02, +0x00, -0x04, +0x03, -0x01, -0x04, +0x07, -0x04, -0x03, -0x02, -0x04, -0x03, -0x01, -0x02, -0x03, -0x03, -0x01, -0x03, +0x01, +0x01, -0x02, -0x08], + [-0x01, -0x02, -0x02, -0x03, -0x03, -0x03, -0x03, -0x04, -0x04, +0x06, +0x01, -0x03, +0x01, +0x00, -0x03, -0x02, +0x00, -0x06, -0x02, +0x03, -0x03, -0x03, -0x01, -0x08], + [-0x03, -0x04, -0x04, -0x05, -0x07, -0x02, -0x04, -0x05, -0x03, +0x01, +0x05, -0x04, +0x03, +0x00, -0x03, -0x04, -0x03, -0x03, -0x02, +0x01, -0x04, -0x03, -0x02, -0x08], + [-0x02, +0x02, +0x01, -0x01, -0x07, +0x00, -0x01, -0x03, -0x02, -0x03, -0x04, +0x05, +0x00, -0x07, -0x02, -0x01, -0x01, -0x05, -0x05, -0x04, +0x00, -0x01, -0x02, -0x08], + [-0x02, -0x01, -0x03, -0x04, -0x06, -0x01, -0x03, -0x04, -0x04, +0x01, +0x03, +0x00, +0x08, -0x01, -0x03, -0x02, -0x01, -0x06, -0x04, +0x01, -0x04, -0x02, -0x02, -0x08], + [-0x04, -0x05, -0x04, -0x07, -0x06, -0x06, -0x07, -0x05, -0x03, +0x00, +0x00, -0x07, -0x01, +0x08, -0x05, -0x03, -0x04, -0x01, +0x04, -0x03, -0x05, -0x06, -0x03, -0x08], + [+0x01, -0x01, -0x02, -0x03, -0x04, +0x00, -0x02, -0x02, -0x01, -0x03, -0x03, -0x02, -0x03, -0x05, +0x06, +0x01, -0x01, -0x07, -0x06, -0x02, -0x02, -0x01, -0x02, -0x08], + [+0x01, -0x01, +0x01, +0x00, +0x00, -0x02, -0x01, +0x01, -0x02, -0x02, -0x04, -0x01, -0x02, -0x03, +0x01, +0x03, +0x02, -0x02, -0x03, -0x02, +0x00, -0x01, -0x01, -0x08], + [+0x01, -0x02, +0x00, -0x01, -0x03, -0x02, -0x02, -0x01, -0x03, +0x00, -0x03, -0x01, -0x01, -0x04, -0x01, +0x02, +0x04, -0x06, -0x03, +0x00, +0x00, -0x02, -0x01, -0x08], + [-0x07, +0x01, -0x04, -0x08, -0x08, -0x06, -0x08, -0x08, -0x03, -0x06, -0x03, -0x05, -0x06, -0x01, -0x07, -0x02, -0x06, +0x0C, -0x02, -0x08, -0x06, -0x07, -0x05, -0x08], + [-0x04, -0x05, -0x02, -0x05, -0x01, -0x05, -0x05, -0x06, -0x01, -0x02, -0x02, -0x05, -0x04, +0x04, -0x06, -0x03, -0x03, -0x02, +0x08, -0x03, -0x03, -0x05, -0x03, -0x08], + [+0x00, -0x03, -0x03, -0x03, -0x03, -0x03, -0x03, -0x02, -0x03, +0x03, +0x01, -0x04, +0x01, -0x03, -0x02, -0x02, +0x00, -0x08, -0x03, +0x05, -0x03, -0x03, -0x01, -0x08], + [+0x00, -0x02, +0x03, +0x04, -0x06, +0x00, +0x03, +0x00, +0x01, -0x03, -0x04, +0x00, -0x04, -0x05, -0x02, +0x00, +0x00, -0x06, -0x03, -0x03, +0x04, +0x02, -0x01, -0x08], + [-0x01, -0x01, +0x00, +0x03, -0x07, +0x04, +0x04, -0x02, +0x01, -0x03, -0x03, -0x01, -0x02, -0x06, -0x01, -0x01, -0x02, -0x07, -0x05, -0x03, +0x02, +0x04, -0x01, -0x08], + [-0x01, -0x02, -0x01, -0x02, -0x04, -0x01, -0x01, -0x02, -0x02, -0x01, -0x02, -0x02, -0x02, -0x03, -0x02, -0x01, -0x01, -0x05, -0x03, -0x01, -0x01, -0x01, -0x02, -0x08], + [-0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, +0x01]] + +PAM130 = [[+0x03, -0x03, +0x00, +0x00, -0x03, -0x01, +0x00, +0x01, -0x02, -0x01, -0x03, -0x02, -0x02, -0x04, +0x01, +0x01, +0x01, -0x06, -0x04, +0x00, +0x00, +0x00, -0x01, -0x08], + [-0x03, +0x06, -0x01, -0x03, -0x04, +0x01, -0x03, -0x04, +0x01, -0x02, -0x04, +0x02, -0x01, -0x05, -0x01, -0x01, -0x02, +0x01, -0x05, -0x03, -0x02, -0x01, -0x02, -0x08], + [+0x00, -0x01, +0x04, +0x02, -0x04, +0x00, +0x01, +0x00, +0x02, -0x02, -0x03, +0x01, -0x03, -0x04, -0x01, +0x01, +0x00, -0x04, -0x02, -0x03, +0x03, +0x00, -0x01, -0x08], + [+0x00, -0x03, +0x02, +0x05, -0x06, +0x01, +0x03, +0x00, +0x00, -0x03, -0x05, -0x01, -0x04, -0x07, -0x02, +0x00, -0x01, -0x07, -0x05, -0x03, +0x04, +0x03, -0x01, -0x08], + [-0x03, -0x04, -0x04, -0x06, +0x09, -0x06, -0x06, -0x04, -0x04, -0x03, -0x07, -0x06, -0x06, -0x05, -0x03, +0x00, -0x03, -0x08, -0x01, -0x02, -0x05, -0x06, -0x04, -0x08], + [-0x01, +0x01, +0x00, +0x01, -0x06, +0x05, +0x02, -0x02, +0x03, -0x03, -0x02, +0x00, -0x01, -0x06, +0x00, -0x01, -0x02, -0x06, -0x05, -0x03, +0x00, +0x04, -0x01, -0x08], + [+0x00, -0x03, +0x01, +0x03, -0x06, +0x02, +0x05, -0x01, +0x00, -0x02, -0x04, -0x01, -0x03, -0x06, -0x02, -0x01, -0x01, -0x08, -0x05, -0x03, +0x02, +0x04, -0x01, -0x08], + [+0x01, -0x04, +0x00, +0x00, -0x04, -0x02, -0x01, +0x05, -0x03, -0x04, -0x05, -0x03, -0x04, -0x05, -0x02, +0x01, -0x01, -0x07, -0x06, -0x02, +0x00, -0x01, -0x02, -0x08], + [-0x02, +0x01, +0x02, +0x00, -0x04, +0x03, +0x00, -0x03, +0x07, -0x03, -0x03, -0x01, -0x03, -0x02, -0x01, -0x02, -0x02, -0x03, +0x00, -0x03, +0x01, +0x01, -0x01, -0x08], + [-0x01, -0x02, -0x02, -0x03, -0x03, -0x03, -0x02, -0x04, -0x03, +0x05, +0x01, -0x02, +0x02, +0x00, -0x03, -0x02, +0x00, -0x06, -0x02, +0x03, -0x03, -0x03, -0x01, -0x08], + [-0x03, -0x04, -0x03, -0x05, -0x07, -0x02, -0x04, -0x05, -0x03, +0x01, +0x05, -0x04, +0x03, +0x01, -0x03, -0x04, -0x02, -0x02, -0x02, +0x01, -0x04, -0x03, -0x02, -0x08], + [-0x02, +0x02, +0x01, -0x01, -0x06, +0x00, -0x01, -0x03, -0x01, -0x02, -0x04, +0x05, +0x00, -0x06, -0x02, -0x01, +0x00, -0x05, -0x05, -0x04, +0x00, +0x00, -0x01, -0x08], + [-0x02, -0x01, -0x03, -0x04, -0x06, -0x01, -0x03, -0x04, -0x03, +0x02, +0x03, +0x00, +0x08, -0x01, -0x03, -0x02, -0x01, -0x05, -0x04, +0x01, -0x03, -0x02, -0x01, -0x08], + [-0x04, -0x05, -0x04, -0x07, -0x05, -0x06, -0x06, -0x05, -0x02, +0x00, +0x01, -0x06, -0x01, +0x07, -0x05, -0x03, -0x04, -0x01, +0x04, -0x02, -0x05, -0x06, -0x03, -0x08], + [+0x01, -0x01, -0x01, -0x02, -0x03, +0x00, -0x02, -0x02, -0x01, -0x03, -0x03, -0x02, -0x03, -0x05, +0x06, +0x01, -0x01, -0x06, -0x06, -0x02, -0x02, -0x01, -0x01, -0x08], + [+0x01, -0x01, +0x01, +0x00, +0x00, -0x01, -0x01, +0x01, -0x02, -0x02, -0x04, -0x01, -0x02, -0x03, +0x01, +0x03, +0x02, -0x02, -0x03, -0x02, +0x00, -0x01, -0x01, -0x08], + [+0x01, -0x02, +0x00, -0x01, -0x03, -0x02, -0x01, -0x01, -0x02, +0x00, -0x02, +0x00, -0x01, -0x04, -0x01, +0x02, +0x04, -0x06, -0x03, +0x00, +0x00, -0x02, -0x01, -0x08], + [-0x06, +0x01, -0x04, -0x07, -0x08, -0x06, -0x08, -0x07, -0x03, -0x06, -0x02, -0x05, -0x05, -0x01, -0x06, -0x02, -0x06, +0x0C, -0x01, -0x07, -0x05, -0x07, -0x05, -0x08], + [-0x04, -0x05, -0x02, -0x05, -0x01, -0x05, -0x05, -0x06, +0x00, -0x02, -0x02, -0x05, -0x04, +0x04, -0x06, -0x03, -0x03, -0x01, +0x08, -0x03, -0x03, -0x05, -0x03, -0x08], + [+0x00, -0x03, -0x03, -0x03, -0x02, -0x03, -0x03, -0x02, -0x03, +0x03, +0x01, -0x04, +0x01, -0x02, -0x02, -0x02, +0x00, -0x07, -0x03, +0x05, -0x03, -0x03, -0x01, -0x08], + [+0x00, -0x02, +0x03, +0x04, -0x05, +0x00, +0x02, +0x00, +0x01, -0x03, -0x04, +0x00, -0x03, -0x05, -0x02, +0x00, +0x00, -0x05, -0x03, -0x03, +0x03, +0x02, -0x01, -0x08], + [+0x00, -0x01, +0x00, +0x03, -0x06, +0x04, +0x04, -0x01, +0x01, -0x03, -0x03, +0x00, -0x02, -0x06, -0x01, -0x01, -0x02, -0x07, -0x05, -0x03, +0x02, +0x04, -0x01, -0x08], + [-0x01, -0x02, -0x01, -0x01, -0x04, -0x01, -0x01, -0x02, -0x01, -0x01, -0x02, -0x01, -0x01, -0x03, -0x01, -0x01, -0x01, -0x05, -0x03, -0x01, -0x01, -0x01, -0x01, -0x08], + [-0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, +0x01]] + +PAM140 = [[+0x03, -0x02, +0x00, +0x00, -0x02, -0x01, +0x00, +0x01, -0x02, -0x01, -0x02, -0x02, -0x02, -0x04, +0x01, +0x01, +0x01, -0x06, -0x04, +0x00, +0x00, +0x00, -0x01, -0x08], + [-0x02, +0x06, -0x01, -0x03, -0x04, +0x01, -0x02, -0x04, +0x01, -0x02, -0x04, +0x03, -0x01, -0x05, -0x01, -0x01, -0x02, +0x01, -0x05, -0x03, -0x02, -0x01, -0x01, -0x08], + [+0x00, -0x01, +0x03, +0x02, -0x04, +0x00, +0x01, +0x00, +0x02, -0x02, -0x03, +0x01, -0x02, -0x04, -0x01, +0x01, +0x00, -0x04, -0x02, -0x02, +0x03, +0x01, -0x01, -0x08], + [+0x00, -0x03, +0x02, +0x04, -0x06, +0x01, +0x03, +0x00, +0x00, -0x03, -0x05, -0x01, -0x04, -0x06, -0x02, +0x00, -0x01, -0x07, -0x05, -0x03, +0x04, +0x03, -0x01, -0x08], + [-0x02, -0x04, -0x04, -0x06, +0x09, -0x06, -0x06, -0x04, -0x04, -0x03, -0x07, -0x06, -0x06, -0x05, -0x03, +0x00, -0x03, -0x08, -0x01, -0x02, -0x05, -0x06, -0x04, -0x08], + [-0x01, +0x01, +0x00, +0x01, -0x06, +0x05, +0x02, -0x02, +0x03, -0x03, -0x02, +0x00, -0x01, -0x05, +0x00, -0x01, -0x02, -0x05, -0x05, -0x02, +0x01, +0x04, -0x01, -0x08], + [+0x00, -0x02, +0x01, +0x03, -0x06, +0x02, +0x04, -0x01, +0x00, -0x02, -0x04, -0x01, -0x03, -0x06, -0x01, -0x01, -0x01, -0x08, -0x04, -0x02, +0x02, +0x04, -0x01, -0x08], + [+0x01, -0x04, +0x00, +0x00, -0x04, -0x02, -0x01, +0x05, -0x03, -0x04, -0x05, -0x03, -0x03, -0x05, -0x01, +0x01, -0x01, -0x07, -0x06, -0x02, +0x00, -0x01, -0x01, -0x08], + [-0x02, +0x01, +0x02, +0x00, -0x04, +0x03, +0x00, -0x03, +0x06, -0x03, -0x02, -0x01, -0x03, -0x02, -0x01, -0x01, -0x02, -0x03, +0x00, -0x03, +0x01, +0x01, -0x01, -0x08], + [-0x01, -0x02, -0x02, -0x03, -0x03, -0x03, -0x02, -0x04, -0x03, +0x05, +0x01, -0x02, +0x02, +0x00, -0x03, -0x02, +0x00, -0x06, -0x02, +0x03, -0x02, -0x02, -0x01, -0x08], + [-0x02, -0x04, -0x03, -0x05, -0x07, -0x02, -0x04, -0x05, -0x02, +0x01, +0x05, -0x03, +0x03, +0x01, -0x03, -0x03, -0x02, -0x02, -0x02, +0x01, -0x04, -0x03, -0x02, -0x08], + [-0x02, +0x03, +0x01, -0x01, -0x06, +0x00, -0x01, -0x03, -0x01, -0x02, -0x03, +0x05, +0x00, -0x06, -0x02, -0x01, +0x00, -0x04, -0x05, -0x03, +0x00, +0x00, -0x01, -0x08], + [-0x02, -0x01, -0x02, -0x04, -0x06, -0x01, -0x03, -0x03, -0x03, +0x02, +0x03, +0x00, +0x07, -0x01, -0x03, -0x02, -0x01, -0x05, -0x04, +0x01, -0x03, -0x02, -0x01, -0x08], + [-0x04, -0x05, -0x04, -0x06, -0x05, -0x05, -0x06, -0x05, -0x02, +0x00, +0x01, -0x06, -0x01, +0x07, -0x05, -0x03, -0x04, -0x01, +0x04, -0x02, -0x05, -0x06, -0x03, -0x08], + [+0x01, -0x01, -0x01, -0x02, -0x03, +0x00, -0x01, -0x01, -0x01, -0x03, -0x03, -0x02, -0x03, -0x05, +0x06, +0x01, +0x00, -0x06, -0x06, -0x02, -0x02, -0x01, -0x01, -0x08], + [+0x01, -0x01, +0x01, +0x00, +0x00, -0x01, -0x01, +0x01, -0x01, -0x02, -0x03, -0x01, -0x02, -0x03, +0x01, +0x03, +0x02, -0x02, -0x03, -0x02, +0x00, -0x01, +0x00, -0x08], + [+0x01, -0x02, +0x00, -0x01, -0x03, -0x02, -0x01, -0x01, -0x02, +0x00, -0x02, +0x00, -0x01, -0x04, +0x00, +0x02, +0x04, -0x05, -0x03, +0x00, +0x00, -0x01, -0x01, -0x08], + [-0x06, +0x01, -0x04, -0x07, -0x08, -0x05, -0x08, -0x07, -0x03, -0x06, -0x02, -0x04, -0x05, -0x01, -0x06, -0x02, -0x05, +0x0C, -0x01, -0x07, -0x05, -0x06, -0x05, -0x08], + [-0x04, -0x05, -0x02, -0x05, -0x01, -0x05, -0x04, -0x06, +0x00, -0x02, -0x02, -0x05, -0x04, +0x04, -0x06, -0x03, -0x03, -0x01, +0x08, -0x03, -0x03, -0x04, -0x03, -0x08], + [+0x00, -0x03, -0x02, -0x03, -0x02, -0x02, -0x02, -0x02, -0x03, +0x03, +0x01, -0x03, +0x01, -0x02, -0x02, -0x02, +0x00, -0x07, -0x03, +0x05, -0x03, -0x02, -0x01, -0x08], + [+0x00, -0x02, +0x03, +0x04, -0x05, +0x01, +0x02, +0x00, +0x01, -0x02, -0x04, +0x00, -0x03, -0x05, -0x02, +0x00, +0x00, -0x05, -0x03, -0x03, +0x03, +0x02, -0x01, -0x08], + [+0x00, -0x01, +0x01, +0x03, -0x06, +0x04, +0x04, -0x01, +0x01, -0x02, -0x03, +0x00, -0x02, -0x06, -0x01, -0x01, -0x01, -0x06, -0x04, -0x02, +0x02, +0x04, -0x01, -0x08], + [-0x01, -0x01, -0x01, -0x01, -0x04, -0x01, -0x01, -0x01, -0x01, -0x01, -0x02, -0x01, -0x01, -0x03, -0x01, +0x00, -0x01, -0x05, -0x03, -0x01, -0x01, -0x01, -0x01, -0x08], + [-0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, +0x01]] + +PAM150 = [[+0x03, -0x02, +0x00, +0x00, -0x02, -0x01, +0x00, +0x01, -0x02, -0x01, -0x02, -0x02, -0x01, -0x04, +0x01, +0x01, +0x01, -0x06, -0x03, +0x00, +0x00, +0x00, -0x01, -0x07], + [-0x02, +0x06, -0x01, -0x02, -0x04, +0x01, -0x02, -0x03, +0x01, -0x02, -0x03, +0x03, -0x01, -0x04, -0x01, -0x01, -0x02, +0x01, -0x04, -0x03, -0x02, +0x00, -0x01, -0x07], + [+0x00, -0x01, +0x03, +0x02, -0x04, +0x00, +0x01, +0x00, +0x02, -0x02, -0x03, +0x01, -0x02, -0x04, -0x01, +0x01, +0x00, -0x04, -0x02, -0x02, +0x03, +0x01, -0x01, -0x07], + [+0x00, -0x02, +0x02, +0x04, -0x06, +0x01, +0x03, +0x00, +0x00, -0x03, -0x05, -0x01, -0x03, -0x06, -0x02, +0x00, -0x01, -0x07, -0x04, -0x03, +0x03, +0x02, -0x01, -0x07], + [-0x02, -0x04, -0x04, -0x06, +0x09, -0x06, -0x06, -0x04, -0x03, -0x02, -0x06, -0x06, -0x05, -0x05, -0x03, +0x00, -0x03, -0x07, +0x00, -0x02, -0x05, -0x06, -0x03, -0x07], + [-0x01, +0x01, +0x00, +0x01, -0x06, +0x05, +0x02, -0x02, +0x03, -0x03, -0x02, +0x00, -0x01, -0x05, +0x00, -0x01, -0x01, -0x05, -0x04, -0x02, +0x01, +0x04, -0x01, -0x07], + [+0x00, -0x02, +0x01, +0x03, -0x06, +0x02, +0x04, -0x01, +0x00, -0x02, -0x04, -0x01, -0x02, -0x06, -0x01, -0x01, -0x01, -0x07, -0x04, -0x02, +0x02, +0x04, -0x01, -0x07], + [+0x01, -0x03, +0x00, +0x00, -0x04, -0x02, -0x01, +0x04, -0x03, -0x03, -0x04, -0x02, -0x03, -0x05, -0x01, +0x01, -0x01, -0x07, -0x05, -0x02, +0x00, -0x01, -0x01, -0x07], + [-0x02, +0x01, +0x02, +0x00, -0x03, +0x03, +0x00, -0x03, +0x06, -0x03, -0x02, -0x01, -0x03, -0x02, -0x01, -0x01, -0x02, -0x03, +0x00, -0x03, +0x01, +0x01, -0x01, -0x07], + [-0x01, -0x02, -0x02, -0x03, -0x02, -0x03, -0x02, -0x03, -0x03, +0x05, +0x01, -0x02, +0x02, +0x00, -0x03, -0x02, +0x00, -0x05, -0x02, +0x03, -0x02, -0x02, -0x01, -0x07], + [-0x02, -0x03, -0x03, -0x05, -0x06, -0x02, -0x04, -0x04, -0x02, +0x01, +0x05, -0x03, +0x03, +0x01, -0x03, -0x03, -0x02, -0x02, -0x02, +0x01, -0x04, -0x03, -0x02, -0x07], + [-0x02, +0x03, +0x01, -0x01, -0x06, +0x00, -0x01, -0x02, -0x01, -0x02, -0x03, +0x04, +0x00, -0x06, -0x02, -0x01, +0x00, -0x04, -0x04, -0x03, +0x00, +0x00, -0x01, -0x07], + [-0x01, -0x01, -0x02, -0x03, -0x05, -0x01, -0x02, -0x03, -0x03, +0x02, +0x03, +0x00, +0x07, -0x01, -0x03, -0x02, -0x01, -0x05, -0x03, +0x01, -0x03, -0x02, -0x01, -0x07], + [-0x04, -0x04, -0x04, -0x06, -0x05, -0x05, -0x06, -0x05, -0x02, +0x00, +0x01, -0x06, -0x01, +0x07, -0x05, -0x03, -0x03, -0x01, +0x05, -0x02, -0x05, -0x05, -0x03, -0x07], + [+0x01, -0x01, -0x01, -0x02, -0x03, +0x00, -0x01, -0x01, -0x01, -0x03, -0x03, -0x02, -0x03, -0x05, +0x06, +0x01, +0x00, -0x06, -0x05, -0x02, -0x02, -0x01, -0x01, -0x07], + [+0x01, -0x01, +0x01, +0x00, +0x00, -0x01, -0x01, +0x01, -0x01, -0x02, -0x03, -0x01, -0x02, -0x03, +0x01, +0x02, +0x01, -0x02, -0x03, -0x01, +0x00, -0x01, +0x00, -0x07], + [+0x01, -0x02, +0x00, -0x01, -0x03, -0x01, -0x01, -0x01, -0x02, +0x00, -0x02, +0x00, -0x01, -0x03, +0x00, +0x01, +0x04, -0x05, -0x03, +0x00, +0x00, -0x01, -0x01, -0x07], + [-0x06, +0x01, -0x04, -0x07, -0x07, -0x05, -0x07, -0x07, -0x03, -0x05, -0x02, -0x04, -0x05, -0x01, -0x06, -0x02, -0x05, +0x0C, -0x01, -0x06, -0x05, -0x06, -0x04, -0x07], + [-0x03, -0x04, -0x02, -0x04, +0x00, -0x04, -0x04, -0x05, +0x00, -0x02, -0x02, -0x04, -0x03, +0x05, -0x05, -0x03, -0x03, -0x01, +0x08, -0x03, -0x03, -0x04, -0x03, -0x07], + [+0x00, -0x03, -0x02, -0x03, -0x02, -0x02, -0x02, -0x02, -0x03, +0x03, +0x01, -0x03, +0x01, -0x02, -0x02, -0x01, +0x00, -0x06, -0x03, +0x04, -0x02, -0x02, -0x01, -0x07], + [+0x00, -0x02, +0x03, +0x03, -0x05, +0x01, +0x02, +0x00, +0x01, -0x02, -0x04, +0x00, -0x03, -0x05, -0x02, +0x00, +0x00, -0x05, -0x03, -0x02, +0x03, +0x02, -0x01, -0x07], + [+0x00, +0x00, +0x01, +0x02, -0x06, +0x04, +0x04, -0x01, +0x01, -0x02, -0x03, +0x00, -0x02, -0x05, -0x01, -0x01, -0x01, -0x06, -0x04, -0x02, +0x02, +0x04, -0x01, -0x07], + [-0x01, -0x01, -0x01, -0x01, -0x03, -0x01, -0x01, -0x01, -0x01, -0x01, -0x02, -0x01, -0x01, -0x03, -0x01, +0x00, -0x01, -0x04, -0x03, -0x01, -0x01, -0x01, -0x01, -0x07], + [-0x07, -0x07, -0x07, -0x07, -0x07, -0x07, -0x07, -0x07, -0x07, -0x07, -0x07, -0x07, -0x07, -0x07, -0x07, -0x07, -0x07, -0x07, -0x07, -0x07, -0x07, -0x07, -0x07, +0x01]] + +PAM160 = [[+0x02, -0x02, +0x00, +0x00, -0x02, -0x01, +0x00, +0x01, -0x02, -0x01, -0x02, -0x02, -0x01, -0x03, +0x01, +0x01, +0x01, -0x05, -0x03, +0x00, +0x00, +0x00, +0x00, -0x07], + [-0x02, +0x06, -0x01, -0x02, -0x03, +0x01, -0x02, -0x03, +0x01, -0x02, -0x03, +0x03, -0x01, -0x04, -0x01, -0x01, -0x01, +0x01, -0x04, -0x03, -0x01, +0x00, -0x01, -0x07], + [+0x00, -0x01, +0x03, +0x02, -0x04, +0x00, +0x01, +0x00, +0x02, -0x02, -0x03, +0x01, -0x02, -0x03, -0x01, +0x01, +0x00, -0x04, -0x02, -0x02, +0x02, +0x01, +0x00, -0x07], + [+0x00, -0x02, +0x02, +0x04, -0x05, +0x01, +0x03, +0x00, +0x00, -0x03, -0x04, +0x00, -0x03, -0x06, -0x02, +0x00, -0x01, -0x06, -0x04, -0x03, +0x03, +0x02, -0x01, -0x07], + [-0x02, -0x03, -0x04, -0x05, +0x09, -0x05, -0x05, -0x03, -0x03, -0x02, -0x06, -0x05, -0x05, -0x05, -0x03, +0x00, -0x02, -0x07, +0x00, -0x02, -0x04, -0x05, -0x03, -0x07], + [-0x01, +0x01, +0x00, +0x01, -0x05, +0x05, +0x02, -0x02, +0x02, -0x02, -0x02, +0x00, -0x01, -0x05, +0x00, -0x01, -0x01, -0x05, -0x04, -0x02, +0x01, +0x03, -0x01, -0x07], + [+0x00, -0x02, +0x01, +0x03, -0x05, +0x02, +0x04, +0x00, +0x00, -0x02, -0x03, -0x01, -0x02, -0x05, -0x01, +0x00, -0x01, -0x07, -0x04, -0x02, +0x02, +0x03, -0x01, -0x07], + [+0x01, -0x03, +0x00, +0x00, -0x03, -0x02, +0x00, +0x04, -0x03, -0x03, -0x04, -0x02, -0x03, -0x04, -0x01, +0x01, -0x01, -0x07, -0x05, -0x02, +0x00, -0x01, -0x01, -0x07], + [-0x02, +0x01, +0x02, +0x00, -0x03, +0x02, +0x00, -0x03, +0x06, -0x03, -0x02, -0x01, -0x03, -0x02, -0x01, -0x01, -0x02, -0x03, +0x00, -0x02, +0x01, +0x01, -0x01, -0x07], + [-0x01, -0x02, -0x02, -0x03, -0x02, -0x02, -0x02, -0x03, -0x03, +0x05, +0x02, -0x02, +0x02, +0x00, -0x02, -0x02, +0x00, -0x05, -0x02, +0x03, -0x02, -0x02, -0x01, -0x07], + [-0x02, -0x03, -0x03, -0x04, -0x06, -0x02, -0x03, -0x04, -0x02, +0x02, +0x05, -0x03, +0x03, +0x01, -0x03, -0x03, -0x02, -0x02, -0x02, +0x01, -0x04, -0x03, -0x02, -0x07], + [-0x02, +0x03, +0x01, +0x00, -0x05, +0x00, -0x01, -0x02, -0x01, -0x02, -0x03, +0x04, +0x00, -0x05, -0x02, -0x01, +0x00, -0x04, -0x04, -0x03, +0x00, +0x00, -0x01, -0x07], + [-0x01, -0x01, -0x02, -0x03, -0x05, -0x01, -0x02, -0x03, -0x03, +0x02, +0x03, +0x00, +0x07, +0x00, -0x02, -0x02, -0x01, -0x04, -0x03, +0x01, -0x03, -0x02, -0x01, -0x07], + [-0x03, -0x04, -0x03, -0x06, -0x05, -0x05, -0x05, -0x04, -0x02, +0x00, +0x01, -0x05, +0x00, +0x07, -0x04, -0x03, -0x03, -0x01, +0x05, -0x02, -0x04, -0x05, -0x03, -0x07], + [+0x01, -0x01, -0x01, -0x02, -0x03, +0x00, -0x01, -0x01, -0x01, -0x02, -0x03, -0x02, -0x02, -0x04, +0x05, +0x01, +0x00, -0x05, -0x05, -0x02, -0x01, -0x01, -0x01, -0x07], + [+0x01, -0x01, +0x01, +0x00, +0x00, -0x01, +0x00, +0x01, -0x01, -0x02, -0x03, -0x01, -0x02, -0x03, +0x01, +0x02, +0x01, -0x02, -0x03, -0x01, +0x00, -0x01, +0x00, -0x07], + [+0x01, -0x01, +0x00, -0x01, -0x02, -0x01, -0x01, -0x01, -0x02, +0x00, -0x02, +0x00, -0x01, -0x03, +0x00, +0x01, +0x03, -0x05, -0x03, +0x00, +0x00, -0x01, +0x00, -0x07], + [-0x05, +0x01, -0x04, -0x06, -0x07, -0x05, -0x07, -0x07, -0x03, -0x05, -0x02, -0x04, -0x04, -0x01, -0x05, -0x02, -0x05, +0x0C, -0x01, -0x06, -0x05, -0x06, -0x04, -0x07], + [-0x03, -0x04, -0x02, -0x04, +0x00, -0x04, -0x04, -0x05, +0x00, -0x02, -0x02, -0x04, -0x03, +0x05, -0x05, -0x03, -0x03, -0x01, +0x08, -0x03, -0x03, -0x04, -0x03, -0x07], + [+0x00, -0x03, -0x02, -0x03, -0x02, -0x02, -0x02, -0x02, -0x02, +0x03, +0x01, -0x03, +0x01, -0x02, -0x02, -0x01, +0x00, -0x06, -0x03, +0x04, -0x02, -0x02, -0x01, -0x07], + [+0x00, -0x01, +0x02, +0x03, -0x04, +0x01, +0x02, +0x00, +0x01, -0x02, -0x04, +0x00, -0x03, -0x04, -0x01, +0x00, +0x00, -0x05, -0x03, -0x02, +0x03, +0x02, -0x01, -0x07], + [+0x00, +0x00, +0x01, +0x02, -0x05, +0x03, +0x03, -0x01, +0x01, -0x02, -0x03, +0x00, -0x02, -0x05, -0x01, -0x01, -0x01, -0x06, -0x04, -0x02, +0x02, +0x03, -0x01, -0x07], + [+0x00, -0x01, +0x00, -0x01, -0x03, -0x01, -0x01, -0x01, -0x01, -0x01, -0x02, -0x01, -0x01, -0x03, -0x01, +0x00, +0x00, -0x04, -0x03, -0x01, -0x01, -0x01, -0x01, -0x07], + [-0x07, -0x07, -0x07, -0x07, -0x07, -0x07, -0x07, -0x07, -0x07, -0x07, -0x07, -0x07, -0x07, -0x07, -0x07, -0x07, -0x07, -0x07, -0x07, -0x07, -0x07, -0x07, -0x07, +0x01]] + +PAM170 = [[+0x03, -0x03, +0x00, +0x00, -0x03, -0x01, +0x00, +0x01, -0x03, -0x01, -0x03, -0x02, -0x02, -0x05, +0x01, +0x02, +0x02, -0x08, -0x05, +0x00, +0x00, +0x00, -0x01, -0x0A], + [-0x03, +0x08, -0x01, -0x03, -0x05, +0x01, -0x02, -0x04, +0x02, -0x03, -0x04, +0x04, -0x01, -0x06, -0x01, -0x01, -0x02, +0x02, -0x06, -0x04, -0x02, +0x00, -0x02, -0x0A], + [+0x00, -0x01, +0x04, +0x03, -0x05, +0x00, +0x02, +0x00, +0x02, -0x03, -0x04, +0x01, -0x03, -0x05, -0x01, +0x01, +0x00, -0x05, -0x03, -0x03, +0x03, +0x01, -0x01, -0x0A], + [+0x00, -0x03, +0x03, +0x06, -0x07, +0x02, +0x05, +0x00, +0x00, -0x04, -0x06, -0x01, -0x04, -0x08, -0x02, +0x00, -0x01, -0x09, -0x06, -0x04, +0x05, +0x04, -0x01, -0x0A], + [-0x03, -0x05, -0x05, -0x07, +0x0D, -0x08, -0x08, -0x05, -0x05, -0x03, -0x09, -0x08, -0x07, -0x06, -0x04, +0x00, -0x03, -0x0A, +0x00, -0x03, -0x06, -0x08, -0x04, -0x0A], + [-0x01, +0x01, +0x00, +0x02, -0x08, +0x06, +0x03, -0x02, +0x04, -0x03, -0x02, +0x00, -0x01, -0x07, +0x00, -0x01, -0x02, -0x07, -0x06, -0x03, +0x01, +0x05, -0x01, -0x0A], + [+0x00, -0x02, +0x02, +0x05, -0x08, +0x03, +0x06, +0x00, +0x00, -0x03, -0x05, -0x01, -0x03, -0x08, -0x01, -0x01, -0x01, -0x0A, -0x06, -0x03, +0x03, +0x05, -0x01, -0x0A], + [+0x01, -0x04, +0x00, +0x00, -0x05, -0x02, +0x00, +0x06, -0x04, -0x04, -0x06, -0x03, -0x04, -0x06, -0x02, +0x01, -0x01, -0x09, -0x07, -0x02, +0x00, -0x01, -0x02, -0x0A], + [-0x03, +0x02, +0x02, +0x00, -0x05, +0x04, +0x00, -0x04, +0x09, -0x04, -0x03, -0x01, -0x04, -0x03, -0x01, -0x02, -0x02, -0x04, +0x00, -0x03, +0x01, +0x02, -0x01, -0x0A], + [-0x01, -0x03, -0x03, -0x04, -0x03, -0x03, -0x03, -0x04, -0x04, +0x07, +0x02, -0x03, +0x02, +0x01, -0x03, -0x02, +0x00, -0x07, -0x02, +0x05, -0x03, -0x03, -0x01, -0x0A], + [-0x03, -0x04, -0x04, -0x06, -0x09, -0x02, -0x05, -0x06, -0x03, +0x02, +0x07, -0x04, +0x04, +0x01, -0x04, -0x04, -0x03, -0x03, -0x02, +0x02, -0x05, -0x04, -0x02, -0x0A], + [-0x02, +0x04, +0x01, -0x01, -0x08, +0x00, -0x01, -0x03, -0x01, -0x03, -0x04, +0x06, +0x01, -0x08, -0x02, -0x01, +0x00, -0x05, -0x06, -0x04, +0x00, +0x00, -0x02, -0x0A], + [-0x02, -0x01, -0x03, -0x04, -0x07, -0x01, -0x03, -0x04, -0x04, +0x02, +0x04, +0x01, +0x0A, +0x00, -0x03, -0x02, -0x01, -0x06, -0x04, +0x02, -0x04, -0x02, -0x01, -0x0A], + [-0x05, -0x06, -0x05, -0x08, -0x06, -0x07, -0x08, -0x06, -0x03, +0x01, +0x01, -0x08, +0x00, +0x0A, -0x06, -0x04, -0x05, -0x01, +0x07, -0x02, -0x06, -0x07, -0x04, -0x0A], + [+0x01, -0x01, -0x01, -0x02, -0x04, +0x00, -0x01, -0x02, -0x01, -0x03, -0x04, -0x02, -0x03, -0x06, +0x08, +0x01, +0x00, -0x08, -0x07, -0x02, -0x02, -0x01, -0x01, -0x0A], + [+0x02, -0x01, +0x01, +0x00, +0x00, -0x01, -0x01, +0x01, -0x02, -0x02, -0x04, -0x01, -0x02, -0x04, +0x01, +0x03, +0x02, -0x03, -0x04, -0x02, +0x01, -0x01, +0x00, -0x0A], + [+0x02, -0x02, +0x00, -0x01, -0x03, -0x02, -0x01, -0x01, -0x02, +0x00, -0x03, +0x00, -0x01, -0x05, +0x00, +0x02, +0x05, -0x07, -0x04, +0x00, +0x00, -0x01, -0x01, -0x0A], + [-0x08, +0x02, -0x05, -0x09, -0x0A, -0x07, -0x0A, -0x09, -0x04, -0x07, -0x03, -0x05, -0x06, -0x01, -0x08, -0x03, -0x07, +0x12, -0x01, -0x09, -0x07, -0x08, -0x06, -0x0A], + [-0x05, -0x06, -0x03, -0x06, +0x00, -0x06, -0x06, -0x07, +0x00, -0x02, -0x02, -0x06, -0x04, +0x07, -0x07, -0x04, -0x04, -0x01, +0x0C, -0x04, -0x04, -0x06, -0x04, -0x0A], + [+0x00, -0x04, -0x03, -0x04, -0x03, -0x03, -0x03, -0x02, -0x03, +0x05, +0x02, -0x04, +0x02, -0x02, -0x02, -0x02, +0x00, -0x09, -0x04, +0x06, -0x03, -0x03, -0x01, -0x0A], + [+0x00, -0x02, +0x03, +0x05, -0x06, +0x01, +0x03, +0x00, +0x01, -0x03, -0x05, +0x00, -0x04, -0x06, -0x02, +0x01, +0x00, -0x07, -0x04, -0x03, +0x04, +0x03, -0x01, -0x0A], + [+0x00, +0x00, +0x01, +0x04, -0x08, +0x05, +0x05, -0x01, +0x02, -0x03, -0x04, +0x00, -0x02, -0x07, -0x01, -0x01, -0x01, -0x08, -0x06, -0x03, +0x03, +0x05, -0x01, -0x0A], + [-0x01, -0x02, -0x01, -0x01, -0x04, -0x01, -0x01, -0x02, -0x01, -0x01, -0x02, -0x02, -0x01, -0x04, -0x01, +0x00, -0x01, -0x06, -0x04, -0x01, -0x01, -0x01, -0x02, -0x0A], + [-0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, +0x01]] + +PAM180 = [[+0x03, -0x03, +0x00, +0x00, -0x03, -0x01, +0x00, +0x01, -0x02, -0x01, -0x03, -0x02, -0x02, -0x05, +0x01, +0x01, +0x02, -0x08, -0x05, +0x00, +0x00, +0x00, -0x01, -0x0A], + [-0x03, +0x08, -0x01, -0x03, -0x05, +0x01, -0x02, -0x04, +0x02, -0x03, -0x04, +0x04, -0x01, -0x06, -0x01, -0x01, -0x02, +0x02, -0x06, -0x04, -0x02, +0x00, -0x02, -0x0A], + [+0x00, -0x01, +0x04, +0x03, -0x05, +0x00, +0x02, +0x00, +0x02, -0x03, -0x04, +0x01, -0x03, -0x05, -0x01, +0x01, +0x00, -0x05, -0x02, -0x03, +0x03, +0x01, -0x01, -0x0A], + [+0x00, -0x03, +0x03, +0x05, -0x07, +0x02, +0x04, +0x00, +0x00, -0x03, -0x06, +0x00, -0x04, -0x08, -0x02, +0x00, -0x01, -0x09, -0x06, -0x03, +0x04, +0x03, -0x01, -0x0A], + [-0x03, -0x05, -0x05, -0x07, +0x0D, -0x07, -0x07, -0x05, -0x04, -0x03, -0x08, -0x07, -0x07, -0x06, -0x04, +0x00, -0x03, -0x0A, +0x00, -0x03, -0x06, -0x07, -0x04, -0x0A], + [-0x01, +0x01, +0x00, +0x02, -0x07, +0x06, +0x03, -0x02, +0x04, -0x03, -0x02, +0x00, -0x01, -0x06, +0x00, -0x01, -0x02, -0x06, -0x06, -0x03, +0x01, +0x05, -0x01, -0x0A], + [+0x00, -0x02, +0x02, +0x04, -0x07, +0x03, +0x05, +0x00, +0x00, -0x03, -0x05, -0x01, -0x03, -0x07, -0x01, -0x01, -0x01, -0x09, -0x06, -0x03, +0x03, +0x05, -0x01, -0x0A], + [+0x01, -0x04, +0x00, +0x00, -0x05, -0x02, +0x00, +0x06, -0x03, -0x04, -0x06, -0x03, -0x04, -0x06, -0x01, +0x01, -0x01, -0x09, -0x07, -0x02, +0x00, -0x01, -0x02, -0x0A], + [-0x02, +0x02, +0x02, +0x00, -0x04, +0x04, +0x00, -0x03, +0x08, -0x04, -0x03, -0x01, -0x03, -0x03, -0x01, -0x02, -0x02, -0x04, +0x00, -0x03, +0x01, +0x02, -0x01, -0x0A], + [-0x01, -0x03, -0x03, -0x03, -0x03, -0x03, -0x03, -0x04, -0x04, +0x06, +0x02, -0x03, +0x02, +0x01, -0x03, -0x02, +0x00, -0x07, -0x02, +0x05, -0x03, -0x03, -0x01, -0x0A], + [-0x03, -0x04, -0x04, -0x06, -0x08, -0x02, -0x05, -0x06, -0x03, +0x02, +0x07, -0x04, +0x04, +0x01, -0x04, -0x04, -0x03, -0x03, -0x02, +0x02, -0x05, -0x03, -0x02, -0x0A], + [-0x02, +0x04, +0x01, +0x00, -0x07, +0x00, -0x01, -0x03, -0x01, -0x03, -0x04, +0x06, +0x01, -0x07, -0x02, -0x01, +0x00, -0x05, -0x06, -0x04, +0x00, +0x00, -0x01, -0x0A], + [-0x02, -0x01, -0x03, -0x04, -0x07, -0x01, -0x03, -0x04, -0x03, +0x02, +0x04, +0x01, +0x09, +0x00, -0x03, -0x02, -0x01, -0x06, -0x04, +0x02, -0x03, -0x02, -0x01, -0x0A], + [-0x05, -0x06, -0x05, -0x08, -0x06, -0x06, -0x07, -0x06, -0x03, +0x01, +0x01, -0x07, +0x00, +0x0A, -0x06, -0x04, -0x04, +0x00, +0x07, -0x02, -0x06, -0x07, -0x03, -0x0A], + [+0x01, -0x01, -0x01, -0x02, -0x04, +0x00, -0x01, -0x01, -0x01, -0x03, -0x04, -0x02, -0x03, -0x06, +0x08, +0x01, +0x00, -0x07, -0x07, -0x02, -0x02, -0x01, -0x01, -0x0A], + [+0x01, -0x01, +0x01, +0x00, +0x00, -0x01, -0x01, +0x01, -0x02, -0x02, -0x04, -0x01, -0x02, -0x04, +0x01, +0x03, +0x02, -0x03, -0x04, -0x02, +0x01, -0x01, +0x00, -0x0A], + [+0x02, -0x02, +0x00, -0x01, -0x03, -0x02, -0x01, -0x01, -0x02, +0x00, -0x03, +0x00, -0x01, -0x04, +0x00, +0x02, +0x04, -0x07, -0x04, +0x00, +0x00, -0x01, -0x01, -0x0A], + [-0x08, +0x02, -0x05, -0x09, -0x0A, -0x06, -0x09, -0x09, -0x04, -0x07, -0x03, -0x05, -0x06, +0x00, -0x07, -0x03, -0x07, +0x12, -0x01, -0x08, -0x07, -0x08, -0x06, -0x0A], + [-0x05, -0x06, -0x02, -0x06, +0x00, -0x06, -0x06, -0x07, +0x00, -0x02, -0x02, -0x06, -0x04, +0x07, -0x07, -0x04, -0x04, -0x01, +0x0B, -0x04, -0x04, -0x06, -0x03, -0x0A], + [+0x00, -0x04, -0x03, -0x03, -0x03, -0x03, -0x03, -0x02, -0x03, +0x05, +0x02, -0x04, +0x02, -0x02, -0x02, -0x02, +0x00, -0x08, -0x04, +0x06, -0x03, -0x03, -0x01, -0x0A], + [+0x00, -0x02, +0x03, +0x04, -0x06, +0x01, +0x03, +0x00, +0x01, -0x03, -0x05, +0x00, -0x03, -0x06, -0x02, +0x01, +0x00, -0x07, -0x04, -0x03, +0x04, +0x03, -0x01, -0x0A], + [+0x00, +0x00, +0x01, +0x03, -0x07, +0x05, +0x05, -0x01, +0x02, -0x03, -0x03, +0x00, -0x02, -0x07, -0x01, -0x01, -0x01, -0x08, -0x06, -0x03, +0x03, +0x05, -0x01, -0x0A], + [-0x01, -0x02, -0x01, -0x01, -0x04, -0x01, -0x01, -0x02, -0x01, -0x01, -0x02, -0x01, -0x01, -0x03, -0x01, +0x00, -0x01, -0x06, -0x03, -0x01, -0x01, -0x01, -0x01, -0x0A], + [-0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, +0x01]] + +PAM190 = [[+0x03, -0x02, +0x00, +0x00, -0x03, -0x01, +0x00, +0x01, -0x02, -0x01, -0x03, -0x02, -0x02, -0x05, +0x01, +0x01, +0x02, -0x07, -0x04, +0x00, +0x00, +0x00, +0x00, -0x09], + [-0x02, +0x08, -0x01, -0x02, -0x05, +0x01, -0x02, -0x04, +0x02, -0x03, -0x04, +0x04, -0x01, -0x06, +0x00, -0x01, -0x02, +0x02, -0x05, -0x03, -0x01, +0x00, -0x01, -0x09], + [+0x00, -0x01, +0x03, +0x03, -0x05, +0x01, +0x02, +0x00, +0x02, -0x02, -0x04, +0x01, -0x03, -0x04, -0x01, +0x01, +0x00, -0x05, -0x02, -0x03, +0x03, +0x01, -0x01, -0x09], + [+0x00, -0x02, +0x03, +0x05, -0x07, +0x02, +0x04, +0x00, +0x00, -0x03, -0x05, +0x00, -0x04, -0x07, -0x02, +0x00, -0x01, -0x08, -0x05, -0x03, +0x04, +0x03, -0x01, -0x09], + [-0x03, -0x05, -0x05, -0x07, +0x0D, -0x07, -0x07, -0x04, -0x04, -0x03, -0x08, -0x07, -0x07, -0x06, -0x04, +0x00, -0x03, -0x09, +0x00, -0x03, -0x06, -0x07, -0x04, -0x09], + [-0x01, +0x01, +0x01, +0x02, -0x07, +0x06, +0x03, -0x02, +0x03, -0x03, -0x02, +0x01, -0x01, -0x06, +0x00, -0x01, -0x01, -0x06, -0x05, -0x03, +0x01, +0x04, -0x01, -0x09], + [+0x00, -0x02, +0x02, +0x04, -0x07, +0x03, +0x05, +0x00, +0x00, -0x03, -0x04, -0x01, -0x03, -0x07, -0x01, +0x00, -0x01, -0x09, -0x05, -0x03, +0x03, +0x04, -0x01, -0x09], + [+0x01, -0x04, +0x00, +0x00, -0x04, -0x02, +0x00, +0x06, -0x03, -0x04, -0x05, -0x03, -0x04, -0x06, -0x01, +0x01, -0x01, -0x09, -0x07, -0x02, +0x00, -0x01, -0x01, -0x09], + [-0x02, +0x02, +0x02, +0x00, -0x04, +0x03, +0x00, -0x03, +0x08, -0x03, -0x03, -0x01, -0x03, -0x02, -0x01, -0x01, -0x02, -0x03, +0x00, -0x03, +0x01, +0x02, -0x01, -0x09], + [-0x01, -0x03, -0x02, -0x03, -0x03, -0x03, -0x03, -0x04, -0x03, +0x06, +0x02, -0x03, +0x02, +0x01, -0x03, -0x02, +0x00, -0x07, -0x02, +0x04, -0x03, -0x03, -0x01, -0x09], + [-0x03, -0x04, -0x04, -0x05, -0x08, -0x02, -0x04, -0x05, -0x03, +0x02, +0x07, -0x04, +0x04, +0x02, -0x03, -0x04, -0x02, -0x03, -0x02, +0x02, -0x05, -0x03, -0x02, -0x09], + [-0x02, +0x04, +0x01, +0x00, -0x07, +0x01, -0x01, -0x03, -0x01, -0x03, -0x04, +0x06, +0x01, -0x07, -0x02, +0x00, +0x00, -0x05, -0x06, -0x03, +0x00, +0x00, -0x01, -0x09], + [-0x02, -0x01, -0x03, -0x04, -0x07, -0x01, -0x03, -0x04, -0x03, +0x02, +0x04, +0x01, +0x09, +0x00, -0x03, -0x02, -0x01, -0x06, -0x04, +0x02, -0x03, -0x02, -0x01, -0x09], + [-0x05, -0x06, -0x04, -0x07, -0x06, -0x06, -0x07, -0x06, -0x02, +0x01, +0x02, -0x07, +0x00, +0x0A, -0x06, -0x04, -0x04, +0x00, +0x07, -0x02, -0x06, -0x07, -0x03, -0x09], + [+0x01, +0x00, -0x01, -0x02, -0x04, +0x00, -0x01, -0x01, -0x01, -0x03, -0x03, -0x02, -0x03, -0x06, +0x07, +0x01, +0x00, -0x07, -0x06, -0x02, -0x01, -0x01, -0x01, -0x09], + [+0x01, -0x01, +0x01, +0x00, +0x00, -0x01, +0x00, +0x01, -0x01, -0x02, -0x04, +0x00, -0x02, -0x04, +0x01, +0x03, +0x02, -0x03, -0x04, -0x02, +0x01, -0x01, +0x00, -0x09], + [+0x02, -0x02, +0x00, -0x01, -0x03, -0x01, -0x01, -0x01, -0x02, +0x00, -0x02, +0x00, -0x01, -0x04, +0x00, +0x02, +0x04, -0x06, -0x03, +0x00, +0x00, -0x01, +0x00, -0x09], + [-0x07, +0x02, -0x05, -0x08, -0x09, -0x06, -0x09, -0x09, -0x03, -0x07, -0x03, -0x05, -0x06, +0x00, -0x07, -0x03, -0x06, +0x12, -0x01, -0x08, -0x06, -0x07, -0x05, -0x09], + [-0x04, -0x05, -0x02, -0x05, +0x00, -0x05, -0x05, -0x07, +0x00, -0x02, -0x02, -0x06, -0x04, +0x07, -0x06, -0x04, -0x03, -0x01, +0x0B, -0x03, -0x04, -0x05, -0x03, -0x09], + [+0x00, -0x03, -0x03, -0x03, -0x03, -0x03, -0x03, -0x02, -0x03, +0x04, +0x02, -0x03, +0x02, -0x02, -0x02, -0x02, +0x00, -0x08, -0x03, +0x06, -0x03, -0x03, -0x01, -0x09], + [+0x00, -0x01, +0x03, +0x04, -0x06, +0x01, +0x03, +0x00, +0x01, -0x03, -0x05, +0x00, -0x03, -0x06, -0x01, +0x01, +0x00, -0x06, -0x04, -0x03, +0x04, +0x02, -0x01, -0x09], + [+0x00, +0x00, +0x01, +0x03, -0x07, +0x04, +0x04, -0x01, +0x02, -0x03, -0x03, +0x00, -0x02, -0x07, -0x01, -0x01, -0x01, -0x07, -0x05, -0x03, +0x02, +0x04, -0x01, -0x09], + [+0x00, -0x01, -0x01, -0x01, -0x04, -0x01, -0x01, -0x01, -0x01, -0x01, -0x02, -0x01, -0x01, -0x03, -0x01, +0x00, +0x00, -0x05, -0x03, -0x01, -0x01, -0x01, -0x01, -0x09], + [-0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, +0x01]] + +PAM200 = [[+0x03, -0x02, +0x00, +0x00, -0x03, -0x01, +0x00, +0x01, -0x02, -0x01, -0x02, -0x02, -0x02, -0x04, +0x01, +0x01, +0x01, -0x07, -0x04, +0x00, +0x00, +0x00, +0x00, -0x09], + [-0x02, +0x07, +0x00, -0x02, -0x04, +0x01, -0x02, -0x04, +0x02, -0x02, -0x04, +0x04, -0x01, -0x05, +0x00, -0x01, -0x01, +0x02, -0x05, -0x03, -0x01, +0x00, -0x01, -0x09], + [+0x00, +0x00, +0x03, +0x03, -0x05, +0x01, +0x02, +0x00, +0x02, -0x02, -0x04, +0x01, -0x02, -0x04, -0x01, +0x01, +0x00, -0x05, -0x02, -0x02, +0x03, +0x01, +0x00, -0x09], + [+0x00, -0x02, +0x03, +0x05, -0x06, +0x02, +0x04, +0x00, +0x00, -0x03, -0x05, +0x00, -0x04, -0x07, -0x02, +0x00, +0x00, -0x08, -0x05, -0x03, +0x04, +0x03, -0x01, -0x09], + [-0x03, -0x04, -0x05, -0x06, +0x0C, -0x07, -0x07, -0x04, -0x04, -0x03, -0x07, -0x07, -0x06, -0x06, -0x04, +0x00, -0x03, -0x09, +0x00, -0x02, -0x05, -0x07, -0x04, -0x09], + [-0x01, +0x01, +0x01, +0x02, -0x07, +0x05, +0x03, -0x02, +0x03, -0x03, -0x02, +0x01, -0x01, -0x06, +0x00, -0x01, -0x01, -0x06, -0x05, -0x03, +0x01, +0x04, -0x01, -0x09], + [+0x00, -0x02, +0x02, +0x04, -0x07, +0x03, +0x05, +0x00, +0x00, -0x03, -0x04, +0x00, -0x03, -0x07, -0x01, +0x00, -0x01, -0x09, -0x05, -0x02, +0x03, +0x04, -0x01, -0x09], + [+0x01, -0x04, +0x00, +0x00, -0x04, -0x02, +0x00, +0x06, -0x03, -0x03, -0x05, -0x02, -0x04, -0x06, -0x01, +0x01, +0x00, -0x08, -0x06, -0x02, +0x00, -0x01, -0x01, -0x09], + [-0x02, +0x02, +0x02, +0x00, -0x04, +0x03, +0x00, -0x03, +0x08, -0x03, -0x03, -0x01, -0x03, -0x02, -0x01, -0x01, -0x02, -0x03, +0x00, -0x03, +0x01, +0x02, -0x01, -0x09], + [-0x01, -0x02, -0x02, -0x03, -0x03, -0x03, -0x03, -0x03, -0x03, +0x06, +0x02, -0x02, +0x02, +0x01, -0x03, -0x02, +0x00, -0x06, -0x02, +0x04, -0x03, -0x03, -0x01, -0x09], + [-0x02, -0x04, -0x04, -0x05, -0x07, -0x02, -0x04, -0x05, -0x03, +0x02, +0x07, -0x04, +0x04, +0x02, -0x03, -0x04, -0x02, -0x02, -0x02, +0x02, -0x04, -0x03, -0x02, -0x09], + [-0x02, +0x04, +0x01, +0x00, -0x07, +0x01, +0x00, -0x02, -0x01, -0x02, -0x04, +0x06, +0x01, -0x07, -0x02, +0x00, +0x00, -0x04, -0x05, -0x03, +0x00, +0x00, -0x01, -0x09], + [-0x02, -0x01, -0x02, -0x04, -0x06, -0x01, -0x03, -0x04, -0x03, +0x02, +0x04, +0x01, +0x08, +0x00, -0x03, -0x02, -0x01, -0x05, -0x03, +0x02, -0x03, -0x02, -0x01, -0x09], + [-0x04, -0x05, -0x04, -0x07, -0x06, -0x06, -0x07, -0x06, -0x02, +0x01, +0x02, -0x07, +0x00, +0x0A, -0x06, -0x04, -0x04, +0x00, +0x07, -0x02, -0x06, -0x06, -0x03, -0x09], + [+0x01, +0x00, -0x01, -0x02, -0x04, +0x00, -0x01, -0x01, -0x01, -0x03, -0x03, -0x02, -0x03, -0x06, +0x07, +0x01, +0x00, -0x07, -0x06, -0x02, -0x01, -0x01, -0x01, -0x09], + [+0x01, -0x01, +0x01, +0x00, +0x00, -0x01, +0x00, +0x01, -0x01, -0x02, -0x04, +0x00, -0x02, -0x04, +0x01, +0x02, +0x02, -0x03, -0x03, -0x01, +0x01, -0x01, +0x00, -0x09], + [+0x01, -0x01, +0x00, +0x00, -0x03, -0x01, -0x01, +0x00, -0x02, +0x00, -0x02, +0x00, -0x01, -0x04, +0x00, +0x02, +0x04, -0x06, -0x03, +0x00, +0x00, -0x01, +0x00, -0x09], + [-0x07, +0x02, -0x05, -0x08, -0x09, -0x06, -0x09, -0x08, -0x03, -0x06, -0x02, -0x04, -0x05, +0x00, -0x07, -0x03, -0x06, +0x12, -0x01, -0x08, -0x06, -0x07, -0x05, -0x09], + [-0x04, -0x05, -0x02, -0x05, +0x00, -0x05, -0x05, -0x06, +0x00, -0x02, -0x02, -0x05, -0x03, +0x07, -0x06, -0x03, -0x03, -0x01, +0x0B, -0x03, -0x04, -0x05, -0x03, -0x09], + [+0x00, -0x03, -0x02, -0x03, -0x02, -0x03, -0x02, -0x02, -0x03, +0x04, +0x02, -0x03, +0x02, -0x02, -0x02, -0x01, +0x00, -0x08, -0x03, +0x05, -0x03, -0x02, -0x01, -0x09], + [+0x00, -0x01, +0x03, +0x04, -0x05, +0x01, +0x03, +0x00, +0x01, -0x03, -0x04, +0x00, -0x03, -0x06, -0x01, +0x01, +0x00, -0x06, -0x04, -0x03, +0x03, +0x02, -0x01, -0x09], + [+0x00, +0x00, +0x01, +0x03, -0x07, +0x04, +0x04, -0x01, +0x02, -0x03, -0x03, +0x00, -0x02, -0x06, -0x01, -0x01, -0x01, -0x07, -0x05, -0x02, +0x02, +0x04, -0x01, -0x09], + [+0x00, -0x01, +0x00, -0x01, -0x04, -0x01, -0x01, -0x01, -0x01, -0x01, -0x02, -0x01, -0x01, -0x03, -0x01, +0x00, +0x00, -0x05, -0x03, -0x01, -0x01, -0x01, -0x01, -0x09], + [-0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, +0x01]] + +PAM210 = [[+0x02, -0x02, +0x00, +0x00, -0x02, -0x01, +0x00, +0x01, -0x02, -0x01, -0x02, -0x02, -0x01, -0x04, +0x01, +0x01, +0x01, -0x07, -0x04, +0x00, +0x00, +0x00, +0x00, -0x09], + [-0x02, +0x07, +0x00, -0x02, -0x04, +0x01, -0x02, -0x03, +0x02, -0x02, -0x04, +0x04, -0x01, -0x05, +0x00, +0x00, -0x01, +0x02, -0x05, -0x03, -0x01, +0x00, -0x01, -0x09], + [+0x00, +0x00, +0x03, +0x02, -0x04, +0x01, +0x02, +0x00, +0x02, -0x02, -0x03, +0x01, -0x02, -0x04, -0x01, +0x01, +0x00, -0x05, -0x02, -0x02, +0x03, +0x01, +0x00, -0x09], + [+0x00, -0x02, +0x02, +0x05, -0x06, +0x02, +0x04, +0x00, +0x01, -0x03, -0x05, +0x00, -0x03, -0x07, -0x01, +0x00, +0x00, -0x08, -0x05, -0x03, +0x04, +0x03, -0x01, -0x09], + [-0x02, -0x04, -0x04, -0x06, +0x0C, -0x06, -0x06, -0x04, -0x04, -0x03, -0x07, -0x06, -0x06, -0x05, -0x03, +0x00, -0x03, -0x09, +0x00, -0x02, -0x05, -0x06, -0x04, -0x09], + [-0x01, +0x01, +0x01, +0x02, -0x06, +0x05, +0x03, -0x02, +0x03, -0x03, -0x02, +0x01, -0x01, -0x06, +0x00, -0x01, -0x01, -0x06, -0x05, -0x02, +0x01, +0x04, -0x01, -0x09], + [+0x00, -0x02, +0x02, +0x04, -0x06, +0x03, +0x05, +0x00, +0x00, -0x02, -0x04, +0x00, -0x03, -0x06, -0x01, +0x00, -0x01, -0x08, -0x05, -0x02, +0x03, +0x04, -0x01, -0x09], + [+0x01, -0x03, +0x00, +0x00, -0x04, -0x02, +0x00, +0x05, -0x03, -0x03, -0x05, -0x02, -0x03, -0x05, -0x01, +0x01, +0x00, -0x08, -0x06, -0x02, +0x00, -0x01, -0x01, -0x09], + [-0x02, +0x02, +0x02, +0x01, -0x04, +0x03, +0x00, -0x03, +0x08, -0x03, -0x02, +0x00, -0x03, -0x02, +0x00, -0x01, -0x02, -0x03, +0x00, -0x03, +0x01, +0x02, -0x01, -0x09], + [-0x01, -0x02, -0x02, -0x03, -0x03, -0x03, -0x02, -0x03, -0x03, +0x05, +0x02, -0x02, +0x02, +0x01, -0x03, -0x02, +0x00, -0x06, -0x01, +0x04, -0x03, -0x03, -0x01, -0x09], + [-0x02, -0x04, -0x03, -0x05, -0x07, -0x02, -0x04, -0x05, -0x02, +0x02, +0x07, -0x03, +0x04, +0x02, -0x03, -0x03, -0x02, -0x02, -0x01, +0x02, -0x04, -0x03, -0x02, -0x09], + [-0x02, +0x04, +0x01, +0x00, -0x06, +0x01, +0x00, -0x02, +0x00, -0x02, -0x03, +0x05, +0x01, -0x06, -0x02, +0x00, +0x00, -0x04, -0x05, -0x03, +0x00, +0x00, -0x01, -0x09], + [-0x01, -0x01, -0x02, -0x03, -0x06, -0x01, -0x03, -0x03, -0x03, +0x02, +0x04, +0x01, +0x08, +0x00, -0x03, -0x02, -0x01, -0x05, -0x03, +0x02, -0x03, -0x02, -0x01, -0x09], + [-0x04, -0x05, -0x04, -0x07, -0x05, -0x06, -0x06, -0x05, -0x02, +0x01, +0x02, -0x06, +0x00, +0x0A, -0x05, -0x04, -0x04, +0x00, +0x07, -0x02, -0x05, -0x06, -0x03, -0x09], + [+0x01, +0x00, -0x01, -0x01, -0x03, +0x00, -0x01, -0x01, +0x00, -0x03, -0x03, -0x02, -0x03, -0x05, +0x07, +0x01, +0x00, -0x07, -0x06, -0x02, -0x01, +0x00, -0x01, -0x09], + [+0x01, +0x00, +0x01, +0x00, +0x00, -0x01, +0x00, +0x01, -0x01, -0x02, -0x03, +0x00, -0x02, -0x04, +0x01, +0x02, +0x02, -0x03, -0x03, -0x01, +0x01, +0x00, +0x00, -0x09], + [+0x01, -0x01, +0x00, +0x00, -0x03, -0x01, -0x01, +0x00, -0x02, +0x00, -0x02, +0x00, -0x01, -0x04, +0x00, +0x02, +0x03, -0x06, -0x03, +0x00, +0x00, -0x01, +0x00, -0x09], + [-0x07, +0x02, -0x05, -0x08, -0x09, -0x06, -0x08, -0x08, -0x03, -0x06, -0x02, -0x04, -0x05, +0x00, -0x07, -0x03, -0x06, +0x12, -0x01, -0x07, -0x06, -0x07, -0x05, -0x09], + [-0x04, -0x05, -0x02, -0x05, +0x00, -0x05, -0x05, -0x06, +0x00, -0x01, -0x01, -0x05, -0x03, +0x07, -0x06, -0x03, -0x03, -0x01, +0x0B, -0x03, -0x04, -0x05, -0x03, -0x09], + [+0x00, -0x03, -0x02, -0x03, -0x02, -0x02, -0x02, -0x02, -0x03, +0x04, +0x02, -0x03, +0x02, -0x02, -0x02, -0x01, +0x00, -0x07, -0x03, +0x05, -0x02, -0x02, -0x01, -0x09], + [+0x00, -0x01, +0x03, +0x04, -0x05, +0x01, +0x03, +0x00, +0x01, -0x03, -0x04, +0x00, -0x03, -0x05, -0x01, +0x01, +0x00, -0x06, -0x04, -0x02, +0x03, +0x02, -0x01, -0x09], + [+0x00, +0x00, +0x01, +0x03, -0x06, +0x04, +0x04, -0x01, +0x02, -0x03, -0x03, +0x00, -0x02, -0x06, +0x00, +0x00, -0x01, -0x07, -0x05, -0x02, +0x02, +0x04, -0x01, -0x09], + [+0x00, -0x01, +0x00, -0x01, -0x04, -0x01, -0x01, -0x01, -0x01, -0x01, -0x02, -0x01, -0x01, -0x03, -0x01, +0x00, +0x00, -0x05, -0x03, -0x01, -0x01, -0x01, -0x01, -0x09], + [-0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, +0x01]] + +PAM220 = [[+0x02, -0x02, +0x00, +0x00, -0x02, -0x01, +0x00, +0x01, -0x02, -0x01, -0x02, -0x01, -0x01, -0x04, +0x01, +0x01, +0x01, -0x06, -0x04, +0x00, +0x00, +0x00, +0x00, -0x08], + [-0x02, +0x07, +0x00, -0x02, -0x04, +0x01, -0x01, -0x03, +0x02, -0x02, -0x03, +0x04, -0x01, -0x05, +0x00, +0x00, -0x01, +0x02, -0x05, -0x03, -0x01, +0x00, -0x01, -0x08], + [+0x00, +0x00, +0x03, +0x02, -0x04, +0x01, +0x02, +0x00, +0x02, -0x02, -0x03, +0x01, -0x02, -0x04, -0x01, +0x01, +0x00, -0x04, -0x02, -0x02, +0x02, +0x01, +0x00, -0x08], + [+0x00, -0x02, +0x02, +0x04, -0x06, +0x02, +0x04, +0x00, +0x01, -0x03, -0x05, +0x00, -0x03, -0x06, -0x01, +0x00, +0x00, -0x08, -0x05, -0x03, +0x04, +0x03, -0x01, -0x08], + [-0x02, -0x04, -0x04, -0x06, +0x0C, -0x06, -0x06, -0x04, -0x04, -0x03, -0x07, -0x06, -0x06, -0x05, -0x03, +0x00, -0x03, -0x08, +0x00, -0x02, -0x05, -0x06, -0x03, -0x08], + [-0x01, +0x01, +0x01, +0x02, -0x06, +0x05, +0x03, -0x02, +0x03, -0x02, -0x02, +0x01, -0x01, -0x05, +0x00, -0x01, -0x01, -0x05, -0x05, -0x02, +0x01, +0x04, -0x01, -0x08], + [+0x00, -0x01, +0x02, +0x04, -0x06, +0x03, +0x04, +0x00, +0x01, -0x02, -0x04, +0x00, -0x02, -0x06, -0x01, +0x00, -0x01, -0x08, -0x05, -0x02, +0x03, +0x04, -0x01, -0x08], + [+0x01, -0x03, +0x00, +0x00, -0x04, -0x02, +0x00, +0x05, -0x03, -0x03, -0x05, -0x02, -0x03, -0x05, -0x01, +0x01, +0x00, -0x08, -0x06, -0x02, +0x00, -0x01, -0x01, -0x08], + [-0x02, +0x02, +0x02, +0x01, -0x04, +0x03, +0x01, -0x03, +0x07, -0x03, -0x02, +0x00, -0x03, -0x02, +0x00, -0x01, -0x02, -0x03, +0x00, -0x03, +0x01, +0x02, -0x01, -0x08], + [-0x01, -0x02, -0x02, -0x03, -0x03, -0x02, -0x02, -0x03, -0x03, +0x05, +0x02, -0x02, +0x02, +0x01, -0x02, -0x02, +0x00, -0x06, -0x01, +0x04, -0x02, -0x02, -0x01, -0x08], + [-0x02, -0x03, -0x03, -0x05, -0x07, -0x02, -0x04, -0x05, -0x02, +0x02, +0x06, -0x03, +0x04, +0x02, -0x03, -0x03, -0x02, -0x02, -0x01, +0x02, -0x04, -0x03, -0x02, -0x08], + [-0x01, +0x04, +0x01, +0x00, -0x06, +0x01, +0x00, -0x02, +0x00, -0x02, -0x03, +0x05, +0x01, -0x06, -0x01, +0x00, +0x00, -0x04, -0x05, -0x03, +0x00, +0x00, -0x01, -0x08], + [-0x01, -0x01, -0x02, -0x03, -0x06, -0x01, -0x02, -0x03, -0x03, +0x02, +0x04, +0x01, +0x08, +0x00, -0x02, -0x02, -0x01, -0x05, -0x03, +0x02, -0x03, -0x02, -0x01, -0x08], + [-0x04, -0x05, -0x04, -0x06, -0x05, -0x05, -0x06, -0x05, -0x02, +0x01, +0x02, -0x06, +0x00, +0x0A, -0x05, -0x04, -0x04, +0x00, +0x07, -0x02, -0x05, -0x06, -0x03, -0x08], + [+0x01, +0x00, -0x01, -0x01, -0x03, +0x00, -0x01, -0x01, +0x00, -0x02, -0x03, -0x01, -0x02, -0x05, +0x07, +0x01, +0x00, -0x06, -0x06, -0x01, -0x01, +0x00, -0x01, -0x08], + [+0x01, +0x00, +0x01, +0x00, +0x00, -0x01, +0x00, +0x01, -0x01, -0x02, -0x03, +0x00, -0x02, -0x04, +0x01, +0x02, +0x02, -0x03, -0x03, -0x01, +0x00, +0x00, +0x00, -0x08], + [+0x01, -0x01, +0x00, +0x00, -0x03, -0x01, -0x01, +0x00, -0x02, +0x00, -0x02, +0x00, -0x01, -0x04, +0x00, +0x02, +0x03, -0x06, -0x03, +0x00, +0x00, -0x01, +0x00, -0x08], + [-0x06, +0x02, -0x04, -0x08, -0x08, -0x05, -0x08, -0x08, -0x03, -0x06, -0x02, -0x04, -0x05, +0x00, -0x06, -0x03, -0x06, +0x11, +0x00, -0x07, -0x06, -0x07, -0x05, -0x08], + [-0x04, -0x05, -0x02, -0x05, +0x00, -0x05, -0x05, -0x06, +0x00, -0x01, -0x01, -0x05, -0x03, +0x07, -0x06, -0x03, -0x03, +0x00, +0x0B, -0x03, -0x03, -0x05, -0x03, -0x08], + [+0x00, -0x03, -0x02, -0x03, -0x02, -0x02, -0x02, -0x02, -0x03, +0x04, +0x02, -0x03, +0x02, -0x02, -0x01, -0x01, +0x00, -0x07, -0x03, +0x05, -0x02, -0x02, -0x01, -0x08], + [+0x00, -0x01, +0x02, +0x04, -0x05, +0x01, +0x03, +0x00, +0x01, -0x02, -0x04, +0x00, -0x03, -0x05, -0x01, +0x00, +0x00, -0x06, -0x03, -0x02, +0x03, +0x02, -0x01, -0x08], + [+0x00, +0x00, +0x01, +0x03, -0x06, +0x04, +0x04, -0x01, +0x02, -0x02, -0x03, +0x00, -0x02, -0x06, +0x00, +0x00, -0x01, -0x07, -0x05, -0x02, +0x02, +0x04, -0x01, -0x08], + [+0x00, -0x01, +0x00, -0x01, -0x03, -0x01, -0x01, -0x01, -0x01, -0x01, -0x02, -0x01, -0x01, -0x03, -0x01, +0x00, +0x00, -0x05, -0x03, -0x01, -0x01, -0x01, -0x01, -0x08], + [-0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, +0x01]] + +PAM230 = [[+0x02, -0x02, +0x00, +0x00, -0x02, -0x01, +0x00, +0x01, -0x02, -0x01, -0x02, -0x01, -0x01, -0x04, +0x01, +0x01, +0x01, -0x06, -0x04, +0x00, +0x00, +0x00, +0x00, -0x08], + [-0x02, +0x07, +0x00, -0x02, -0x04, +0x01, -0x01, -0x03, +0x02, -0x02, -0x03, +0x04, -0x01, -0x05, +0x00, +0x00, -0x01, +0x02, -0x05, -0x03, -0x01, +0x00, -0x01, -0x08], + [+0x00, +0x00, +0x02, +0x02, -0x04, +0x01, +0x01, +0x00, +0x02, -0x02, -0x03, +0x01, -0x02, -0x04, -0x01, +0x01, +0x00, -0x04, -0x02, -0x02, +0x02, +0x01, +0x00, -0x08], + [+0x00, -0x02, +0x02, +0x04, -0x06, +0x02, +0x04, +0x01, +0x01, -0x03, -0x04, +0x00, -0x03, -0x06, -0x01, +0x00, +0x00, -0x07, -0x05, -0x02, +0x03, +0x03, -0x01, -0x08], + [-0x02, -0x04, -0x04, -0x06, +0x0C, -0x06, -0x06, -0x04, -0x04, -0x02, -0x07, -0x06, -0x06, -0x05, -0x03, +0x00, -0x02, -0x08, +0x00, -0x02, -0x05, -0x06, -0x03, -0x08], + [-0x01, +0x01, +0x01, +0x02, -0x06, +0x05, +0x03, -0x01, +0x03, -0x02, -0x02, +0x01, -0x01, -0x05, +0x00, -0x01, -0x01, -0x05, -0x04, -0x02, +0x01, +0x04, -0x01, -0x08], + [+0x00, -0x01, +0x01, +0x04, -0x06, +0x03, +0x04, +0x00, +0x01, -0x02, -0x04, +0x00, -0x02, -0x06, -0x01, +0x00, -0x01, -0x08, -0x05, -0x02, +0x03, +0x04, -0x01, -0x08], + [+0x01, -0x03, +0x00, +0x01, -0x04, -0x01, +0x00, +0x05, -0x02, -0x03, -0x04, -0x02, -0x03, -0x05, -0x01, +0x01, +0x00, -0x07, -0x06, -0x02, +0x00, -0x01, -0x01, -0x08], + [-0x02, +0x02, +0x02, +0x01, -0x04, +0x03, +0x01, -0x02, +0x07, -0x03, -0x02, +0x00, -0x02, -0x02, +0x00, -0x01, -0x02, -0x03, +0x00, -0x02, +0x01, +0x02, -0x01, -0x08], + [-0x01, -0x02, -0x02, -0x03, -0x02, -0x02, -0x02, -0x03, -0x03, +0x05, +0x02, -0x02, +0x02, +0x01, -0x02, -0x02, +0x00, -0x06, -0x01, +0x04, -0x02, -0x02, -0x01, -0x08], + [-0x02, -0x03, -0x03, -0x04, -0x07, -0x02, -0x04, -0x04, -0x02, +0x02, +0x06, -0x03, +0x04, +0x02, -0x03, -0x03, -0x02, -0x02, -0x01, +0x02, -0x04, -0x03, -0x02, -0x08], + [-0x01, +0x04, +0x01, +0x00, -0x06, +0x01, +0x00, -0x02, +0x00, -0x02, -0x03, +0x05, +0x00, -0x06, -0x01, +0x00, +0x00, -0x04, -0x05, -0x03, +0x01, +0x00, -0x01, -0x08], + [-0x01, -0x01, -0x02, -0x03, -0x06, -0x01, -0x02, -0x03, -0x02, +0x02, +0x04, +0x00, +0x07, +0x00, -0x02, -0x02, -0x01, -0x05, -0x03, +0x02, -0x02, -0x02, -0x01, -0x08], + [-0x04, -0x05, -0x04, -0x06, -0x05, -0x05, -0x06, -0x05, -0x02, +0x01, +0x02, -0x06, +0x00, +0x09, -0x05, -0x03, -0x03, +0x00, +0x07, -0x01, -0x05, -0x06, -0x03, -0x08], + [+0x01, +0x00, -0x01, -0x01, -0x03, +0x00, -0x01, -0x01, +0x00, -0x02, -0x03, -0x01, -0x02, -0x05, +0x06, +0x01, +0x00, -0x06, -0x05, -0x01, -0x01, +0x00, -0x01, -0x08], + [+0x01, +0x00, +0x01, +0x00, +0x00, -0x01, +0x00, +0x01, -0x01, -0x02, -0x03, +0x00, -0x02, -0x03, +0x01, +0x02, +0x02, -0x03, -0x03, -0x01, +0x00, +0x00, +0x00, -0x08], + [+0x01, -0x01, +0x00, +0x00, -0x02, -0x01, -0x01, +0x00, -0x02, +0x00, -0x02, +0x00, -0x01, -0x03, +0x00, +0x02, +0x03, -0x06, -0x03, +0x00, +0x00, -0x01, +0x00, -0x08], + [-0x06, +0x02, -0x04, -0x07, -0x08, -0x05, -0x08, -0x07, -0x03, -0x06, -0x02, -0x04, -0x05, +0x00, -0x06, -0x03, -0x06, +0x11, +0x00, -0x07, -0x06, -0x06, -0x04, -0x08], + [-0x04, -0x05, -0x02, -0x05, +0x00, -0x04, -0x05, -0x06, +0x00, -0x01, -0x01, -0x05, -0x03, +0x07, -0x05, -0x03, -0x03, +0x00, +0x0A, -0x03, -0x03, -0x05, -0x03, -0x08], + [+0x00, -0x03, -0x02, -0x02, -0x02, -0x02, -0x02, -0x02, -0x02, +0x04, +0x02, -0x03, +0x02, -0x01, -0x01, -0x01, +0x00, -0x07, -0x03, +0x05, -0x02, -0x02, -0x01, -0x08], + [+0x00, -0x01, +0x02, +0x03, -0x05, +0x01, +0x03, +0x00, +0x01, -0x02, -0x04, +0x01, -0x02, -0x05, -0x01, +0x00, +0x00, -0x06, -0x03, -0x02, +0x03, +0x02, -0x01, -0x08], + [+0x00, +0x00, +0x01, +0x03, -0x06, +0x04, +0x04, -0x01, +0x02, -0x02, -0x03, +0x00, -0x02, -0x06, +0x00, +0x00, -0x01, -0x06, -0x05, -0x02, +0x02, +0x04, -0x01, -0x08], + [+0x00, -0x01, +0x00, -0x01, -0x03, -0x01, -0x01, -0x01, -0x01, -0x01, -0x02, -0x01, -0x01, -0x03, -0x01, +0x00, +0x00, -0x04, -0x03, -0x01, -0x01, -0x01, -0x01, -0x08], + [-0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, +0x01]] + +PAM240 = [[+0x02, -0x02, +0x00, +0x00, -0x02, +0x00, +0x00, +0x01, -0x01, -0x01, -0x02, -0x01, -0x01, -0x04, +0x01, +0x01, +0x01, -0x06, -0x04, +0x00, +0x00, +0x00, +0x00, -0x08], + [-0x02, +0x06, +0x00, -0x01, -0x04, +0x01, -0x01, -0x03, +0x02, -0x02, -0x03, +0x03, +0x00, -0x05, +0x00, +0x00, -0x01, +0x02, -0x04, -0x03, -0x01, +0x00, -0x01, -0x08], + [+0x00, +0x00, +0x02, +0x02, -0x04, +0x01, +0x01, +0x00, +0x02, -0x02, -0x03, +0x01, -0x02, -0x04, -0x01, +0x01, +0x00, -0x04, -0x02, -0x02, +0x02, +0x01, +0x00, -0x08], + [+0x00, -0x01, +0x02, +0x04, -0x05, +0x02, +0x04, +0x01, +0x01, -0x02, -0x04, +0x00, -0x03, -0x06, -0x01, +0x00, +0x00, -0x07, -0x04, -0x02, +0x03, +0x03, -0x01, -0x08], + [-0x02, -0x04, -0x04, -0x05, +0x0C, -0x06, -0x06, -0x04, -0x04, -0x02, -0x06, -0x06, -0x05, -0x05, -0x03, +0x00, -0x02, -0x08, +0x00, -0x02, -0x05, -0x06, -0x03, -0x08], + [+0x00, +0x01, +0x01, +0x02, -0x06, +0x04, +0x03, -0x01, +0x03, -0x02, -0x02, +0x01, -0x01, -0x05, +0x00, -0x01, -0x01, -0x05, -0x04, -0x02, +0x01, +0x03, -0x01, -0x08], + [+0x00, -0x01, +0x01, +0x04, -0x06, +0x03, +0x04, +0x00, +0x01, -0x02, -0x03, +0x00, -0x02, -0x06, -0x01, +0x00, +0x00, -0x07, -0x04, -0x02, +0x03, +0x03, -0x01, -0x08], + [+0x01, -0x03, +0x00, +0x01, -0x04, -0x01, +0x00, +0x05, -0x02, -0x03, -0x04, -0x02, -0x03, -0x05, -0x01, +0x01, +0x00, -0x07, -0x05, -0x01, +0x00, +0x00, -0x01, -0x08], + [-0x01, +0x02, +0x02, +0x01, -0x04, +0x03, +0x01, -0x02, +0x07, -0x03, -0x02, +0x00, -0x02, -0x02, +0x00, -0x01, -0x01, -0x03, +0x00, -0x02, +0x01, +0x02, -0x01, -0x08], + [-0x01, -0x02, -0x02, -0x02, -0x02, -0x02, -0x02, -0x03, -0x03, +0x05, +0x02, -0x02, +0x02, +0x01, -0x02, -0x01, +0x00, -0x05, -0x01, +0x04, -0x02, -0x02, -0x01, -0x08], + [-0x02, -0x03, -0x03, -0x04, -0x06, -0x02, -0x03, -0x04, -0x02, +0x02, +0x06, -0x03, +0x04, +0x02, -0x03, -0x03, -0x02, -0x02, -0x01, +0x02, -0x04, -0x03, -0x01, -0x08], + [-0x01, +0x03, +0x01, +0x00, -0x06, +0x01, +0x00, -0x02, +0x00, -0x02, -0x03, +0x05, +0x00, -0x05, -0x01, +0x00, +0x00, -0x04, -0x05, -0x03, +0x01, +0x00, -0x01, -0x08], + [-0x01, +0x00, -0x02, -0x03, -0x05, -0x01, -0x02, -0x03, -0x02, +0x02, +0x04, +0x00, +0x07, +0x00, -0x02, -0x02, -0x01, -0x04, -0x03, +0x02, -0x02, -0x02, -0x01, -0x08], + [-0x04, -0x05, -0x04, -0x06, -0x05, -0x05, -0x06, -0x05, -0x02, +0x01, +0x02, -0x05, +0x00, +0x09, -0x05, -0x03, -0x03, +0x00, +0x07, -0x01, -0x05, -0x05, -0x02, -0x08], + [+0x01, +0x00, -0x01, -0x01, -0x03, +0x00, -0x01, -0x01, +0x00, -0x02, -0x03, -0x01, -0x02, -0x05, +0x06, +0x01, +0x00, -0x06, -0x05, -0x01, -0x01, +0x00, -0x01, -0x08], + [+0x01, +0x00, +0x01, +0x00, +0x00, -0x01, +0x00, +0x01, -0x01, -0x01, -0x03, +0x00, -0x02, -0x03, +0x01, +0x02, +0x01, -0x03, -0x03, -0x01, +0x00, +0x00, +0x00, -0x08], + [+0x01, -0x01, +0x00, +0x00, -0x02, -0x01, +0x00, +0x00, -0x01, +0x00, -0x02, +0x00, -0x01, -0x03, +0x00, +0x01, +0x03, -0x05, -0x03, +0x00, +0x00, -0x01, +0x00, -0x08], + [-0x06, +0x02, -0x04, -0x07, -0x08, -0x05, -0x07, -0x07, -0x03, -0x05, -0x02, -0x04, -0x04, +0x00, -0x06, -0x03, -0x05, +0x11, +0x00, -0x06, -0x05, -0x06, -0x04, -0x08], + [-0x04, -0x04, -0x02, -0x04, +0x00, -0x04, -0x04, -0x05, +0x00, -0x01, -0x01, -0x05, -0x03, +0x07, -0x05, -0x03, -0x03, +0x00, +0x0A, -0x03, -0x03, -0x04, -0x02, -0x08], + [+0x00, -0x03, -0x02, -0x02, -0x02, -0x02, -0x02, -0x01, -0x02, +0x04, +0x02, -0x03, +0x02, -0x01, -0x01, -0x01, +0x00, -0x06, -0x03, +0x04, -0x02, -0x02, -0x01, -0x08], + [+0x00, -0x01, +0x02, +0x03, -0x05, +0x01, +0x03, +0x00, +0x01, -0x02, -0x04, +0x01, -0x02, -0x05, -0x01, +0x00, +0x00, -0x05, -0x03, -0x02, +0x03, +0x02, -0x01, -0x08], + [+0x00, +0x00, +0x01, +0x03, -0x06, +0x03, +0x03, +0x00, +0x02, -0x02, -0x03, +0x00, -0x02, -0x05, +0x00, +0x00, -0x01, -0x06, -0x04, -0x02, +0x02, +0x03, -0x01, -0x08], + [+0x00, -0x01, +0x00, -0x01, -0x03, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x02, -0x01, +0x00, +0x00, -0x04, -0x02, -0x01, -0x01, -0x01, -0x01, -0x08], + [-0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, +0x01]] + +PAM250 = [[+0x02, -0x02, +0x00, +0x00, -0x02, +0x00, +0x00, +0x01, -0x01, -0x01, -0x02, -0x01, -0x01, -0x03, +0x01, +0x01, +0x01, -0x06, -0x03, +0x00, +0x00, +0x00, +0x00, -0x08], + [-0x02, +0x06, +0x00, -0x01, -0x04, +0x01, -0x01, -0x03, +0x02, -0x02, -0x03, +0x03, +0x00, -0x04, +0x00, +0x00, -0x01, +0x02, -0x04, -0x02, -0x01, +0x00, -0x01, -0x08], + [+0x00, +0x00, +0x02, +0x02, -0x04, +0x01, +0x01, +0x00, +0x02, -0x02, -0x03, +0x01, -0x02, -0x03, +0x00, +0x01, +0x00, -0x04, -0x02, -0x02, +0x02, +0x01, +0x00, -0x08], + [+0x00, -0x01, +0x02, +0x04, -0x05, +0x02, +0x03, +0x01, +0x01, -0x02, -0x04, +0x00, -0x03, -0x06, -0x01, +0x00, +0x00, -0x07, -0x04, -0x02, +0x03, +0x03, -0x01, -0x08], + [-0x02, -0x04, -0x04, -0x05, +0x0C, -0x05, -0x05, -0x03, -0x03, -0x02, -0x06, -0x05, -0x05, -0x04, -0x03, +0x00, -0x02, -0x08, +0x00, -0x02, -0x04, -0x05, -0x03, -0x08], + [+0x00, +0x01, +0x01, +0x02, -0x05, +0x04, +0x02, -0x01, +0x03, -0x02, -0x02, +0x01, -0x01, -0x05, +0x00, -0x01, -0x01, -0x05, -0x04, -0x02, +0x01, +0x03, -0x01, -0x08], + [+0x00, -0x01, +0x01, +0x03, -0x05, +0x02, +0x04, +0x00, +0x01, -0x02, -0x03, +0x00, -0x02, -0x05, -0x01, +0x00, +0x00, -0x07, -0x04, -0x02, +0x03, +0x03, -0x01, -0x08], + [+0x01, -0x03, +0x00, +0x01, -0x03, -0x01, +0x00, +0x05, -0x02, -0x03, -0x04, -0x02, -0x03, -0x05, +0x00, +0x01, +0x00, -0x07, -0x05, -0x01, +0x00, +0x00, -0x01, -0x08], + [-0x01, +0x02, +0x02, +0x01, -0x03, +0x03, +0x01, -0x02, +0x06, -0x02, -0x02, +0x00, -0x02, -0x02, +0x00, -0x01, -0x01, -0x03, +0x00, -0x02, +0x01, +0x02, -0x01, -0x08], + [-0x01, -0x02, -0x02, -0x02, -0x02, -0x02, -0x02, -0x03, -0x02, +0x05, +0x02, -0x02, +0x02, +0x01, -0x02, -0x01, +0x00, -0x05, -0x01, +0x04, -0x02, -0x02, -0x01, -0x08], + [-0x02, -0x03, -0x03, -0x04, -0x06, -0x02, -0x03, -0x04, -0x02, +0x02, +0x06, -0x03, +0x04, +0x02, -0x03, -0x03, -0x02, -0x02, -0x01, +0x02, -0x03, -0x03, -0x01, -0x08], + [-0x01, +0x03, +0x01, +0x00, -0x05, +0x01, +0x00, -0x02, +0x00, -0x02, -0x03, +0x05, +0x00, -0x05, -0x01, +0x00, +0x00, -0x03, -0x04, -0x02, +0x01, +0x00, -0x01, -0x08], + [-0x01, +0x00, -0x02, -0x03, -0x05, -0x01, -0x02, -0x03, -0x02, +0x02, +0x04, +0x00, +0x06, +0x00, -0x02, -0x02, -0x01, -0x04, -0x02, +0x02, -0x02, -0x02, -0x01, -0x08], + [-0x03, -0x04, -0x03, -0x06, -0x04, -0x05, -0x05, -0x05, -0x02, +0x01, +0x02, -0x05, +0x00, +0x09, -0x05, -0x03, -0x03, +0x00, +0x07, -0x01, -0x04, -0x05, -0x02, -0x08], + [+0x01, +0x00, +0x00, -0x01, -0x03, +0x00, -0x01, +0x00, +0x00, -0x02, -0x03, -0x01, -0x02, -0x05, +0x06, +0x01, +0x00, -0x06, -0x05, -0x01, -0x01, +0x00, -0x01, -0x08], + [+0x01, +0x00, +0x01, +0x00, +0x00, -0x01, +0x00, +0x01, -0x01, -0x01, -0x03, +0x00, -0x02, -0x03, +0x01, +0x02, +0x01, -0x02, -0x03, -0x01, +0x00, +0x00, +0x00, -0x08], + [+0x01, -0x01, +0x00, +0x00, -0x02, -0x01, +0x00, +0x00, -0x01, +0x00, -0x02, +0x00, -0x01, -0x03, +0x00, +0x01, +0x03, -0x05, -0x03, +0x00, +0x00, -0x01, +0x00, -0x08], + [-0x06, +0x02, -0x04, -0x07, -0x08, -0x05, -0x07, -0x07, -0x03, -0x05, -0x02, -0x03, -0x04, +0x00, -0x06, -0x02, -0x05, +0x11, +0x00, -0x06, -0x05, -0x06, -0x04, -0x08], + [-0x03, -0x04, -0x02, -0x04, +0x00, -0x04, -0x04, -0x05, +0x00, -0x01, -0x01, -0x04, -0x02, +0x07, -0x05, -0x03, -0x03, +0x00, +0x0A, -0x02, -0x03, -0x04, -0x02, -0x08], + [+0x00, -0x02, -0x02, -0x02, -0x02, -0x02, -0x02, -0x01, -0x02, +0x04, +0x02, -0x02, +0x02, -0x01, -0x01, -0x01, +0x00, -0x06, -0x02, +0x04, -0x02, -0x02, -0x01, -0x08], + [+0x00, -0x01, +0x02, +0x03, -0x04, +0x01, +0x03, +0x00, +0x01, -0x02, -0x03, +0x01, -0x02, -0x04, -0x01, +0x00, +0x00, -0x05, -0x03, -0x02, +0x03, +0x02, -0x01, -0x08], + [+0x00, +0x00, +0x01, +0x03, -0x05, +0x03, +0x03, +0x00, +0x02, -0x02, -0x03, +0x00, -0x02, -0x05, +0x00, +0x00, -0x01, -0x06, -0x04, -0x02, +0x02, +0x03, -0x01, -0x08], + [+0x00, -0x01, +0x00, -0x01, -0x03, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x02, -0x01, +0x00, +0x00, -0x04, -0x02, -0x01, -0x01, -0x01, -0x01, -0x08], + [-0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, +0x01]] + +PAM260 = [[+0x02, -0x01, +0x00, +0x00, -0x02, +0x00, +0x00, +0x01, -0x01, +0x00, -0x02, -0x01, -0x01, -0x03, +0x01, +0x01, +0x01, -0x06, -0x03, +0x00, +0x00, +0x00, +0x00, -0x07], + [-0x01, +0x06, +0x00, -0x01, -0x04, +0x01, -0x01, -0x02, +0x02, -0x02, -0x03, +0x03, +0x00, -0x04, +0x00, +0x00, -0x01, +0x02, -0x04, -0x02, -0x01, +0x00, -0x01, -0x07], + [+0x00, +0x00, +0x02, +0x02, -0x03, +0x01, +0x01, +0x00, +0x02, -0x02, -0x03, +0x01, -0x02, -0x03, +0x00, +0x01, +0x00, -0x04, -0x02, -0x02, +0x02, +0x01, +0x00, -0x07], + [+0x00, -0x01, +0x02, +0x04, -0x05, +0x02, +0x03, +0x01, +0x01, -0x02, -0x04, +0x00, -0x02, -0x05, -0x01, +0x00, +0x00, -0x06, -0x04, -0x02, +0x03, +0x03, -0x01, -0x07], + [-0x02, -0x04, -0x03, -0x05, +0x0C, -0x05, -0x05, -0x03, -0x03, -0x02, -0x06, -0x05, -0x05, -0x04, -0x03, +0x00, -0x02, -0x07, +0x00, -0x02, -0x04, -0x05, -0x03, -0x07], + [+0x00, +0x01, +0x01, +0x02, -0x05, +0x04, +0x02, -0x01, +0x03, -0x02, -0x02, +0x01, -0x01, -0x04, +0x00, +0x00, -0x01, -0x05, -0x04, -0x02, +0x01, +0x03, +0x00, -0x07], + [+0x00, -0x01, +0x01, +0x03, -0x05, +0x02, +0x04, +0x00, +0x01, -0x02, -0x03, +0x00, -0x02, -0x05, +0x00, +0x00, +0x00, -0x07, -0x04, -0x02, +0x03, +0x03, -0x01, -0x07], + [+0x01, -0x02, +0x00, +0x01, -0x03, -0x01, +0x00, +0x05, -0x02, -0x02, -0x04, -0x02, -0x03, -0x05, +0x00, +0x01, +0x00, -0x07, -0x05, -0x01, +0x01, +0x00, -0x01, -0x07], + [-0x01, +0x02, +0x02, +0x01, -0x03, +0x03, +0x01, -0x02, +0x06, -0x02, -0x02, +0x00, -0x02, -0x02, +0x00, -0x01, -0x01, -0x03, +0x00, -0x02, +0x01, +0x02, -0x01, -0x07], + [+0x00, -0x02, -0x02, -0x02, -0x02, -0x02, -0x02, -0x02, -0x02, +0x04, +0x02, -0x02, +0x02, +0x01, -0x02, -0x01, +0x00, -0x05, -0x01, +0x04, -0x02, -0x02, -0x01, -0x07], + [-0x02, -0x03, -0x03, -0x04, -0x06, -0x02, -0x03, -0x04, -0x02, +0x02, +0x06, -0x03, +0x04, +0x02, -0x02, -0x03, -0x02, -0x02, -0x01, +0x02, -0x03, -0x02, -0x01, -0x07], + [-0x01, +0x03, +0x01, +0x00, -0x05, +0x01, +0x00, -0x02, +0x00, -0x02, -0x03, +0x04, +0x00, -0x05, -0x01, +0x00, +0x00, -0x03, -0x04, -0x02, +0x01, +0x00, -0x01, -0x07], + [-0x01, +0x00, -0x02, -0x02, -0x05, -0x01, -0x02, -0x03, -0x02, +0x02, +0x04, +0x00, +0x06, +0x00, -0x02, -0x01, -0x01, -0x04, -0x02, +0x02, -0x02, -0x02, -0x01, -0x07], + [-0x03, -0x04, -0x03, -0x05, -0x04, -0x04, -0x05, -0x05, -0x02, +0x01, +0x02, -0x05, +0x00, +0x09, -0x04, -0x03, -0x03, +0x00, +0x07, -0x01, -0x04, -0x05, -0x02, -0x07], + [+0x01, +0x00, +0x00, -0x01, -0x03, +0x00, +0x00, +0x00, +0x00, -0x02, -0x02, -0x01, -0x02, -0x04, +0x06, +0x01, +0x00, -0x05, -0x05, -0x01, -0x01, +0x00, -0x01, -0x07], + [+0x01, +0x00, +0x01, +0x00, +0x00, +0x00, +0x00, +0x01, -0x01, -0x01, -0x03, +0x00, -0x01, -0x03, +0x01, +0x01, +0x01, -0x02, -0x03, -0x01, +0x00, +0x00, +0x00, -0x07], + [+0x01, -0x01, +0x00, +0x00, -0x02, -0x01, +0x00, +0x00, -0x01, +0x00, -0x02, +0x00, -0x01, -0x03, +0x00, +0x01, +0x02, -0x05, -0x03, +0x00, +0x00, +0x00, +0x00, -0x07], + [-0x06, +0x02, -0x04, -0x06, -0x07, -0x05, -0x07, -0x07, -0x03, -0x05, -0x02, -0x03, -0x04, +0x00, -0x05, -0x02, -0x05, +0x11, +0x00, -0x06, -0x05, -0x06, -0x04, -0x07], + [-0x03, -0x04, -0x02, -0x04, +0x00, -0x04, -0x04, -0x05, +0x00, -0x01, -0x01, -0x04, -0x02, +0x07, -0x05, -0x03, -0x03, +0x00, +0x0A, -0x02, -0x03, -0x04, -0x02, -0x07], + [+0x00, -0x02, -0x02, -0x02, -0x02, -0x02, -0x02, -0x01, -0x02, +0x04, +0x02, -0x02, +0x02, -0x01, -0x01, -0x01, +0x00, -0x06, -0x02, +0x04, -0x02, -0x02, -0x01, -0x07], + [+0x00, -0x01, +0x02, +0x03, -0x04, +0x01, +0x03, +0x01, +0x01, -0x02, -0x03, +0x01, -0x02, -0x04, -0x01, +0x00, +0x00, -0x05, -0x03, -0x02, +0x03, +0x02, +0x00, -0x07], + [+0x00, +0x00, +0x01, +0x03, -0x05, +0x03, +0x03, +0x00, +0x02, -0x02, -0x02, +0x00, -0x02, -0x05, +0x00, +0x00, +0x00, -0x06, -0x04, -0x02, +0x02, +0x03, -0x01, -0x07], + [+0x00, -0x01, +0x00, -0x01, -0x03, +0x00, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x02, -0x01, +0x00, +0x00, -0x04, -0x02, -0x01, +0x00, -0x01, -0x01, -0x07], + [-0x07, -0x07, -0x07, -0x07, -0x07, -0x07, -0x07, -0x07, -0x07, -0x07, -0x07, -0x07, -0x07, -0x07, -0x07, -0x07, -0x07, -0x07, -0x07, -0x07, -0x07, -0x07, -0x07, +0x01]] + +PAM270 = [[+0x02, -0x02, +0x00, +0x00, -0x02, +0x00, +0x00, +0x02, -0x02, -0x01, -0x02, -0x01, -0x01, -0x04, +0x01, +0x01, +0x01, -0x07, -0x04, +0x00, +0x00, +0x00, +0x00, -0x0A], + [-0x02, +0x08, +0x00, -0x01, -0x05, +0x02, -0x01, -0x03, +0x02, -0x02, -0x04, +0x04, -0x01, -0x05, +0x00, +0x00, -0x01, +0x03, -0x05, -0x03, -0x01, +0x00, -0x01, -0x0A], + [+0x00, +0x00, +0x02, +0x02, -0x04, +0x01, +0x02, +0x01, +0x02, -0x02, -0x03, +0x01, -0x02, -0x04, +0x00, +0x01, +0x01, -0x05, -0x03, -0x02, +0x02, +0x02, +0x00, -0x0A], + [+0x00, -0x01, +0x02, +0x05, -0x06, +0x02, +0x04, +0x01, +0x01, -0x03, -0x05, +0x00, -0x03, -0x07, -0x01, +0x00, +0x00, -0x08, -0x05, -0x03, +0x04, +0x03, -0x01, -0x0A], + [-0x02, -0x05, -0x04, -0x06, +0x10, -0x07, -0x06, -0x04, -0x04, -0x03, -0x07, -0x07, -0x06, -0x05, -0x03, +0x00, -0x03, -0x0A, +0x01, -0x02, -0x05, -0x07, -0x04, -0x0A], + [+0x00, +0x02, +0x01, +0x02, -0x07, +0x05, +0x03, -0x01, +0x04, -0x02, -0x02, +0x01, -0x01, -0x06, +0x00, -0x01, -0x01, -0x06, -0x05, -0x02, +0x02, +0x04, -0x01, -0x0A], + [+0x00, -0x01, +0x02, +0x04, -0x06, +0x03, +0x05, +0x00, +0x01, -0x02, -0x04, +0x00, -0x03, -0x07, -0x01, +0x00, +0x00, -0x09, -0x05, -0x02, +0x03, +0x04, -0x01, -0x0A], + [+0x02, -0x03, +0x01, +0x01, -0x04, -0x01, +0x00, +0x06, -0x02, -0x03, -0x05, -0x02, -0x03, -0x06, +0x00, +0x01, +0x00, -0x09, -0x06, -0x02, +0x01, +0x00, -0x01, -0x0A], + [-0x02, +0x02, +0x02, +0x01, -0x04, +0x04, +0x01, -0x02, +0x08, -0x03, -0x03, +0x00, -0x03, -0x02, +0x00, -0x01, -0x01, -0x03, +0x00, -0x03, +0x01, +0x02, -0x01, -0x0A], + [-0x01, -0x02, -0x02, -0x03, -0x03, -0x02, -0x02, -0x03, -0x03, +0x05, +0x03, -0x02, +0x03, +0x01, -0x02, -0x02, +0x00, -0x06, -0x01, +0x05, -0x03, -0x02, -0x01, -0x0A], + [-0x02, -0x04, -0x03, -0x05, -0x07, -0x02, -0x04, -0x05, -0x03, +0x03, +0x08, -0x03, +0x05, +0x02, -0x03, -0x03, -0x02, -0x02, -0x01, +0x02, -0x04, -0x03, -0x02, -0x0A], + [-0x01, +0x04, +0x01, +0x00, -0x07, +0x01, +0x00, -0x02, +0x00, -0x02, -0x03, +0x06, +0x00, -0x06, -0x01, +0x00, +0x00, -0x04, -0x05, -0x03, +0x01, +0x00, -0x01, -0x0A], + [-0x01, -0x01, -0x02, -0x03, -0x06, -0x01, -0x03, -0x03, -0x03, +0x03, +0x05, +0x00, +0x08, +0x00, -0x02, -0x02, -0x01, -0x05, -0x03, +0x02, -0x03, -0x02, -0x01, -0x0A], + [-0x04, -0x05, -0x04, -0x07, -0x05, -0x06, -0x07, -0x06, -0x02, +0x01, +0x02, -0x06, +0x00, +0x0C, -0x06, -0x04, -0x04, +0x01, +0x09, -0x01, -0x06, -0x06, -0x03, -0x0A], + [+0x01, +0x00, +0x00, -0x01, -0x03, +0x00, -0x01, +0x00, +0x00, -0x02, -0x03, -0x01, -0x02, -0x06, +0x07, +0x01, +0x00, -0x07, -0x06, -0x01, -0x01, +0x00, -0x01, -0x0A], + [+0x01, +0x00, +0x01, +0x00, +0x00, -0x01, +0x00, +0x01, -0x01, -0x02, -0x03, +0x00, -0x02, -0x04, +0x01, +0x02, +0x02, -0x03, -0x04, -0x01, +0x01, +0x00, +0x00, -0x0A], + [+0x01, -0x01, +0x01, +0x00, -0x03, -0x01, +0x00, +0x00, -0x01, +0x00, -0x02, +0x00, -0x01, -0x04, +0x00, +0x02, +0x03, -0x06, -0x03, +0x00, +0x00, -0x01, +0x00, -0x0A], + [-0x07, +0x03, -0x05, -0x08, -0x0A, -0x06, -0x09, -0x09, -0x03, -0x06, -0x02, -0x04, -0x05, +0x01, -0x07, -0x03, -0x06, +0x17, +0x00, -0x08, -0x07, -0x07, -0x05, -0x0A], + [-0x04, -0x05, -0x03, -0x05, +0x01, -0x05, -0x05, -0x06, +0x00, -0x01, -0x01, -0x05, -0x03, +0x09, -0x06, -0x04, -0x03, +0x00, +0x0D, -0x03, -0x04, -0x05, -0x03, -0x0A], + [+0x00, -0x03, -0x02, -0x03, -0x02, -0x02, -0x02, -0x02, -0x03, +0x05, +0x02, -0x03, +0x02, -0x01, -0x01, -0x01, +0x00, -0x08, -0x03, +0x05, -0x02, -0x02, -0x01, -0x0A], + [+0x00, -0x01, +0x02, +0x04, -0x05, +0x02, +0x03, +0x01, +0x01, -0x03, -0x04, +0x01, -0x03, -0x06, -0x01, +0x01, +0x00, -0x07, -0x04, -0x02, +0x03, +0x03, -0x01, -0x0A], + [+0x00, +0x00, +0x02, +0x03, -0x07, +0x04, +0x04, +0x00, +0x02, -0x02, -0x03, +0x00, -0x02, -0x06, +0x00, +0x00, -0x01, -0x07, -0x05, -0x02, +0x03, +0x04, -0x01, -0x0A], + [+0x00, -0x01, +0x00, -0x01, -0x04, -0x01, -0x01, -0x01, -0x01, -0x01, -0x02, -0x01, -0x01, -0x03, -0x01, +0x00, +0x00, -0x05, -0x03, -0x01, -0x01, -0x01, -0x01, -0x0A], + [-0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, +0x01]] + +PAM280 = [[+0x02, -0x02, +0x00, +0x00, -0x02, +0x00, +0x00, +0x02, -0x01, -0x01, -0x02, -0x01, -0x01, -0x04, +0x01, +0x01, +0x01, -0x07, -0x04, +0x00, +0x00, +0x00, +0x00, -0x09], + [-0x02, +0x07, +0x00, -0x01, -0x04, +0x02, -0x01, -0x03, +0x02, -0x02, -0x03, +0x04, +0x00, -0x05, +0x00, +0x00, -0x01, +0x03, -0x05, -0x03, -0x01, +0x00, -0x01, -0x09], + [+0x00, +0x00, +0x02, +0x02, -0x04, +0x01, +0x02, +0x01, +0x02, -0x02, -0x03, +0x01, -0x02, -0x04, +0x00, +0x01, +0x01, -0x05, -0x03, -0x02, +0x02, +0x01, +0x00, -0x09], + [+0x00, -0x01, +0x02, +0x04, -0x06, +0x02, +0x04, +0x01, +0x01, -0x03, -0x05, +0x00, -0x03, -0x07, -0x01, +0x00, +0x00, -0x08, -0x05, -0x02, +0x04, +0x03, -0x01, -0x09], + [-0x02, -0x04, -0x04, -0x06, +0x0F, -0x06, -0x06, -0x04, -0x04, -0x03, -0x07, -0x06, -0x06, -0x05, -0x03, +0x00, -0x03, -0x09, +0x01, -0x02, -0x05, -0x06, -0x03, -0x09], + [+0x00, +0x02, +0x01, +0x02, -0x06, +0x04, +0x03, -0x01, +0x03, -0x02, -0x02, +0x01, -0x01, -0x05, +0x00, +0x00, -0x01, -0x06, -0x05, -0x02, +0x02, +0x04, -0x01, -0x09], + [+0x00, -0x01, +0x02, +0x04, -0x06, +0x03, +0x04, +0x00, +0x01, -0x02, -0x04, +0x00, -0x02, -0x06, +0x00, +0x00, +0x00, -0x08, -0x05, -0x02, +0x03, +0x04, -0x01, -0x09], + [+0x02, -0x03, +0x01, +0x01, -0x04, -0x01, +0x00, +0x06, -0x02, -0x03, -0x05, -0x02, -0x03, -0x06, +0x00, +0x01, +0x00, -0x08, -0x06, -0x01, +0x01, +0x00, -0x01, -0x09], + [-0x01, +0x02, +0x02, +0x01, -0x04, +0x03, +0x01, -0x02, +0x08, -0x03, -0x02, +0x00, -0x02, -0x02, +0x00, -0x01, -0x01, -0x03, +0x00, -0x03, +0x01, +0x02, -0x01, -0x09], + [-0x01, -0x02, -0x02, -0x03, -0x03, -0x02, -0x02, -0x03, -0x03, +0x05, +0x03, -0x02, +0x03, +0x01, -0x02, -0x02, +0x00, -0x06, -0x01, +0x04, -0x02, -0x02, -0x01, -0x09], + [-0x02, -0x03, -0x03, -0x05, -0x07, -0x02, -0x04, -0x05, -0x02, +0x03, +0x07, -0x03, +0x05, +0x02, -0x03, -0x03, -0x02, -0x02, -0x01, +0x02, -0x04, -0x03, -0x01, -0x09], + [-0x01, +0x04, +0x01, +0x00, -0x06, +0x01, +0x00, -0x02, +0x00, -0x02, -0x03, +0x06, +0x00, -0x06, -0x01, +0x00, +0x00, -0x04, -0x05, -0x03, +0x01, +0x01, -0x01, -0x09], + [-0x01, +0x00, -0x02, -0x03, -0x06, -0x01, -0x02, -0x03, -0x02, +0x03, +0x05, +0x00, +0x07, +0x00, -0x02, -0x02, -0x01, -0x05, -0x03, +0x02, -0x02, -0x02, -0x01, -0x09], + [-0x04, -0x05, -0x04, -0x07, -0x05, -0x05, -0x06, -0x06, -0x02, +0x01, +0x02, -0x06, +0x00, +0x0B, -0x05, -0x04, -0x04, +0x01, +0x09, -0x01, -0x05, -0x06, -0x03, -0x09], + [+0x01, +0x00, +0x00, -0x01, -0x03, +0x00, +0x00, +0x00, +0x00, -0x02, -0x03, -0x01, -0x02, -0x05, +0x07, +0x01, +0x01, -0x07, -0x06, -0x01, -0x01, +0x00, -0x01, -0x09], + [+0x01, +0x00, +0x01, +0x00, +0x00, +0x00, +0x00, +0x01, -0x01, -0x02, -0x03, +0x00, -0x02, -0x04, +0x01, +0x02, +0x01, -0x03, -0x03, -0x01, +0x01, +0x00, +0x00, -0x09], + [+0x01, -0x01, +0x01, +0x00, -0x03, -0x01, +0x00, +0x00, -0x01, +0x00, -0x02, +0x00, -0x01, -0x04, +0x01, +0x01, +0x03, -0x06, -0x03, +0x00, +0x00, +0x00, +0x00, -0x09], + [-0x07, +0x03, -0x05, -0x08, -0x09, -0x06, -0x08, -0x08, -0x03, -0x06, -0x02, -0x04, -0x05, +0x01, -0x07, -0x03, -0x06, +0x16, +0x00, -0x07, -0x06, -0x07, -0x05, -0x09], + [-0x04, -0x05, -0x03, -0x05, +0x01, -0x05, -0x05, -0x06, +0x00, -0x01, -0x01, -0x05, -0x03, +0x09, -0x06, -0x03, -0x03, +0x00, +0x0D, -0x03, -0x04, -0x05, -0x03, -0x09], + [+0x00, -0x03, -0x02, -0x02, -0x02, -0x02, -0x02, -0x01, -0x03, +0x04, +0x02, -0x03, +0x02, -0x01, -0x01, -0x01, +0x00, -0x07, -0x03, +0x05, -0x02, -0x02, -0x01, -0x09], + [+0x00, -0x01, +0x02, +0x04, -0x05, +0x02, +0x03, +0x01, +0x01, -0x02, -0x04, +0x01, -0x02, -0x05, -0x01, +0x01, +0x00, -0x06, -0x04, -0x02, +0x03, +0x02, -0x01, -0x09], + [+0x00, +0x00, +0x01, +0x03, -0x06, +0x04, +0x04, +0x00, +0x02, -0x02, -0x03, +0x01, -0x02, -0x06, +0x00, +0x00, +0x00, -0x07, -0x05, -0x02, +0x02, +0x04, -0x01, -0x09], + [+0x00, -0x01, +0x00, -0x01, -0x03, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x03, -0x01, +0x00, +0x00, -0x05, -0x03, -0x01, -0x01, -0x01, -0x01, -0x09], + [-0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, +0x01]] + +PAM290 = [[+0x02, -0x02, +0x00, +0x00, -0x02, +0x00, +0x00, +0x02, -0x01, -0x01, -0x02, -0x01, -0x01, -0x04, +0x01, +0x01, +0x01, -0x07, -0x04, +0x00, +0x00, +0x00, +0x00, -0x09], + [-0x02, +0x07, +0x00, -0x01, -0x04, +0x02, -0x01, -0x03, +0x02, -0x02, -0x03, +0x04, +0x00, -0x05, +0x00, +0x00, -0x01, +0x03, -0x05, -0x03, +0x00, +0x00, -0x01, -0x09], + [+0x00, +0x00, +0x02, +0x02, -0x04, +0x01, +0x02, +0x01, +0x02, -0x02, -0x03, +0x01, -0x02, -0x04, +0x00, +0x01, +0x01, -0x05, -0x03, -0x02, +0x02, +0x01, +0x00, -0x09], + [+0x00, -0x01, +0x02, +0x04, -0x06, +0x02, +0x04, +0x01, +0x01, -0x03, -0x04, +0x00, -0x03, -0x06, -0x01, +0x00, +0x00, -0x08, -0x05, -0x02, +0x03, +0x03, -0x01, -0x09], + [-0x02, -0x04, -0x04, -0x06, +0x0F, -0x06, -0x06, -0x04, -0x04, -0x03, -0x07, -0x06, -0x06, -0x05, -0x03, +0x00, -0x02, -0x09, +0x01, -0x02, -0x05, -0x06, -0x03, -0x09], + [+0x00, +0x02, +0x01, +0x02, -0x06, +0x04, +0x03, -0x01, +0x03, -0x02, -0x02, +0x01, -0x01, -0x05, +0x00, +0x00, -0x01, -0x05, -0x05, -0x02, +0x02, +0x03, +0x00, -0x09], + [+0x00, -0x01, +0x02, +0x04, -0x06, +0x03, +0x04, +0x00, +0x01, -0x02, -0x04, +0x00, -0x02, -0x06, +0x00, +0x00, +0x00, -0x08, -0x05, -0x02, +0x03, +0x04, -0x01, -0x09], + [+0x02, -0x03, +0x01, +0x01, -0x04, -0x01, +0x00, +0x05, -0x02, -0x03, -0x04, -0x02, -0x03, -0x06, +0x00, +0x01, +0x00, -0x08, -0x06, -0x01, +0x01, +0x00, -0x01, -0x09], + [-0x01, +0x02, +0x02, +0x01, -0x04, +0x03, +0x01, -0x02, +0x07, -0x03, -0x02, +0x00, -0x02, -0x02, +0x00, -0x01, -0x01, -0x03, +0x00, -0x02, +0x01, +0x02, -0x01, -0x09], + [-0x01, -0x02, -0x02, -0x03, -0x03, -0x02, -0x02, -0x03, -0x03, +0x05, +0x03, -0x02, +0x03, +0x01, -0x02, -0x01, +0x00, -0x06, -0x01, +0x04, -0x02, -0x02, -0x01, -0x09], + [-0x02, -0x03, -0x03, -0x04, -0x07, -0x02, -0x04, -0x04, -0x02, +0x03, +0x07, -0x03, +0x05, +0x03, -0x03, -0x03, -0x02, -0x02, -0x01, +0x02, -0x04, -0x03, -0x01, -0x09], + [-0x01, +0x04, +0x01, +0x00, -0x06, +0x01, +0x00, -0x02, +0x00, -0x02, -0x03, +0x05, +0x00, -0x06, -0x01, +0x00, +0x00, -0x04, -0x05, -0x03, +0x01, +0x01, -0x01, -0x09], + [-0x01, +0x00, -0x02, -0x03, -0x06, -0x01, -0x02, -0x03, -0x02, +0x03, +0x05, +0x00, +0x07, +0x00, -0x02, -0x02, -0x01, -0x05, -0x02, +0x02, -0x02, -0x02, -0x01, -0x09], + [-0x04, -0x05, -0x04, -0x06, -0x05, -0x05, -0x06, -0x06, -0x02, +0x01, +0x03, -0x06, +0x00, +0x0B, -0x05, -0x04, -0x03, +0x01, +0x09, -0x01, -0x05, -0x06, -0x03, -0x09], + [+0x01, +0x00, +0x00, -0x01, -0x03, +0x00, +0x00, +0x00, +0x00, -0x02, -0x03, -0x01, -0x02, -0x05, +0x07, +0x01, +0x01, -0x06, -0x06, -0x01, -0x01, +0x00, -0x01, -0x09], + [+0x01, +0x00, +0x01, +0x00, +0x00, +0x00, +0x00, +0x01, -0x01, -0x01, -0x03, +0x00, -0x02, -0x04, +0x01, +0x02, +0x01, -0x03, -0x03, -0x01, +0x01, +0x00, +0x00, -0x09], + [+0x01, -0x01, +0x01, +0x00, -0x02, -0x01, +0x00, +0x00, -0x01, +0x00, -0x02, +0x00, -0x01, -0x03, +0x01, +0x01, +0x03, -0x06, -0x03, +0x00, +0x00, +0x00, +0x00, -0x09], + [-0x07, +0x03, -0x05, -0x08, -0x09, -0x05, -0x08, -0x08, -0x03, -0x06, -0x02, -0x04, -0x05, +0x01, -0x06, -0x03, -0x06, +0x16, +0x00, -0x07, -0x06, -0x07, -0x05, -0x09], + [-0x04, -0x05, -0x03, -0x05, +0x01, -0x05, -0x05, -0x06, +0x00, -0x01, -0x01, -0x05, -0x02, +0x09, -0x06, -0x03, -0x03, +0x00, +0x0D, -0x03, -0x04, -0x05, -0x02, -0x09], + [+0x00, -0x03, -0x02, -0x02, -0x02, -0x02, -0x02, -0x01, -0x02, +0x04, +0x02, -0x03, +0x02, -0x01, -0x01, -0x01, +0x00, -0x07, -0x03, +0x05, -0x02, -0x02, -0x01, -0x09], + [+0x00, +0x00, +0x02, +0x03, -0x05, +0x02, +0x03, +0x01, +0x01, -0x02, -0x04, +0x01, -0x02, -0x05, -0x01, +0x01, +0x00, -0x06, -0x04, -0x02, +0x03, +0x02, +0x00, -0x09], + [+0x00, +0x00, +0x01, +0x03, -0x06, +0x03, +0x04, +0x00, +0x02, -0x02, -0x03, +0x01, -0x02, -0x06, +0x00, +0x00, +0x00, -0x07, -0x05, -0x02, +0x02, +0x04, -0x01, -0x09], + [+0x00, -0x01, +0x00, -0x01, -0x03, +0x00, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x01, -0x03, -0x01, +0x00, +0x00, -0x05, -0x02, -0x01, +0x00, -0x01, -0x01, -0x09], + [-0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, +0x01]] + +PAM300 = [[+0x02, -0x01, +0x00, +0x00, -0x02, +0x00, +0x00, +0x02, -0x01, +0x00, -0x02, -0x01, -0x01, -0x04, +0x01, +0x01, +0x01, -0x06, -0x04, +0x00, +0x00, +0x00, +0x00, -0x09], + [-0x01, +0x07, +0x00, -0x01, -0x04, +0x02, -0x01, -0x02, +0x02, -0x02, -0x03, +0x04, +0x00, -0x05, +0x00, +0x00, -0x01, +0x03, -0x05, -0x03, +0x00, +0x00, -0x01, -0x09], + [+0x00, +0x00, +0x02, +0x02, -0x04, +0x01, +0x02, +0x01, +0x02, -0x02, -0x03, +0x01, -0x02, -0x04, +0x00, +0x01, +0x00, -0x05, -0x02, -0x02, +0x02, +0x01, +0x00, -0x09], + [+0x00, -0x01, +0x02, +0x04, -0x06, +0x02, +0x04, +0x01, +0x01, -0x02, -0x04, +0x00, -0x03, -0x06, -0x01, +0x00, +0x00, -0x07, -0x05, -0x02, +0x03, +0x03, -0x01, -0x09], + [-0x02, -0x04, -0x04, -0x06, +0x0F, -0x06, -0x06, -0x04, -0x04, -0x03, -0x07, -0x06, -0x06, -0x05, -0x03, +0x00, -0x02, -0x09, +0x01, -0x02, -0x05, -0x06, -0x03, -0x09], + [+0x00, +0x02, +0x01, +0x02, -0x06, +0x04, +0x03, -0x01, +0x03, -0x02, -0x02, +0x01, -0x01, -0x05, +0x00, +0x00, -0x01, -0x05, -0x04, -0x02, +0x02, +0x03, +0x00, -0x09], + [+0x00, -0x01, +0x02, +0x04, -0x06, +0x03, +0x04, +0x00, +0x01, -0x02, -0x04, +0x00, -0x02, -0x06, +0x00, +0x00, +0x00, -0x08, -0x05, -0x02, +0x03, +0x03, -0x01, -0x09], + [+0x02, -0x02, +0x01, +0x01, -0x04, -0x01, +0x00, +0x05, -0x02, -0x03, -0x04, -0x02, -0x03, -0x05, +0x00, +0x01, +0x00, -0x08, -0x06, -0x01, +0x01, +0x00, -0x01, -0x09], + [-0x01, +0x02, +0x02, +0x01, -0x04, +0x03, +0x01, -0x02, +0x07, -0x02, -0x02, +0x00, -0x02, -0x02, +0x00, -0x01, -0x01, -0x03, +0x00, -0x02, +0x01, +0x02, +0x00, -0x09], + [+0x00, -0x02, -0x02, -0x02, -0x03, -0x02, -0x02, -0x03, -0x02, +0x05, +0x03, -0x02, +0x03, +0x01, -0x02, -0x01, +0x00, -0x06, -0x01, +0x04, -0x02, -0x02, -0x01, -0x09], + [-0x02, -0x03, -0x03, -0x04, -0x07, -0x02, -0x04, -0x04, -0x02, +0x03, +0x07, -0x03, +0x04, +0x03, -0x03, -0x03, -0x02, -0x02, +0x00, +0x02, -0x04, -0x03, -0x01, -0x09], + [-0x01, +0x04, +0x01, +0x00, -0x06, +0x01, +0x00, -0x02, +0x00, -0x02, -0x03, +0x05, +0x00, -0x06, -0x01, +0x00, +0x00, -0x04, -0x05, -0x02, +0x01, +0x01, -0x01, -0x09], + [-0x01, +0x00, -0x02, -0x03, -0x06, -0x01, -0x02, -0x03, -0x02, +0x03, +0x04, +0x00, +0x06, +0x01, -0x02, -0x02, -0x01, -0x05, -0x02, +0x02, -0x02, -0x02, -0x01, -0x09], + [-0x04, -0x05, -0x04, -0x06, -0x05, -0x05, -0x06, -0x05, -0x02, +0x01, +0x03, -0x06, +0x01, +0x0B, -0x05, -0x04, -0x03, +0x01, +0x09, -0x01, -0x05, -0x05, -0x02, -0x09], + [+0x01, +0x00, +0x00, -0x01, -0x03, +0x00, +0x00, +0x00, +0x00, -0x02, -0x03, -0x01, -0x02, -0x05, +0x06, +0x01, +0x01, -0x06, -0x05, -0x01, +0x00, +0x00, -0x01, -0x09], + [+0x01, +0x00, +0x01, +0x00, +0x00, +0x00, +0x00, +0x01, -0x01, -0x01, -0x03, +0x00, -0x02, -0x04, +0x01, +0x01, +0x01, -0x03, -0x03, -0x01, +0x01, +0x00, +0x00, -0x09], + [+0x01, -0x01, +0x00, +0x00, -0x02, -0x01, +0x00, +0x00, -0x01, +0x00, -0x02, +0x00, -0x01, -0x03, +0x01, +0x01, +0x02, -0x06, -0x03, +0x00, +0x00, +0x00, +0x00, -0x09], + [-0x06, +0x03, -0x05, -0x07, -0x09, -0x05, -0x08, -0x08, -0x03, -0x06, -0x02, -0x04, -0x05, +0x01, -0x06, -0x03, -0x06, +0x16, +0x00, -0x07, -0x06, -0x06, -0x04, -0x09], + [-0x04, -0x05, -0x02, -0x05, +0x01, -0x04, -0x05, -0x06, +0x00, -0x01, +0x00, -0x05, -0x02, +0x09, -0x05, -0x03, -0x03, +0x00, +0x0C, -0x03, -0x04, -0x05, -0x02, -0x09], + [+0x00, -0x03, -0x02, -0x02, -0x02, -0x02, -0x02, -0x01, -0x02, +0x04, +0x02, -0x02, +0x02, -0x01, -0x01, -0x01, +0x00, -0x07, -0x03, +0x05, -0x02, -0x02, +0x00, -0x09], + [+0x00, +0x00, +0x02, +0x03, -0x05, +0x02, +0x03, +0x01, +0x01, -0x02, -0x04, +0x01, -0x02, -0x05, +0x00, +0x01, +0x00, -0x06, -0x04, -0x02, +0x03, +0x02, +0x00, -0x09], + [+0x00, +0x00, +0x01, +0x03, -0x06, +0x03, +0x03, +0x00, +0x02, -0x02, -0x03, +0x01, -0x02, -0x05, +0x00, +0x00, +0x00, -0x06, -0x05, -0x02, +0x02, +0x03, -0x01, -0x09], + [+0x00, -0x01, +0x00, -0x01, -0x03, +0x00, -0x01, -0x01, +0x00, -0x01, -0x01, -0x01, -0x01, -0x02, -0x01, +0x00, +0x00, -0x04, -0x02, +0x00, +0x00, -0x01, -0x01, -0x09], + [-0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, +0x01]] + +PAM310 = [[+0x02, -0x01, +0x00, +0x00, -0x02, +0x00, +0x00, +0x01, -0x01, +0x00, -0x02, -0x01, -0x01, -0x04, +0x01, +0x01, +0x01, -0x06, -0x04, +0x00, +0x00, +0x00, +0x00, -0x09], + [-0x01, +0x06, +0x00, -0x01, -0x04, +0x01, -0x01, -0x02, +0x02, -0x02, -0x03, +0x04, +0x00, -0x05, +0x00, +0x00, -0x01, +0x03, -0x04, -0x02, +0x00, +0x00, -0x01, -0x09], + [+0x00, +0x00, +0x02, +0x02, -0x04, +0x01, +0x02, +0x01, +0x02, -0x02, -0x03, +0x01, -0x02, -0x04, +0x00, +0x01, +0x00, -0x04, -0x02, -0x02, +0x02, +0x01, +0x00, -0x09], + [+0x00, -0x01, +0x02, +0x04, -0x05, +0x02, +0x04, +0x01, +0x01, -0x02, -0x04, +0x00, -0x02, -0x06, -0x01, +0x00, +0x00, -0x07, -0x05, -0x02, +0x03, +0x03, -0x01, -0x09], + [-0x02, -0x04, -0x04, -0x05, +0x0F, -0x06, -0x06, -0x03, -0x04, -0x02, -0x06, -0x06, -0x06, -0x04, -0x03, +0x00, -0x02, -0x09, +0x01, -0x02, -0x05, -0x06, -0x03, -0x09], + [+0x00, +0x01, +0x01, +0x02, -0x06, +0x04, +0x03, -0x01, +0x03, -0x02, -0x02, +0x01, -0x01, -0x05, +0x00, +0x00, -0x01, -0x05, -0x04, -0x02, +0x02, +0x03, +0x00, -0x09], + [+0x00, -0x01, +0x02, +0x04, -0x06, +0x03, +0x04, +0x01, +0x01, -0x02, -0x03, +0x00, -0x02, -0x06, +0x00, +0x00, +0x00, -0x07, -0x05, -0x02, +0x03, +0x03, -0x01, -0x09], + [+0x01, -0x02, +0x01, +0x01, -0x03, -0x01, +0x01, +0x05, -0x02, -0x02, -0x04, -0x01, -0x03, -0x05, +0x00, +0x01, +0x00, -0x08, -0x06, -0x01, +0x01, +0x00, -0x01, -0x09], + [-0x01, +0x02, +0x02, +0x01, -0x04, +0x03, +0x01, -0x02, +0x07, -0x02, -0x02, +0x00, -0x02, -0x02, +0x00, -0x01, -0x01, -0x03, +0x00, -0x02, +0x01, +0x02, +0x00, -0x09], + [+0x00, -0x02, -0x02, -0x02, -0x02, -0x02, -0x02, -0x02, -0x02, +0x04, +0x03, -0x02, +0x03, +0x01, -0x02, -0x01, +0x00, -0x05, -0x01, +0x04, -0x02, -0x02, -0x01, -0x09], + [-0x02, -0x03, -0x03, -0x04, -0x06, -0x02, -0x03, -0x04, -0x02, +0x03, +0x07, -0x03, +0x04, +0x03, -0x03, -0x03, -0x02, -0x02, +0x00, +0x02, -0x03, -0x03, -0x01, -0x09], + [-0x01, +0x04, +0x01, +0x00, -0x06, +0x01, +0x00, -0x01, +0x00, -0x02, -0x03, +0x05, +0x00, -0x05, -0x01, +0x00, +0x00, -0x03, -0x05, -0x02, +0x01, +0x01, -0x01, -0x09], + [-0x01, +0x00, -0x02, -0x02, -0x06, -0x01, -0x02, -0x03, -0x02, +0x03, +0x04, +0x00, +0x06, +0x01, -0x02, -0x02, -0x01, -0x04, -0x02, +0x02, -0x02, -0x02, -0x01, -0x09], + [-0x04, -0x05, -0x04, -0x06, -0x04, -0x05, -0x06, -0x05, -0x02, +0x01, +0x03, -0x05, +0x01, +0x0B, -0x05, -0x04, -0x03, +0x01, +0x09, -0x01, -0x05, -0x05, -0x02, -0x09], + [+0x01, +0x00, +0x00, -0x01, -0x03, +0x00, +0x00, +0x00, +0x00, -0x02, -0x03, -0x01, -0x02, -0x05, +0x06, +0x01, +0x01, -0x06, -0x05, -0x01, +0x00, +0x00, +0x00, -0x09], + [+0x01, +0x00, +0x01, +0x00, +0x00, +0x00, +0x00, +0x01, -0x01, -0x01, -0x03, +0x00, -0x02, -0x04, +0x01, +0x01, +0x01, -0x03, -0x03, -0x01, +0x01, +0x00, +0x00, -0x09], + [+0x01, -0x01, +0x00, +0x00, -0x02, -0x01, +0x00, +0x00, -0x01, +0x00, -0x02, +0x00, -0x01, -0x03, +0x01, +0x01, +0x02, -0x06, -0x03, +0x00, +0x00, +0x00, +0x00, -0x09], + [-0x06, +0x03, -0x04, -0x07, -0x09, -0x05, -0x07, -0x08, -0x03, -0x05, -0x02, -0x03, -0x04, +0x01, -0x06, -0x03, -0x06, +0x16, +0x00, -0x07, -0x06, -0x06, -0x04, -0x09], + [-0x04, -0x04, -0x02, -0x05, +0x01, -0x04, -0x05, -0x06, +0x00, -0x01, +0x00, -0x05, -0x02, +0x09, -0x05, -0x03, -0x03, +0x00, +0x0C, -0x02, -0x04, -0x04, -0x02, -0x09], + [+0x00, -0x02, -0x02, -0x02, -0x02, -0x02, -0x02, -0x01, -0x02, +0x04, +0x02, -0x02, +0x02, -0x01, -0x01, -0x01, +0x00, -0x07, -0x02, +0x04, -0x02, -0x02, +0x00, -0x09], + [+0x00, +0x00, +0x02, +0x03, -0x05, +0x02, +0x03, +0x01, +0x01, -0x02, -0x03, +0x01, -0x02, -0x05, +0x00, +0x01, +0x00, -0x06, -0x04, -0x02, +0x03, +0x02, +0x00, -0x09], + [+0x00, +0x00, +0x01, +0x03, -0x06, +0x03, +0x03, +0x00, +0x02, -0x02, -0x03, +0x01, -0x02, -0x05, +0x00, +0x00, +0x00, -0x06, -0x04, -0x02, +0x02, +0x03, +0x00, -0x09], + [+0x00, -0x01, +0x00, -0x01, -0x03, +0x00, -0x01, -0x01, +0x00, -0x01, -0x01, -0x01, -0x01, -0x02, +0x00, +0x00, +0x00, -0x04, -0x02, +0x00, +0x00, +0x00, -0x01, -0x09], + [-0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, +0x01]] + +PAM320 = [[+0x01, -0x01, +0x00, +0x01, -0x02, +0x00, +0x00, +0x01, -0x01, +0x00, -0x02, -0x01, -0x01, -0x04, +0x01, +0x01, +0x01, -0x06, -0x04, +0x00, +0x00, +0x00, +0x00, -0x08], + [-0x01, +0x06, +0x00, -0x01, -0x04, +0x01, -0x01, -0x02, +0x02, -0x02, -0x03, +0x04, +0x00, -0x05, +0x00, +0x00, -0x01, +0x03, -0x04, -0x02, +0x00, +0x00, -0x01, -0x08], + [+0x00, +0x00, +0x02, +0x02, -0x04, +0x01, +0x02, +0x01, +0x02, -0x02, -0x03, +0x01, -0x02, -0x04, +0x00, +0x01, +0x00, -0x04, -0x02, -0x02, +0x02, +0x01, +0x00, -0x08], + [+0x01, -0x01, +0x02, +0x04, -0x05, +0x02, +0x03, +0x01, +0x01, -0x02, -0x04, +0x00, -0x02, -0x06, +0x00, +0x00, +0x00, -0x07, -0x05, -0x02, +0x03, +0x03, -0x01, -0x08], + [-0x02, -0x04, -0x04, -0x05, +0x0F, -0x05, -0x05, -0x03, -0x04, -0x02, -0x06, -0x06, -0x05, -0x04, -0x03, +0x00, -0x02, -0x08, +0x01, -0x02, -0x04, -0x05, -0x03, -0x08], + [+0x00, +0x01, +0x01, +0x02, -0x05, +0x04, +0x02, -0x01, +0x03, -0x02, -0x02, +0x01, -0x01, -0x05, +0x00, +0x00, +0x00, -0x05, -0x04, -0x02, +0x02, +0x03, +0x00, -0x08], + [+0x00, -0x01, +0x02, +0x03, -0x05, +0x02, +0x04, +0x01, +0x01, -0x02, -0x03, +0x00, -0x02, -0x05, +0x00, +0x00, +0x00, -0x07, -0x05, -0x02, +0x03, +0x03, +0x00, -0x08], + [+0x01, -0x02, +0x01, +0x01, -0x03, -0x01, +0x01, +0x05, -0x02, -0x02, -0x04, -0x01, -0x03, -0x05, +0x00, +0x01, +0x00, -0x07, -0x05, -0x01, +0x01, +0x00, -0x01, -0x08], + [-0x01, +0x02, +0x02, +0x01, -0x04, +0x03, +0x01, -0x02, +0x06, -0x02, -0x02, +0x00, -0x02, -0x02, +0x00, -0x01, -0x01, -0x03, +0x00, -0x02, +0x01, +0x02, +0x00, -0x08], + [+0x00, -0x02, -0x02, -0x02, -0x02, -0x02, -0x02, -0x02, -0x02, +0x04, +0x03, -0x02, +0x02, +0x01, -0x02, -0x01, +0x00, -0x05, -0x01, +0x04, -0x02, -0x02, +0x00, -0x08], + [-0x02, -0x03, -0x03, -0x04, -0x06, -0x02, -0x03, -0x04, -0x02, +0x03, +0x07, -0x03, +0x04, +0x03, -0x02, -0x03, -0x02, -0x02, +0x00, +0x02, -0x03, -0x03, -0x01, -0x08], + [-0x01, +0x04, +0x01, +0x00, -0x06, +0x01, +0x00, -0x01, +0x00, -0x02, -0x03, +0x05, +0x00, -0x05, -0x01, +0x00, +0x00, -0x03, -0x05, -0x02, +0x01, +0x01, -0x01, -0x08], + [-0x01, +0x00, -0x02, -0x02, -0x05, -0x01, -0x02, -0x03, -0x02, +0x02, +0x04, +0x00, +0x06, +0x01, -0x02, -0x01, -0x01, -0x04, -0x02, +0x02, -0x02, -0x02, +0x00, -0x08], + [-0x04, -0x05, -0x04, -0x06, -0x04, -0x05, -0x05, -0x05, -0x02, +0x01, +0x03, -0x05, +0x01, +0x0B, -0x05, -0x03, -0x03, +0x01, +0x09, -0x01, -0x05, -0x05, -0x02, -0x08], + [+0x01, +0x00, +0x00, +0x00, -0x03, +0x00, +0x00, +0x00, +0x00, -0x02, -0x02, -0x01, -0x02, -0x05, +0x06, +0x01, +0x01, -0x06, -0x05, -0x01, +0x00, +0x00, +0x00, -0x08], + [+0x01, +0x00, +0x01, +0x00, +0x00, +0x00, +0x00, +0x01, -0x01, -0x01, -0x03, +0x00, -0x01, -0x03, +0x01, +0x01, +0x01, -0x03, -0x03, -0x01, +0x01, +0x00, +0x00, -0x08], + [+0x01, -0x01, +0x00, +0x00, -0x02, +0x00, +0x00, +0x00, -0x01, +0x00, -0x02, +0x00, -0x01, -0x03, +0x01, +0x01, +0x02, -0x05, -0x03, +0x00, +0x00, +0x00, +0x00, -0x08], + [-0x06, +0x03, -0x04, -0x07, -0x08, -0x05, -0x07, -0x07, -0x03, -0x05, -0x02, -0x03, -0x04, +0x01, -0x06, -0x03, -0x05, +0x16, +0x01, -0x06, -0x06, -0x06, -0x04, -0x08], + [-0x04, -0x04, -0x02, -0x05, +0x01, -0x04, -0x05, -0x05, +0x00, -0x01, +0x00, -0x05, -0x02, +0x09, -0x05, -0x03, -0x03, +0x01, +0x0C, -0x02, -0x03, -0x04, -0x02, -0x08], + [+0x00, -0x02, -0x02, -0x02, -0x02, -0x02, -0x02, -0x01, -0x02, +0x04, +0x02, -0x02, +0x02, -0x01, -0x01, -0x01, +0x00, -0x06, -0x02, +0x04, -0x02, -0x02, +0x00, -0x08], + [+0x00, +0x00, +0x02, +0x03, -0x04, +0x02, +0x03, +0x01, +0x01, -0x02, -0x03, +0x01, -0x02, -0x05, +0x00, +0x01, +0x00, -0x06, -0x03, -0x02, +0x02, +0x02, +0x00, -0x08], + [+0x00, +0x00, +0x01, +0x03, -0x05, +0x03, +0x03, +0x00, +0x02, -0x02, -0x03, +0x01, -0x02, -0x05, +0x00, +0x00, +0x00, -0x06, -0x04, -0x02, +0x02, +0x03, +0x00, -0x08], + [+0x00, -0x01, +0x00, -0x01, -0x03, +0x00, +0x00, -0x01, +0x00, +0x00, -0x01, -0x01, +0x00, -0x02, +0x00, +0x00, +0x00, -0x04, -0x02, +0x00, +0x00, +0x00, -0x01, -0x08], + [-0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, +0x01]] + +PAM330 = [[+0x01, -0x01, +0x00, +0x01, -0x02, +0x00, +0x00, +0x01, -0x01, +0x00, -0x02, -0x01, -0x01, -0x03, +0x01, +0x01, +0x01, -0x06, -0x03, +0x00, +0x00, +0x00, +0x00, -0x08], + [-0x01, +0x06, +0x00, -0x01, -0x04, +0x01, -0x01, -0x02, +0x02, -0x02, -0x03, +0x04, +0x00, -0x04, +0x00, +0x00, -0x01, +0x03, -0x04, -0x02, +0x00, +0x00, -0x01, -0x08], + [+0x00, +0x00, +0x02, +0x02, -0x04, +0x01, +0x02, +0x01, +0x01, -0x02, -0x03, +0x01, -0x01, -0x03, +0x00, +0x01, +0x00, -0x04, -0x02, -0x01, +0x02, +0x01, +0x00, -0x08], + [+0x01, -0x01, +0x02, +0x03, -0x05, +0x02, +0x03, +0x01, +0x01, -0x02, -0x04, +0x00, -0x02, -0x05, +0x00, +0x00, +0x00, -0x07, -0x04, -0x02, +0x03, +0x03, +0x00, -0x08], + [-0x02, -0x04, -0x04, -0x05, +0x0F, -0x05, -0x05, -0x03, -0x03, -0x02, -0x06, -0x05, -0x05, -0x04, -0x03, +0x00, -0x02, -0x08, +0x01, -0x02, -0x04, -0x05, -0x03, -0x08], + [+0x00, +0x01, +0x01, +0x02, -0x05, +0x03, +0x02, -0x01, +0x03, -0x02, -0x02, +0x01, -0x01, -0x04, +0x00, +0x00, +0x00, -0x05, -0x04, -0x02, +0x01, +0x03, +0x00, -0x08], + [+0x00, -0x01, +0x02, +0x03, -0x05, +0x02, +0x03, +0x01, +0x01, -0x02, -0x03, +0x00, -0x02, -0x05, +0x00, +0x00, +0x00, -0x07, -0x04, -0x02, +0x02, +0x03, +0x00, -0x08], + [+0x01, -0x02, +0x01, +0x01, -0x03, -0x01, +0x01, +0x05, -0x02, -0x02, -0x04, -0x01, -0x02, -0x05, +0x00, +0x01, +0x00, -0x07, -0x05, -0x01, +0x01, +0x00, -0x01, -0x08], + [-0x01, +0x02, +0x01, +0x01, -0x03, +0x03, +0x01, -0x02, +0x06, -0x02, -0x02, +0x00, -0x02, -0x02, +0x00, -0x01, -0x01, -0x03, +0x00, -0x02, +0x01, +0x02, +0x00, -0x08], + [+0x00, -0x02, -0x02, -0x02, -0x02, -0x02, -0x02, -0x02, -0x02, +0x04, +0x03, -0x02, +0x02, +0x01, -0x02, -0x01, +0x00, -0x05, +0x00, +0x04, -0x02, -0x02, +0x00, -0x08], + [-0x02, -0x03, -0x03, -0x04, -0x06, -0x02, -0x03, -0x04, -0x02, +0x03, +0x06, -0x03, +0x04, +0x03, -0x02, -0x03, -0x01, -0x02, +0x00, +0x02, -0x03, -0x02, -0x01, -0x08], + [-0x01, +0x04, +0x01, +0x00, -0x05, +0x01, +0x00, -0x01, +0x00, -0x02, -0x03, +0x05, +0x00, -0x05, -0x01, +0x00, +0x00, -0x03, -0x04, -0x02, +0x01, +0x01, -0x01, -0x08], + [-0x01, +0x00, -0x01, -0x02, -0x05, -0x01, -0x02, -0x02, -0x02, +0x02, +0x04, +0x00, +0x05, +0x01, -0x02, -0x01, +0x00, -0x04, -0x02, +0x02, -0x02, -0x01, +0x00, -0x08], + [-0x03, -0x04, -0x03, -0x05, -0x04, -0x04, -0x05, -0x05, -0x02, +0x01, +0x03, -0x05, +0x01, +0x0A, -0x05, -0x03, -0x03, +0x01, +0x09, -0x01, -0x04, -0x05, -0x02, -0x08], + [+0x01, +0x00, +0x00, +0x00, -0x03, +0x00, +0x00, +0x00, +0x00, -0x02, -0x02, -0x01, -0x02, -0x05, +0x06, +0x01, +0x01, -0x06, -0x05, -0x01, +0x00, +0x00, +0x00, -0x08], + [+0x01, +0x00, +0x01, +0x00, +0x00, +0x00, +0x00, +0x01, -0x01, -0x01, -0x03, +0x00, -0x01, -0x03, +0x01, +0x01, +0x01, -0x03, -0x03, -0x01, +0x01, +0x00, +0x00, -0x08], + [+0x01, -0x01, +0x00, +0x00, -0x02, +0x00, +0x00, +0x00, -0x01, +0x00, -0x01, +0x00, +0x00, -0x03, +0x01, +0x01, +0x02, -0x05, -0x03, +0x00, +0x00, +0x00, +0x00, -0x08], + [-0x06, +0x03, -0x04, -0x07, -0x08, -0x05, -0x07, -0x07, -0x03, -0x05, -0x02, -0x03, -0x04, +0x01, -0x06, -0x03, -0x05, +0x16, +0x01, -0x06, -0x05, -0x06, -0x04, -0x08], + [-0x03, -0x04, -0x02, -0x04, +0x01, -0x04, -0x04, -0x05, +0x00, +0x00, +0x00, -0x04, -0x02, +0x09, -0x05, -0x03, -0x03, +0x01, +0x0C, -0x02, -0x03, -0x04, -0x02, -0x08], + [+0x00, -0x02, -0x01, -0x02, -0x02, -0x02, -0x02, -0x01, -0x02, +0x04, +0x02, -0x02, +0x02, -0x01, -0x01, -0x01, +0x00, -0x06, -0x02, +0x04, -0x02, -0x02, +0x00, -0x08], + [+0x00, +0x00, +0x02, +0x03, -0x04, +0x01, +0x02, +0x01, +0x01, -0x02, -0x03, +0x01, -0x02, -0x04, +0x00, +0x01, +0x00, -0x05, -0x03, -0x02, +0x02, +0x02, +0x00, -0x08], + [+0x00, +0x00, +0x01, +0x03, -0x05, +0x03, +0x03, +0x00, +0x02, -0x02, -0x02, +0x01, -0x01, -0x05, +0x00, +0x00, +0x00, -0x06, -0x04, -0x02, +0x02, +0x03, +0x00, -0x08], + [+0x00, -0x01, +0x00, +0x00, -0x03, +0x00, +0x00, -0x01, +0x00, +0x00, -0x01, -0x01, +0x00, -0x02, +0x00, +0x00, +0x00, -0x04, -0x02, +0x00, +0x00, +0x00, -0x01, -0x08], + [-0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, +0x01]] + +PAM340 = [[+0x01, -0x01, +0x00, +0x01, -0x02, +0x00, +0x00, +0x01, -0x01, +0x00, -0x02, -0x01, -0x01, -0x03, +0x01, +0x01, +0x01, -0x06, -0x03, +0x00, +0x00, +0x00, +0x00, -0x08], + [-0x01, +0x06, +0x00, -0x01, -0x04, +0x01, +0x00, -0x02, +0x02, -0x02, -0x03, +0x04, +0x00, -0x04, +0x00, +0x00, +0x00, +0x03, -0x04, -0x02, +0x00, +0x00, -0x01, -0x08], + [+0x00, +0x00, +0x01, +0x02, -0x03, +0x01, +0x01, +0x01, +0x01, -0x02, -0x03, +0x01, -0x01, -0x03, +0x00, +0x01, +0x00, -0x04, -0x02, -0x01, +0x02, +0x01, +0x00, -0x08], + [+0x01, -0x01, +0x02, +0x03, -0x05, +0x02, +0x03, +0x01, +0x01, -0x02, -0x04, +0x00, -0x02, -0x05, +0x00, +0x00, +0x00, -0x07, -0x04, -0x02, +0x03, +0x03, +0x00, -0x08], + [-0x02, -0x04, -0x03, -0x05, +0x0F, -0x05, -0x05, -0x03, -0x03, -0x02, -0x06, -0x05, -0x05, -0x04, -0x03, +0x00, -0x02, -0x08, +0x01, -0x02, -0x04, -0x05, -0x03, -0x08], + [+0x00, +0x01, +0x01, +0x02, -0x05, +0x03, +0x02, -0x01, +0x03, -0x02, -0x02, +0x01, -0x01, -0x04, +0x00, +0x00, +0x00, -0x05, -0x04, -0x02, +0x01, +0x03, +0x00, -0x08], + [+0x00, +0x00, +0x01, +0x03, -0x05, +0x02, +0x03, +0x01, +0x01, -0x02, -0x03, +0x00, -0x02, -0x05, +0x00, +0x00, +0x00, -0x07, -0x04, -0x01, +0x02, +0x03, +0x00, -0x08], + [+0x01, -0x02, +0x01, +0x01, -0x03, -0x01, +0x01, +0x04, -0x02, -0x02, -0x04, -0x01, -0x02, -0x05, +0x00, +0x01, +0x00, -0x07, -0x05, -0x01, +0x01, +0x00, -0x01, -0x08], + [-0x01, +0x02, +0x01, +0x01, -0x03, +0x03, +0x01, -0x02, +0x06, -0x02, -0x02, +0x00, -0x02, -0x02, +0x00, +0x00, -0x01, -0x02, +0x00, -0x02, +0x01, +0x02, +0x00, -0x08], + [+0x00, -0x02, -0x02, -0x02, -0x02, -0x02, -0x02, -0x02, -0x02, +0x04, +0x03, -0x02, +0x02, +0x01, -0x02, -0x01, +0x00, -0x05, +0x00, +0x03, -0x02, -0x02, +0x00, -0x08], + [-0x02, -0x03, -0x03, -0x04, -0x06, -0x02, -0x03, -0x04, -0x02, +0x03, +0x06, -0x03, +0x04, +0x03, -0x02, -0x02, -0x01, -0x02, +0x00, +0x02, -0x03, -0x02, -0x01, -0x08], + [-0x01, +0x04, +0x01, +0x00, -0x05, +0x01, +0x00, -0x01, +0x00, -0x02, -0x03, +0x04, +0x00, -0x05, -0x01, +0x00, +0x00, -0x03, -0x04, -0x02, +0x01, +0x01, +0x00, -0x08], + [-0x01, +0x00, -0x01, -0x02, -0x05, -0x01, -0x02, -0x02, -0x02, +0x02, +0x04, +0x00, +0x05, +0x01, -0x02, -0x01, +0x00, -0x04, -0x02, +0x02, -0x02, -0x01, +0x00, -0x08], + [-0x03, -0x04, -0x03, -0x05, -0x04, -0x04, -0x05, -0x05, -0x02, +0x01, +0x03, -0x05, +0x01, +0x0A, -0x04, -0x03, -0x03, +0x01, +0x09, -0x01, -0x04, -0x05, -0x02, -0x08], + [+0x01, +0x00, +0x00, +0x00, -0x03, +0x00, +0x00, +0x00, +0x00, -0x02, -0x02, -0x01, -0x02, -0x04, +0x05, +0x01, +0x01, -0x05, -0x05, -0x01, +0x00, +0x00, +0x00, -0x08], + [+0x01, +0x00, +0x01, +0x00, +0x00, +0x00, +0x00, +0x01, +0x00, -0x01, -0x02, +0x00, -0x01, -0x03, +0x01, +0x01, +0x01, -0x03, -0x03, -0x01, +0x01, +0x00, +0x00, -0x08], + [+0x01, +0x00, +0x00, +0x00, -0x02, +0x00, +0x00, +0x00, -0x01, +0x00, -0x01, +0x00, +0x00, -0x03, +0x01, +0x01, +0x02, -0x05, -0x03, +0x00, +0x00, +0x00, +0x00, -0x08], + [-0x06, +0x03, -0x04, -0x07, -0x08, -0x05, -0x07, -0x07, -0x02, -0x05, -0x02, -0x03, -0x04, +0x01, -0x05, -0x03, -0x05, +0x16, +0x01, -0x06, -0x05, -0x06, -0x04, -0x08], + [-0x03, -0x04, -0x02, -0x04, +0x01, -0x04, -0x04, -0x05, +0x00, +0x00, +0x00, -0x04, -0x02, +0x09, -0x05, -0x03, -0x03, +0x01, +0x0C, -0x02, -0x03, -0x04, -0x02, -0x08], + [+0x00, -0x02, -0x01, -0x02, -0x02, -0x02, -0x01, -0x01, -0x02, +0x03, +0x02, -0x02, +0x02, -0x01, -0x01, -0x01, +0x00, -0x06, -0x02, +0x04, -0x02, -0x02, +0x00, -0x08], + [+0x00, +0x00, +0x02, +0x03, -0x04, +0x01, +0x02, +0x01, +0x01, -0x02, -0x03, +0x01, -0x02, -0x04, +0x00, +0x01, +0x00, -0x05, -0x03, -0x02, +0x02, +0x02, +0x00, -0x08], + [+0x00, +0x00, +0x01, +0x03, -0x05, +0x03, +0x03, +0x00, +0x02, -0x02, -0x02, +0x01, -0x01, -0x05, +0x00, +0x00, +0x00, -0x06, -0x04, -0x02, +0x02, +0x03, +0x00, -0x08], + [+0x00, -0x01, +0x00, +0x00, -0x03, +0x00, +0x00, -0x01, +0x00, +0x00, -0x01, +0x00, +0x00, -0x02, +0x00, +0x00, +0x00, -0x04, -0x02, +0x00, +0x00, +0x00, -0x01, -0x08], + [-0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, +0x01]] + +PAM350 = [[+0x02, -0x01, +0x00, +0x01, -0x02, +0x00, +0x01, +0x02, -0x01, +0x00, -0x02, -0x01, -0x01, -0x04, +0x01, +0x01, +0x01, -0x07, -0x04, +0x00, +0x01, +0x00, +0x00, -0x0A], + [-0x01, +0x07, +0x01, -0x01, -0x04, +0x02, +0x00, -0x02, +0x02, -0x02, -0x03, +0x04, +0x00, -0x05, +0x00, +0x00, -0x01, +0x04, -0x05, -0x03, +0x00, +0x01, -0x01, -0x0A], + [+0x00, +0x01, +0x02, +0x02, -0x04, +0x01, +0x02, +0x01, +0x02, -0x02, -0x03, +0x01, -0x02, -0x04, +0x00, +0x01, +0x01, -0x05, -0x03, -0x02, +0x02, +0x02, +0x00, -0x0A], + [+0x01, -0x01, +0x02, +0x04, -0x06, +0x02, +0x04, +0x01, +0x01, -0x02, -0x04, +0x01, -0x03, -0x06, +0x00, +0x01, +0x00, -0x08, -0x05, -0x02, +0x03, +0x03, -0x01, -0x0A], + [-0x02, -0x04, -0x04, -0x06, +0x12, -0x06, -0x06, -0x04, -0x04, -0x03, -0x07, -0x06, -0x06, -0x05, -0x03, +0x00, -0x02, -0x0A, +0x01, -0x02, -0x05, -0x06, -0x03, -0x0A], + [+0x00, +0x02, +0x01, +0x02, -0x06, +0x04, +0x03, -0x01, +0x03, -0x02, -0x02, +0x01, -0x01, -0x05, +0x01, +0x00, +0x00, -0x05, -0x05, -0x02, +0x02, +0x03, +0x00, -0x0A], + [+0x01, +0x00, +0x02, +0x04, -0x06, +0x03, +0x04, +0x01, +0x01, -0x02, -0x04, +0x00, -0x02, -0x06, +0x00, +0x00, +0x00, -0x08, -0x05, -0x02, +0x03, +0x03, +0x00, -0x0A], + [+0x02, -0x02, +0x01, +0x01, -0x04, -0x01, +0x01, +0x05, -0x02, -0x02, -0x04, -0x01, -0x03, -0x06, +0x00, +0x01, +0x01, -0x08, -0x06, -0x01, +0x01, +0x00, -0x01, -0x0A], + [-0x01, +0x02, +0x02, +0x01, -0x04, +0x03, +0x01, -0x02, +0x07, -0x02, -0x02, +0x01, -0x02, -0x02, +0x00, -0x01, -0x01, -0x03, +0x00, -0x02, +0x01, +0x02, +0x00, -0x0A], + [+0x00, -0x02, -0x02, -0x02, -0x03, -0x02, -0x02, -0x02, -0x02, +0x05, +0x04, -0x02, +0x03, +0x02, -0x02, -0x01, +0x00, -0x06, +0x00, +0x04, -0x02, -0x02, +0x00, -0x0A], + [-0x02, -0x03, -0x03, -0x04, -0x07, -0x02, -0x04, -0x04, -0x02, +0x04, +0x08, -0x03, +0x05, +0x03, -0x03, -0x03, -0x02, -0x02, +0x00, +0x03, -0x04, -0x03, -0x01, -0x0A], + [-0x01, +0x04, +0x01, +0x01, -0x06, +0x01, +0x00, -0x01, +0x01, -0x02, -0x03, +0x05, +0x00, -0x06, -0x01, +0x00, +0x00, -0x04, -0x05, -0x02, +0x01, +0x01, -0x01, -0x0A], + [-0x01, +0x00, -0x02, -0x03, -0x06, -0x01, -0x02, -0x03, -0x02, +0x03, +0x05, +0x00, +0x06, +0x01, -0x02, -0x02, -0x01, -0x05, -0x02, +0x02, -0x02, -0x02, +0x00, -0x0A], + [-0x04, -0x05, -0x04, -0x06, -0x05, -0x05, -0x06, -0x06, -0x02, +0x02, +0x03, -0x06, +0x01, +0x0D, -0x05, -0x04, -0x03, +0x01, +0x0B, -0x01, -0x05, -0x06, -0x02, -0x0A], + [+0x01, +0x00, +0x00, +0x00, -0x03, +0x01, +0x00, +0x00, +0x00, -0x02, -0x03, -0x01, -0x02, -0x05, +0x06, +0x01, +0x01, -0x07, -0x06, -0x01, +0x00, +0x00, +0x00, -0x0A], + [+0x01, +0x00, +0x01, +0x01, +0x00, +0x00, +0x00, +0x01, -0x01, -0x01, -0x03, +0x00, -0x02, -0x04, +0x01, +0x01, +0x01, -0x03, -0x03, -0x01, +0x01, +0x00, +0x00, -0x0A], + [+0x01, -0x01, +0x01, +0x00, -0x02, +0x00, +0x00, +0x01, -0x01, +0x00, -0x02, +0x00, -0x01, -0x03, +0x01, +0x01, +0x02, -0x06, -0x03, +0x00, +0x00, +0x00, +0x00, -0x0A], + [-0x07, +0x04, -0x05, -0x08, -0x0A, -0x05, -0x08, -0x08, -0x03, -0x06, -0x02, -0x04, -0x05, +0x01, -0x07, -0x03, -0x06, +0x1B, +0x01, -0x07, -0x06, -0x07, -0x05, -0x0A], + [-0x04, -0x05, -0x03, -0x05, +0x01, -0x05, -0x05, -0x06, +0x00, +0x00, +0x00, -0x05, -0x02, +0x0B, -0x06, -0x03, -0x03, +0x01, +0x0E, -0x02, -0x04, -0x05, -0x02, -0x0A], + [+0x00, -0x03, -0x02, -0x02, -0x02, -0x02, -0x02, -0x01, -0x02, +0x04, +0x03, -0x02, +0x02, -0x01, -0x01, -0x01, +0x00, -0x07, -0x02, +0x05, -0x02, -0x02, +0x00, -0x0A], + [+0x01, +0x00, +0x02, +0x03, -0x05, +0x02, +0x03, +0x01, +0x01, -0x02, -0x04, +0x01, -0x02, -0x05, +0x00, +0x01, +0x00, -0x06, -0x04, -0x02, +0x03, +0x02, +0x00, -0x0A], + [+0x00, +0x01, +0x02, +0x03, -0x06, +0x03, +0x03, +0x00, +0x02, -0x02, -0x03, +0x01, -0x02, -0x06, +0x00, +0x00, +0x00, -0x07, -0x05, -0x02, +0x02, +0x03, +0x00, -0x0A], + [+0x00, -0x01, +0x00, -0x01, -0x03, +0x00, +0x00, -0x01, +0x00, +0x00, -0x01, -0x01, +0x00, -0x02, +0x00, +0x00, +0x00, -0x05, -0x02, +0x00, +0x00, +0x00, -0x01, -0x0A], + [-0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, +0x01]] + +PAM360 = [[+0x01, -0x01, +0x00, +0x01, -0x02, +0x00, +0x01, +0x02, -0x01, +0x00, -0x02, -0x01, -0x01, -0x04, +0x01, +0x01, +0x01, -0x07, -0x04, +0x00, +0x01, +0x00, +0x00, -0x09], + [-0x01, +0x06, +0x01, -0x01, -0x04, +0x02, +0x00, -0x02, +0x02, -0x02, -0x03, +0x04, +0x00, -0x05, +0x00, +0x00, +0x00, +0x04, -0x05, -0x02, +0x00, +0x01, -0x01, -0x09], + [+0x00, +0x01, +0x02, +0x02, -0x04, +0x01, +0x02, +0x01, +0x02, -0x02, -0x03, +0x01, -0x02, -0x04, +0x00, +0x01, +0x01, -0x05, -0x03, -0x02, +0x02, +0x02, +0x00, -0x09], + [+0x01, -0x01, +0x02, +0x04, -0x06, +0x02, +0x04, +0x01, +0x01, -0x02, -0x04, +0x01, -0x02, -0x06, +0x00, +0x01, +0x00, -0x08, -0x05, -0x02, +0x03, +0x03, +0x00, -0x09], + [-0x02, -0x04, -0x04, -0x06, +0x12, -0x06, -0x06, -0x04, -0x04, -0x03, -0x07, -0x06, -0x06, -0x04, -0x03, +0x00, -0x02, -0x09, +0x01, -0x02, -0x05, -0x06, -0x03, -0x09], + [+0x00, +0x02, +0x01, +0x02, -0x06, +0x03, +0x03, -0x01, +0x03, -0x02, -0x02, +0x01, -0x01, -0x05, +0x01, +0x00, +0x00, -0x05, -0x04, -0x02, +0x02, +0x03, +0x00, -0x09], + [+0x01, +0x00, +0x02, +0x04, -0x06, +0x03, +0x04, +0x01, +0x01, -0x02, -0x03, +0x00, -0x02, -0x06, +0x00, +0x00, +0x00, -0x08, -0x05, -0x02, +0x03, +0x03, +0x00, -0x09], + [+0x02, -0x02, +0x01, +0x01, -0x04, -0x01, +0x01, +0x05, -0x02, -0x02, -0x04, -0x01, -0x03, -0x06, +0x00, +0x01, +0x01, -0x08, -0x06, -0x01, +0x01, +0x00, -0x01, -0x09], + [-0x01, +0x02, +0x02, +0x01, -0x04, +0x03, +0x01, -0x02, +0x07, -0x02, -0x02, +0x01, -0x02, -0x02, +0x00, +0x00, -0x01, -0x03, +0x00, -0x02, +0x01, +0x02, +0x00, -0x09], + [+0x00, -0x02, -0x02, -0x02, -0x03, -0x02, -0x02, -0x02, -0x02, +0x04, +0x03, -0x02, +0x03, +0x02, -0x02, -0x01, +0x00, -0x06, +0x00, +0x04, -0x02, -0x02, +0x00, -0x09], + [-0x02, -0x03, -0x03, -0x04, -0x07, -0x02, -0x03, -0x04, -0x02, +0x03, +0x07, -0x03, +0x05, +0x03, -0x03, -0x03, -0x02, -0x02, +0x00, +0x03, -0x04, -0x03, -0x01, -0x09], + [-0x01, +0x04, +0x01, +0x01, -0x06, +0x01, +0x00, -0x01, +0x01, -0x02, -0x03, +0x05, +0x00, -0x06, -0x01, +0x00, +0x00, -0x04, -0x05, -0x02, +0x01, +0x01, -0x01, -0x09], + [-0x01, +0x00, -0x02, -0x02, -0x06, -0x01, -0x02, -0x03, -0x02, +0x03, +0x05, +0x00, +0x06, +0x01, -0x02, -0x02, -0x01, -0x04, -0x02, +0x02, -0x02, -0x02, +0x00, -0x09], + [-0x04, -0x05, -0x04, -0x06, -0x04, -0x05, -0x06, -0x06, -0x02, +0x02, +0x03, -0x06, +0x01, +0x0C, -0x05, -0x04, -0x03, +0x02, +0x0B, -0x01, -0x05, -0x05, -0x02, -0x09], + [+0x01, +0x00, +0x00, +0x00, -0x03, +0x01, +0x00, +0x00, +0x00, -0x02, -0x03, -0x01, -0x02, -0x05, +0x06, +0x01, +0x01, -0x06, -0x05, -0x01, +0x00, +0x00, +0x00, -0x09], + [+0x01, +0x00, +0x01, +0x01, +0x00, +0x00, +0x00, +0x01, +0x00, -0x01, -0x03, +0x00, -0x02, -0x04, +0x01, +0x01, +0x01, -0x03, -0x03, -0x01, +0x01, +0x00, +0x00, -0x09], + [+0x01, +0x00, +0x01, +0x00, -0x02, +0x00, +0x00, +0x01, -0x01, +0x00, -0x02, +0x00, -0x01, -0x03, +0x01, +0x01, +0x02, -0x06, -0x03, +0x00, +0x00, +0x00, +0x00, -0x09], + [-0x07, +0x04, -0x05, -0x08, -0x09, -0x05, -0x08, -0x08, -0x03, -0x06, -0x02, -0x04, -0x04, +0x02, -0x06, -0x03, -0x06, +0x1B, +0x01, -0x07, -0x06, -0x07, -0x04, -0x09], + [-0x04, -0x05, -0x03, -0x05, +0x01, -0x04, -0x05, -0x06, +0x00, +0x00, +0x00, -0x05, -0x02, +0x0B, -0x05, -0x03, -0x03, +0x01, +0x0E, -0x02, -0x04, -0x05, -0x02, -0x09], + [+0x00, -0x02, -0x02, -0x02, -0x02, -0x02, -0x02, -0x01, -0x02, +0x04, +0x03, -0x02, +0x02, -0x01, -0x01, -0x01, +0x00, -0x07, -0x02, +0x04, -0x02, -0x02, +0x00, -0x09], + [+0x01, +0x00, +0x02, +0x03, -0x05, +0x02, +0x03, +0x01, +0x01, -0x02, -0x04, +0x01, -0x02, -0x05, +0x00, +0x01, +0x00, -0x06, -0x04, -0x02, +0x02, +0x02, +0x00, -0x09], + [+0x00, +0x01, +0x02, +0x03, -0x06, +0x03, +0x03, +0x00, +0x02, -0x02, -0x03, +0x01, -0x02, -0x05, +0x00, +0x00, +0x00, -0x07, -0x05, -0x02, +0x02, +0x03, +0x00, -0x09], + [+0x00, -0x01, +0x00, +0x00, -0x03, +0x00, +0x00, -0x01, +0x00, +0x00, -0x01, -0x01, +0x00, -0x02, +0x00, +0x00, +0x00, -0x04, -0x02, +0x00, +0x00, +0x00, -0x01, -0x09], + [-0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, +0x01]] + +PAM370 = [[+0x01, -0x01, +0x00, +0x01, -0x02, +0x00, +0x01, +0x02, -0x01, +0x00, -0x02, -0x01, -0x01, -0x04, +0x01, +0x01, +0x01, -0x07, -0x04, +0x00, +0x01, +0x00, +0x00, -0x09], + [-0x01, +0x06, +0x01, +0x00, -0x04, +0x02, +0x00, -0x02, +0x02, -0x02, -0x03, +0x04, +0x00, -0x05, +0x00, +0x00, +0x00, +0x03, -0x04, -0x02, +0x00, +0x01, -0x01, -0x09], + [+0x00, +0x01, +0x02, +0x02, -0x04, +0x01, +0x02, +0x01, +0x02, -0x02, -0x03, +0x01, -0x02, -0x04, +0x00, +0x01, +0x00, -0x05, -0x03, -0x01, +0x02, +0x01, +0x00, -0x09], + [+0x01, +0x00, +0x02, +0x04, -0x05, +0x02, +0x03, +0x01, +0x01, -0x02, -0x04, +0x01, -0x02, -0x06, +0x00, +0x01, +0x00, -0x07, -0x05, -0x02, +0x03, +0x03, +0x00, -0x09], + [-0x02, -0x04, -0x04, -0x05, +0x12, -0x06, -0x06, -0x03, -0x04, -0x02, -0x06, -0x06, -0x06, -0x04, -0x03, +0x00, -0x02, -0x09, +0x01, -0x02, -0x05, -0x06, -0x03, -0x09], + [+0x00, +0x02, +0x01, +0x02, -0x06, +0x03, +0x02, -0x01, +0x03, -0x02, -0x02, +0x01, -0x01, -0x05, +0x01, +0x00, +0x00, -0x05, -0x04, -0x02, +0x02, +0x03, +0x00, -0x09], + [+0x01, +0x00, +0x02, +0x03, -0x06, +0x02, +0x03, +0x01, +0x01, -0x02, -0x03, +0x01, -0x02, -0x06, +0x00, +0x00, +0x00, -0x08, -0x05, -0x02, +0x03, +0x03, +0x00, -0x09], + [+0x02, -0x02, +0x01, +0x01, -0x03, -0x01, +0x01, +0x05, -0x02, -0x02, -0x04, -0x01, -0x03, -0x05, +0x00, +0x01, +0x01, -0x08, -0x06, -0x01, +0x01, +0x00, -0x01, -0x09], + [-0x01, +0x02, +0x02, +0x01, -0x04, +0x03, +0x01, -0x02, +0x06, -0x02, -0x02, +0x01, -0x02, -0x02, +0x00, +0x00, -0x01, -0x03, +0x00, -0x02, +0x01, +0x02, +0x00, -0x09], + [+0x00, -0x02, -0x02, -0x02, -0x02, -0x02, -0x02, -0x02, -0x02, +0x04, +0x03, -0x02, +0x03, +0x02, -0x02, -0x01, +0x00, -0x05, +0x00, +0x04, -0x02, -0x02, +0x00, -0x09], + [-0x02, -0x03, -0x03, -0x04, -0x06, -0x02, -0x03, -0x04, -0x02, +0x03, +0x07, -0x03, +0x05, +0x03, -0x03, -0x03, -0x01, -0x02, +0x00, +0x03, -0x03, -0x03, -0x01, -0x09], + [-0x01, +0x04, +0x01, +0x01, -0x06, +0x01, +0x01, -0x01, +0x01, -0x02, -0x03, +0x05, +0x00, -0x06, -0x01, +0x00, +0x00, -0x03, -0x05, -0x02, +0x01, +0x01, +0x00, -0x09], + [-0x01, +0x00, -0x02, -0x02, -0x06, -0x01, -0x02, -0x03, -0x02, +0x03, +0x05, +0x00, +0x05, +0x01, -0x02, -0x01, +0x00, -0x04, -0x02, +0x02, -0x02, -0x02, +0x00, -0x09], + [-0x04, -0x05, -0x04, -0x06, -0x04, -0x05, -0x06, -0x05, -0x02, +0x02, +0x03, -0x06, +0x01, +0x0C, -0x05, -0x04, -0x03, +0x02, +0x0B, +0x00, -0x05, -0x05, -0x02, -0x09], + [+0x01, +0x00, +0x00, +0x00, -0x03, +0x01, +0x00, +0x00, +0x00, -0x02, -0x03, -0x01, -0x02, -0x05, +0x06, +0x01, +0x01, -0x06, -0x05, -0x01, +0x00, +0x00, +0x00, -0x09], + [+0x01, +0x00, +0x01, +0x01, +0x00, +0x00, +0x00, +0x01, +0x00, -0x01, -0x03, +0x00, -0x01, -0x04, +0x01, +0x01, +0x01, -0x03, -0x03, -0x01, +0x01, +0x00, +0x00, -0x09], + [+0x01, +0x00, +0x00, +0x00, -0x02, +0x00, +0x00, +0x01, -0x01, +0x00, -0x01, +0x00, +0x00, -0x03, +0x01, +0x01, +0x02, -0x06, -0x03, +0x00, +0x00, +0x00, +0x00, -0x09], + [-0x07, +0x03, -0x05, -0x07, -0x09, -0x05, -0x08, -0x08, -0x03, -0x05, -0x02, -0x03, -0x04, +0x02, -0x06, -0x03, -0x06, +0x1B, +0x01, -0x07, -0x06, -0x06, -0x04, -0x09], + [-0x04, -0x04, -0x03, -0x05, +0x01, -0x04, -0x05, -0x06, +0x00, +0x00, +0x00, -0x05, -0x02, +0x0B, -0x05, -0x03, -0x03, +0x01, +0x0E, -0x02, -0x04, -0x05, -0x02, -0x09], + [+0x00, -0x02, -0x01, -0x02, -0x02, -0x02, -0x02, -0x01, -0x02, +0x04, +0x03, -0x02, +0x02, +0x00, -0x01, -0x01, +0x00, -0x07, -0x02, +0x04, -0x02, -0x02, +0x00, -0x09], + [+0x01, +0x00, +0x02, +0x03, -0x05, +0x02, +0x03, +0x01, +0x01, -0x02, -0x03, +0x01, -0x02, -0x05, +0x00, +0x01, +0x00, -0x06, -0x04, -0x02, +0x02, +0x02, +0x00, -0x09], + [+0x00, +0x01, +0x01, +0x03, -0x06, +0x03, +0x03, +0x00, +0x02, -0x02, -0x03, +0x01, -0x02, -0x05, +0x00, +0x00, +0x00, -0x06, -0x05, -0x02, +0x02, +0x03, +0x00, -0x09], + [+0x00, -0x01, +0x00, +0x00, -0x03, +0x00, +0x00, -0x01, +0x00, +0x00, -0x01, +0x00, +0x00, -0x02, +0x00, +0x00, +0x00, -0x04, -0x02, +0x00, +0x00, +0x00, -0x01, -0x09], + [-0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, +0x01]] + +PAM380 = [[+0x01, -0x01, +0x00, +0x01, -0x02, +0x00, +0x01, +0x02, -0x01, +0x00, -0x02, -0x01, -0x01, -0x04, +0x01, +0x01, +0x01, -0x06, -0x04, +0x00, +0x01, +0x00, +0x00, -0x09], + [-0x01, +0x06, +0x01, +0x00, -0x04, +0x02, +0x00, -0x02, +0x02, -0x02, -0x03, +0x04, +0x00, -0x05, +0x00, +0x00, +0x00, +0x03, -0x04, -0x02, +0x00, +0x01, +0x00, -0x09], + [+0x00, +0x01, +0x01, +0x02, -0x04, +0x01, +0x02, +0x01, +0x01, -0x02, -0x03, +0x01, -0x01, -0x04, +0x00, +0x01, +0x00, -0x05, -0x03, -0x01, +0x02, +0x01, +0x00, -0x09], + [+0x01, +0x00, +0x02, +0x03, -0x05, +0x02, +0x03, +0x01, +0x01, -0x02, -0x04, +0x01, -0x02, -0x06, +0x00, +0x01, +0x00, -0x07, -0x05, -0x02, +0x03, +0x03, +0x00, -0x09], + [-0x02, -0x04, -0x04, -0x05, +0x11, -0x05, -0x05, -0x03, -0x04, -0x02, -0x06, -0x06, -0x05, -0x04, -0x03, +0x00, -0x02, -0x09, +0x01, -0x02, -0x04, -0x05, -0x03, -0x09], + [+0x00, +0x02, +0x01, +0x02, -0x05, +0x03, +0x02, -0x01, +0x03, -0x02, -0x02, +0x01, -0x01, -0x05, +0x01, +0x00, +0x00, -0x05, -0x04, -0x02, +0x02, +0x03, +0x00, -0x09], + [+0x01, +0x00, +0x02, +0x03, -0x05, +0x02, +0x03, +0x01, +0x01, -0x02, -0x03, +0x01, -0x02, -0x05, +0x00, +0x00, +0x00, -0x07, -0x05, -0x02, +0x03, +0x03, +0x00, -0x09], + [+0x02, -0x02, +0x01, +0x01, -0x03, -0x01, +0x01, +0x05, -0x01, -0x02, -0x04, -0x01, -0x02, -0x05, +0x00, +0x01, +0x01, -0x08, -0x05, -0x01, +0x01, +0x00, +0x00, -0x09], + [-0x01, +0x02, +0x01, +0x01, -0x04, +0x03, +0x01, -0x01, +0x06, -0x02, -0x02, +0x01, -0x02, -0x02, +0x00, +0x00, -0x01, -0x03, +0x00, -0x02, +0x01, +0x02, +0x00, -0x09], + [+0x00, -0x02, -0x02, -0x02, -0x02, -0x02, -0x02, -0x02, -0x02, +0x04, +0x03, -0x02, +0x03, +0x02, -0x02, -0x01, +0x00, -0x05, +0x00, +0x04, -0x02, -0x02, +0x00, -0x09], + [-0x02, -0x03, -0x03, -0x04, -0x06, -0x02, -0x03, -0x04, -0x02, +0x03, +0x07, -0x03, +0x04, +0x03, -0x02, -0x03, -0x01, -0x02, +0x00, +0x03, -0x03, -0x03, -0x01, -0x09], + [-0x01, +0x04, +0x01, +0x01, -0x06, +0x01, +0x01, -0x01, +0x01, -0x02, -0x03, +0x05, +0x00, -0x05, +0x00, +0x00, +0x00, -0x03, -0x05, -0x02, +0x01, +0x01, +0x00, -0x09], + [-0x01, +0x00, -0x01, -0x02, -0x05, -0x01, -0x02, -0x02, -0x02, +0x03, +0x04, +0x00, +0x05, +0x01, -0x02, -0x01, +0x00, -0x04, -0x02, +0x02, -0x02, -0x01, +0x00, -0x09], + [-0x04, -0x05, -0x04, -0x06, -0x04, -0x05, -0x05, -0x05, -0x02, +0x02, +0x03, -0x05, +0x01, +0x0C, -0x05, -0x04, -0x03, +0x02, +0x0A, +0x00, -0x05, -0x05, -0x02, -0x09], + [+0x01, +0x00, +0x00, +0x00, -0x03, +0x01, +0x00, +0x00, +0x00, -0x02, -0x02, +0x00, -0x02, -0x05, +0x05, +0x01, +0x01, -0x06, -0x05, -0x01, +0x00, +0x00, +0x00, -0x09], + [+0x01, +0x00, +0x01, +0x01, +0x00, +0x00, +0x00, +0x01, +0x00, -0x01, -0x03, +0x00, -0x01, -0x04, +0x01, +0x01, +0x01, -0x03, -0x03, -0x01, +0x01, +0x00, +0x00, -0x09], + [+0x01, +0x00, +0x00, +0x00, -0x02, +0x00, +0x00, +0x01, -0x01, +0x00, -0x01, +0x00, +0x00, -0x03, +0x01, +0x01, +0x02, -0x06, -0x03, +0x00, +0x00, +0x00, +0x00, -0x09], + [-0x06, +0x03, -0x05, -0x07, -0x09, -0x05, -0x07, -0x08, -0x03, -0x05, -0x02, -0x03, -0x04, +0x02, -0x06, -0x03, -0x06, +0x1A, +0x01, -0x06, -0x06, -0x06, -0x04, -0x09], + [-0x04, -0x04, -0x03, -0x05, +0x01, -0x04, -0x05, -0x05, +0x00, +0x00, +0x00, -0x05, -0x02, +0x0A, -0x05, -0x03, -0x03, +0x01, +0x0D, -0x02, -0x04, -0x04, -0x02, -0x09], + [+0x00, -0x02, -0x01, -0x02, -0x02, -0x02, -0x02, -0x01, -0x02, +0x04, +0x03, -0x02, +0x02, +0x00, -0x01, -0x01, +0x00, -0x06, -0x02, +0x04, -0x02, -0x02, +0x00, -0x09], + [+0x01, +0x00, +0x02, +0x03, -0x04, +0x02, +0x03, +0x01, +0x01, -0x02, -0x03, +0x01, -0x02, -0x05, +0x00, +0x01, +0x00, -0x06, -0x04, -0x02, +0x02, +0x02, +0x00, -0x09], + [+0x00, +0x01, +0x01, +0x03, -0x05, +0x03, +0x03, +0x00, +0x02, -0x02, -0x03, +0x01, -0x01, -0x05, +0x00, +0x00, +0x00, -0x06, -0x04, -0x02, +0x02, +0x03, +0x00, -0x09], + [+0x00, +0x00, +0x00, +0x00, -0x03, +0x00, +0x00, +0x00, +0x00, +0x00, -0x01, +0x00, +0x00, -0x02, +0x00, +0x00, +0x00, -0x04, -0x02, +0x00, +0x00, +0x00, -0x01, -0x09], + [-0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, +0x01]] + +PAM390 = [[+0x01, -0x01, +0x00, +0x01, -0x02, +0x00, +0x01, +0x01, -0x01, +0x00, -0x02, -0x01, -0x01, -0x03, +0x01, +0x01, +0x01, -0x06, -0x04, +0x00, +0x01, +0x00, +0x00, -0x09], + [-0x01, +0x06, +0x01, +0x00, -0x04, +0x01, +0x00, -0x02, +0x02, -0x02, -0x03, +0x04, +0x00, -0x05, +0x00, +0x00, +0x00, +0x03, -0x04, -0x02, +0x00, +0x01, +0x00, -0x09], + [+0x00, +0x01, +0x01, +0x02, -0x04, +0x01, +0x02, +0x01, +0x01, -0x02, -0x03, +0x01, -0x01, -0x04, +0x00, +0x01, +0x00, -0x04, -0x03, -0x01, +0x02, +0x01, +0x00, -0x09], + [+0x01, +0x00, +0x02, +0x03, -0x05, +0x02, +0x03, +0x01, +0x01, -0x02, -0x04, +0x01, -0x02, -0x05, +0x00, +0x01, +0x00, -0x07, -0x05, -0x02, +0x03, +0x03, +0x00, -0x09], + [-0x02, -0x04, -0x04, -0x05, +0x11, -0x05, -0x05, -0x03, -0x04, -0x02, -0x06, -0x05, -0x05, -0x04, -0x03, +0x00, -0x02, -0x09, +0x01, -0x02, -0x04, -0x05, -0x03, -0x09], + [+0x00, +0x01, +0x01, +0x02, -0x05, +0x03, +0x02, +0x00, +0x03, -0x02, -0x02, +0x01, -0x01, -0x04, +0x00, +0x00, +0x00, -0x05, -0x04, -0x01, +0x02, +0x03, +0x00, -0x09], + [+0x01, +0x00, +0x02, +0x03, -0x05, +0x02, +0x03, +0x01, +0x01, -0x02, -0x03, +0x01, -0x02, -0x05, +0x00, +0x00, +0x00, -0x07, -0x05, -0x01, +0x02, +0x03, +0x00, -0x09], + [+0x01, -0x02, +0x01, +0x01, -0x03, +0x00, +0x01, +0x05, -0x01, -0x02, -0x04, -0x01, -0x02, -0x05, +0x00, +0x01, +0x01, -0x07, -0x05, -0x01, +0x01, +0x00, +0x00, -0x09], + [-0x01, +0x02, +0x01, +0x01, -0x04, +0x03, +0x01, -0x01, +0x06, -0x02, -0x02, +0x01, -0x02, -0x02, +0x00, +0x00, -0x01, -0x03, +0x00, -0x02, +0x01, +0x02, +0x00, -0x09], + [+0x00, -0x02, -0x02, -0x02, -0x02, -0x02, -0x02, -0x02, -0x02, +0x04, +0x03, -0x02, +0x03, +0x02, -0x01, -0x01, +0x00, -0x05, +0x00, +0x04, -0x02, -0x02, +0x00, -0x09], + [-0x02, -0x03, -0x03, -0x04, -0x06, -0x02, -0x03, -0x04, -0x02, +0x03, +0x07, -0x03, +0x04, +0x03, -0x02, -0x02, -0x01, -0x02, +0x00, +0x03, -0x03, -0x02, -0x01, -0x09], + [-0x01, +0x04, +0x01, +0x01, -0x05, +0x01, +0x01, -0x01, +0x01, -0x02, -0x03, +0x04, +0x00, -0x05, +0x00, +0x00, +0x00, -0x03, -0x05, -0x02, +0x01, +0x01, +0x00, -0x09], + [-0x01, +0x00, -0x01, -0x02, -0x05, -0x01, -0x02, -0x02, -0x02, +0x03, +0x04, +0x00, +0x05, +0x01, -0x02, -0x01, +0x00, -0x04, -0x01, +0x02, -0x02, -0x01, +0x00, -0x09], + [-0x03, -0x05, -0x04, -0x05, -0x04, -0x04, -0x05, -0x05, -0x02, +0x02, +0x03, -0x05, +0x01, +0x0C, -0x05, -0x03, -0x03, +0x02, +0x0A, +0x00, -0x05, -0x05, -0x02, -0x09], + [+0x01, +0x00, +0x00, +0x00, -0x03, +0x00, +0x00, +0x00, +0x00, -0x01, -0x02, +0x00, -0x02, -0x05, +0x05, +0x01, +0x01, -0x06, -0x05, -0x01, +0x00, +0x00, +0x00, -0x09], + [+0x01, +0x00, +0x01, +0x01, +0x00, +0x00, +0x00, +0x01, +0x00, -0x01, -0x02, +0x00, -0x01, -0x03, +0x01, +0x01, +0x01, -0x03, -0x03, -0x01, +0x01, +0x00, +0x00, -0x09], + [+0x01, +0x00, +0x00, +0x00, -0x02, +0x00, +0x00, +0x01, -0x01, +0x00, -0x01, +0x00, +0x00, -0x03, +0x01, +0x01, +0x01, -0x05, -0x03, +0x00, +0x00, +0x00, +0x00, -0x09], + [-0x06, +0x03, -0x04, -0x07, -0x09, -0x05, -0x07, -0x07, -0x03, -0x05, -0x02, -0x03, -0x04, +0x02, -0x06, -0x03, -0x05, +0x1A, +0x01, -0x06, -0x06, -0x06, -0x04, -0x09], + [-0x04, -0x04, -0x03, -0x05, +0x01, -0x04, -0x05, -0x05, +0x00, +0x00, +0x00, -0x05, -0x01, +0x0A, -0x05, -0x03, -0x03, +0x01, +0x0D, -0x02, -0x04, -0x04, -0x02, -0x09], + [+0x00, -0x02, -0x01, -0x02, -0x02, -0x01, -0x01, -0x01, -0x02, +0x04, +0x03, -0x02, +0x02, +0x00, -0x01, -0x01, +0x00, -0x06, -0x02, +0x04, -0x02, -0x01, +0x00, -0x09], + [+0x01, +0x00, +0x02, +0x03, -0x04, +0x02, +0x02, +0x01, +0x01, -0x02, -0x03, +0x01, -0x02, -0x05, +0x00, +0x01, +0x00, -0x06, -0x04, -0x02, +0x02, +0x02, +0x00, -0x09], + [+0x00, +0x01, +0x01, +0x03, -0x05, +0x03, +0x03, +0x00, +0x02, -0x02, -0x02, +0x01, -0x01, -0x05, +0x00, +0x00, +0x00, -0x06, -0x04, -0x01, +0x02, +0x03, +0x00, -0x09], + [+0x00, +0x00, +0x00, +0x00, -0x03, +0x00, +0x00, +0x00, +0x00, +0x00, -0x01, +0x00, +0x00, -0x02, +0x00, +0x00, +0x00, -0x04, -0x02, +0x00, +0x00, +0x00, -0x01, -0x09], + [-0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, +0x01]] + +PAM400 = [[+0x01, -0x01, +0x00, +0x01, -0x02, +0x00, +0x01, +0x01, -0x01, +0x00, -0x02, -0x01, -0x01, -0x03, +0x01, +0x01, +0x01, -0x06, -0x03, +0x00, +0x01, +0x00, +0x00, -0x08], + [-0x01, +0x05, +0x01, +0x00, -0x04, +0x01, +0x00, -0x02, +0x02, -0x02, -0x03, +0x04, +0x00, -0x04, +0x00, +0x00, +0x00, +0x03, -0x04, -0x02, +0x00, +0x01, +0x00, -0x08], + [+0x00, +0x01, +0x01, +0x02, -0x03, +0x01, +0x02, +0x01, +0x01, -0x01, -0x03, +0x01, -0x01, -0x03, +0x00, +0x01, +0x00, -0x04, -0x03, -0x01, +0x02, +0x01, +0x00, -0x08], + [+0x01, +0x00, +0x02, +0x03, -0x05, +0x02, +0x03, +0x01, +0x01, -0x02, -0x03, +0x01, -0x02, -0x05, +0x00, +0x01, +0x00, -0x07, -0x04, -0x02, +0x02, +0x02, +0x00, -0x08], + [-0x02, -0x04, -0x03, -0x05, +0x11, -0x05, -0x05, -0x03, -0x03, -0x02, -0x06, -0x05, -0x05, -0x04, -0x02, +0x00, -0x02, -0x08, +0x01, -0x02, -0x04, -0x05, -0x03, -0x08], + [+0x00, +0x01, +0x01, +0x02, -0x05, +0x03, +0x02, +0x00, +0x03, -0x02, -0x02, +0x01, -0x01, -0x04, +0x00, +0x00, +0x00, -0x05, -0x04, -0x01, +0x02, +0x02, +0x00, -0x08], + [+0x01, +0x00, +0x02, +0x03, -0x05, +0x02, +0x03, +0x01, +0x01, -0x02, -0x03, +0x01, -0x02, -0x05, +0x00, +0x00, +0x00, -0x07, -0x04, -0x01, +0x02, +0x03, +0x00, -0x08], + [+0x01, -0x02, +0x01, +0x01, -0x03, +0x00, +0x01, +0x04, -0x01, -0x02, -0x03, -0x01, -0x02, -0x05, +0x00, +0x01, +0x01, -0x07, -0x05, -0x01, +0x01, +0x00, +0x00, -0x08], + [-0x01, +0x02, +0x01, +0x01, -0x03, +0x03, +0x01, -0x01, +0x05, -0x02, -0x02, +0x01, -0x01, -0x02, +0x00, +0x00, -0x01, -0x02, +0x00, -0x02, +0x01, +0x02, +0x00, -0x08], + [+0x00, -0x02, -0x01, -0x02, -0x02, -0x02, -0x02, -0x02, -0x02, +0x04, +0x03, -0x02, +0x02, +0x02, -0x01, -0x01, +0x00, -0x05, +0x00, +0x03, -0x02, -0x02, +0x00, -0x08], + [-0x02, -0x03, -0x03, -0x03, -0x06, -0x02, -0x03, -0x03, -0x02, +0x03, +0x07, -0x02, +0x04, +0x03, -0x02, -0x02, -0x01, -0x02, +0x00, +0x03, -0x03, -0x02, -0x01, -0x08], + [-0x01, +0x04, +0x01, +0x01, -0x05, +0x01, +0x01, -0x01, +0x01, -0x02, -0x02, +0x04, +0x00, -0x05, +0x00, +0x00, +0x00, -0x03, -0x04, -0x02, +0x01, +0x01, +0x00, -0x08], + [-0x01, +0x00, -0x01, -0x02, -0x05, -0x01, -0x02, -0x02, -0x01, +0x02, +0x04, +0x00, +0x05, +0x01, -0x01, -0x01, +0x00, -0x04, -0x01, +0x02, -0x02, -0x01, +0x00, -0x08], + [-0x03, -0x04, -0x03, -0x05, -0x04, -0x04, -0x05, -0x05, -0x02, +0x02, +0x03, -0x05, +0x01, +0x0B, -0x04, -0x03, -0x03, +0x02, +0x0A, +0x00, -0x04, -0x05, -0x02, -0x08], + [+0x01, +0x00, +0x00, +0x00, -0x02, +0x00, +0x00, +0x00, +0x00, -0x01, -0x02, +0x00, -0x01, -0x04, +0x05, +0x01, +0x01, -0x06, -0x05, -0x01, +0x00, +0x00, +0x00, -0x08], + [+0x01, +0x00, +0x01, +0x01, +0x00, +0x00, +0x00, +0x01, +0x00, -0x01, -0x02, +0x00, -0x01, -0x03, +0x01, +0x01, +0x01, -0x03, -0x03, -0x01, +0x01, +0x00, +0x00, -0x08], + [+0x01, +0x00, +0x00, +0x00, -0x02, +0x00, +0x00, +0x01, -0x01, +0x00, -0x01, +0x00, +0x00, -0x03, +0x01, +0x01, +0x01, -0x05, -0x03, +0x00, +0x00, +0x00, +0x00, -0x08], + [-0x06, +0x03, -0x04, -0x07, -0x08, -0x05, -0x07, -0x07, -0x02, -0x05, -0x02, -0x03, -0x04, +0x02, -0x06, -0x03, -0x05, +0x1A, +0x01, -0x06, -0x05, -0x06, -0x04, -0x08], + [-0x03, -0x04, -0x03, -0x04, +0x01, -0x04, -0x04, -0x05, +0x00, +0x00, +0x00, -0x04, -0x01, +0x0A, -0x05, -0x03, -0x03, +0x01, +0x0D, -0x02, -0x03, -0x04, -0x02, -0x08], + [+0x00, -0x02, -0x01, -0x02, -0x02, -0x01, -0x01, -0x01, -0x02, +0x03, +0x03, -0x02, +0x02, +0x00, -0x01, -0x01, +0x00, -0x06, -0x02, +0x04, -0x01, -0x01, +0x00, -0x08], + [+0x01, +0x00, +0x02, +0x02, -0x04, +0x02, +0x02, +0x01, +0x01, -0x02, -0x03, +0x01, -0x02, -0x04, +0x00, +0x01, +0x00, -0x05, -0x03, -0x01, +0x02, +0x02, +0x00, -0x08], + [+0x00, +0x01, +0x01, +0x02, -0x05, +0x02, +0x03, +0x00, +0x02, -0x02, -0x02, +0x01, -0x01, -0x05, +0x00, +0x00, +0x00, -0x06, -0x04, -0x01, +0x02, +0x03, +0x00, -0x08], + [+0x00, +0x00, +0x00, +0x00, -0x03, +0x00, +0x00, +0x00, +0x00, +0x00, -0x01, +0x00, +0x00, -0x02, +0x00, +0x00, +0x00, -0x04, -0x02, +0x00, +0x00, +0x00, -0x01, -0x08], + [-0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, -0x08, +0x01]] + +PAM410 = [[+0x01, -0x01, +0x00, +0x01, -0x02, +0x00, +0x01, +0x02, -0x01, +0x00, -0x02, -0x01, -0x01, -0x04, +0x01, +0x01, +0x01, -0x07, -0x04, +0x00, +0x01, +0x00, +0x00, -0x0A], + [-0x01, +0x06, +0x01, +0x00, -0x04, +0x02, +0x00, -0x02, +0x02, -0x02, -0x03, +0x04, +0x00, -0x05, +0x00, +0x00, +0x00, +0x04, -0x05, -0x02, +0x00, +0x01, +0x00, -0x0A], + [+0x00, +0x01, +0x01, +0x02, -0x04, +0x01, +0x02, +0x01, +0x01, -0x02, -0x03, +0x01, -0x02, -0x04, +0x00, +0x01, +0x01, -0x05, -0x03, -0x01, +0x02, +0x02, +0x00, -0x0A], + [+0x01, +0x00, +0x02, +0x03, -0x06, +0x02, +0x03, +0x01, +0x01, -0x02, -0x04, +0x01, -0x02, -0x06, +0x00, +0x01, +0x00, -0x08, -0x05, -0x02, +0x03, +0x03, +0x00, -0x0A], + [-0x02, -0x04, -0x04, -0x06, +0x14, -0x06, -0x06, -0x04, -0x04, -0x03, -0x07, -0x06, -0x06, -0x04, -0x03, +0x00, -0x02, -0x0A, +0x01, -0x02, -0x05, -0x06, -0x03, -0x0A], + [+0x00, +0x02, +0x01, +0x02, -0x06, +0x03, +0x02, +0x00, +0x03, -0x02, -0x02, +0x01, -0x01, -0x05, +0x01, +0x00, +0x00, -0x05, -0x04, -0x02, +0x02, +0x03, +0x00, -0x0A], + [+0x01, +0x00, +0x02, +0x03, -0x06, +0x02, +0x03, +0x01, +0x01, -0x02, -0x03, +0x01, -0x02, -0x06, +0x00, +0x01, +0x00, -0x08, -0x05, -0x02, +0x03, +0x03, +0x00, -0x0A], + [+0x02, -0x02, +0x01, +0x01, -0x04, +0x00, +0x01, +0x05, -0x01, -0x02, -0x04, -0x01, -0x03, -0x06, +0x00, +0x01, +0x01, -0x08, -0x06, -0x01, +0x01, +0x00, +0x00, -0x0A], + [-0x01, +0x02, +0x01, +0x01, -0x04, +0x03, +0x01, -0x01, +0x06, -0x02, -0x02, +0x01, -0x02, -0x02, +0x00, +0x00, -0x01, -0x03, +0x00, -0x02, +0x01, +0x02, +0x00, -0x0A], + [+0x00, -0x02, -0x02, -0x02, -0x03, -0x02, -0x02, -0x02, -0x02, +0x04, +0x04, -0x02, +0x03, +0x02, -0x02, -0x01, +0x00, -0x06, +0x00, +0x04, -0x02, -0x02, +0x00, -0x0A], + [-0x02, -0x03, -0x03, -0x04, -0x07, -0x02, -0x03, -0x04, -0x02, +0x04, +0x08, -0x03, +0x05, +0x04, -0x03, -0x03, -0x01, -0x02, +0x01, +0x03, -0x03, -0x03, -0x01, -0x0A], + [-0x01, +0x04, +0x01, +0x01, -0x06, +0x01, +0x01, -0x01, +0x01, -0x02, -0x03, +0x05, +0x00, -0x06, +0x00, +0x00, +0x00, -0x03, -0x05, -0x02, +0x01, +0x01, +0x00, -0x0A], + [-0x01, +0x00, -0x02, -0x02, -0x06, -0x01, -0x02, -0x03, -0x02, +0x03, +0x05, +0x00, +0x05, +0x01, -0x02, -0x01, +0x00, -0x04, -0x02, +0x02, -0x02, -0x02, +0x00, -0x0A], + [-0x04, -0x05, -0x04, -0x06, -0x04, -0x05, -0x06, -0x06, -0x02, +0x02, +0x04, -0x06, +0x01, +0x0E, -0x05, -0x04, -0x03, +0x02, +0x0C, +0x00, -0x05, -0x05, -0x02, -0x0A], + [+0x01, +0x00, +0x00, +0x00, -0x03, +0x01, +0x00, +0x00, +0x00, -0x02, -0x03, +0x00, -0x02, -0x05, +0x06, +0x01, +0x01, -0x07, -0x05, -0x01, +0x00, +0x00, +0x00, -0x0A], + [+0x01, +0x00, +0x01, +0x01, +0x00, +0x00, +0x01, +0x01, +0x00, -0x01, -0x03, +0x00, -0x01, -0x04, +0x01, +0x01, +0x01, -0x03, -0x03, -0x01, +0x01, +0x00, +0x00, -0x0A], + [+0x01, +0x00, +0x01, +0x00, -0x02, +0x00, +0x00, +0x01, -0x01, +0x00, -0x01, +0x00, +0x00, -0x03, +0x01, +0x01, +0x02, -0x06, -0x03, +0x00, +0x00, +0x00, +0x00, -0x0A], + [-0x07, +0x04, -0x05, -0x08, -0x0A, -0x05, -0x08, -0x08, -0x03, -0x06, -0x02, -0x03, -0x04, +0x02, -0x07, -0x03, -0x06, +0x1F, +0x02, -0x07, -0x06, -0x07, -0x04, -0x0A], + [-0x04, -0x05, -0x03, -0x05, +0x01, -0x04, -0x05, -0x06, +0x00, +0x00, +0x01, -0x05, -0x02, +0x0C, -0x05, -0x03, -0x03, +0x02, +0x0F, -0x02, -0x04, -0x05, -0x02, -0x0A], + [+0x00, -0x02, -0x01, -0x02, -0x02, -0x02, -0x02, -0x01, -0x02, +0x04, +0x03, -0x02, +0x02, +0x00, -0x01, -0x01, +0x00, -0x07, -0x02, +0x04, -0x02, -0x02, +0x00, -0x0A], + [+0x01, +0x00, +0x02, +0x03, -0x05, +0x02, +0x03, +0x01, +0x01, -0x02, -0x03, +0x01, -0x02, -0x05, +0x00, +0x01, +0x00, -0x06, -0x04, -0x02, +0x02, +0x02, +0x00, -0x0A], + [+0x00, +0x01, +0x02, +0x03, -0x06, +0x03, +0x03, +0x00, +0x02, -0x02, -0x03, +0x01, -0x02, -0x05, +0x00, +0x00, +0x00, -0x07, -0x05, -0x02, +0x02, +0x03, +0x00, -0x0A], + [+0x00, +0x00, +0x00, +0x00, -0x03, +0x00, +0x00, +0x00, +0x00, +0x00, -0x01, +0x00, +0x00, -0x02, +0x00, +0x00, +0x00, -0x04, -0x02, +0x00, +0x00, +0x00, -0x01, -0x0A], + [-0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, +0x01]] + +PAM420 = [[+0x01, -0x01, +0x00, +0x01, -0x02, +0x00, +0x01, +0x02, -0x01, +0x00, -0x02, +0x00, -0x01, -0x04, +0x01, +0x01, +0x01, -0x07, -0x04, +0x00, +0x01, +0x00, +0x00, -0x0A], + [-0x01, +0x06, +0x01, +0x00, -0x04, +0x02, +0x00, -0x02, +0x02, -0x02, -0x03, +0x04, +0x00, -0x05, +0x00, +0x00, +0x00, +0x04, -0x05, -0x02, +0x00, +0x01, +0x00, -0x0A], + [+0x00, +0x01, +0x01, +0x02, -0x04, +0x01, +0x02, +0x01, +0x01, -0x02, -0x03, +0x01, -0x01, -0x04, +0x00, +0x01, +0x00, -0x05, -0x03, -0x01, +0x02, +0x02, +0x00, -0x0A], + [+0x01, +0x00, +0x02, +0x03, -0x05, +0x02, +0x03, +0x01, +0x01, -0x02, -0x04, +0x01, -0x02, -0x06, +0x00, +0x01, +0x00, -0x08, -0x05, -0x02, +0x03, +0x03, +0x00, -0x0A], + [-0x02, -0x04, -0x04, -0x05, +0x14, -0x06, -0x06, -0x03, -0x04, -0x03, -0x07, -0x06, -0x06, -0x04, -0x03, +0x00, -0x02, -0x0A, +0x01, -0x02, -0x05, -0x06, -0x03, -0x0A], + [+0x00, +0x02, +0x01, +0x02, -0x06, +0x03, +0x02, +0x00, +0x03, -0x02, -0x02, +0x01, -0x01, -0x05, +0x01, +0x00, +0x00, -0x05, -0x04, -0x02, +0x02, +0x03, +0x00, -0x0A], + [+0x01, +0x00, +0x02, +0x03, -0x06, +0x02, +0x03, +0x01, +0x01, -0x02, -0x03, +0x01, -0x02, -0x06, +0x00, +0x01, +0x00, -0x08, -0x05, -0x02, +0x03, +0x03, +0x00, -0x0A], + [+0x02, -0x02, +0x01, +0x01, -0x03, +0x00, +0x01, +0x05, -0x01, -0x02, -0x04, -0x01, -0x02, -0x06, +0x00, +0x01, +0x01, -0x08, -0x06, -0x01, +0x01, +0x00, +0x00, -0x0A], + [-0x01, +0x02, +0x01, +0x01, -0x04, +0x03, +0x01, -0x01, +0x06, -0x02, -0x02, +0x01, -0x02, -0x02, +0x00, +0x00, -0x01, -0x03, +0x00, -0x02, +0x01, +0x02, +0x00, -0x0A], + [+0x00, -0x02, -0x02, -0x02, -0x03, -0x02, -0x02, -0x02, -0x02, +0x04, +0x04, -0x02, +0x03, +0x02, -0x02, -0x01, +0x00, -0x06, +0x00, +0x04, -0x02, -0x02, +0x00, -0x0A], + [-0x02, -0x03, -0x03, -0x04, -0x07, -0x02, -0x03, -0x04, -0x02, +0x04, +0x07, -0x03, +0x05, +0x04, -0x02, -0x03, -0x01, -0x02, +0x01, +0x03, -0x03, -0x03, -0x01, -0x0A], + [+0x00, +0x04, +0x01, +0x01, -0x06, +0x01, +0x01, -0x01, +0x01, -0x02, -0x03, +0x05, +0x00, -0x06, +0x00, +0x00, +0x00, -0x03, -0x05, -0x02, +0x01, +0x01, +0x00, -0x0A], + [-0x01, +0x00, -0x01, -0x02, -0x06, -0x01, -0x02, -0x02, -0x02, +0x03, +0x05, +0x00, +0x05, +0x01, -0x02, -0x01, +0x00, -0x04, -0x01, +0x02, -0x02, -0x01, +0x00, -0x0A], + [-0x04, -0x05, -0x04, -0x06, -0x04, -0x05, -0x06, -0x06, -0x02, +0x02, +0x04, -0x06, +0x01, +0x0D, -0x05, -0x04, -0x03, +0x02, +0x0C, +0x00, -0x05, -0x05, -0x02, -0x0A], + [+0x01, +0x00, +0x00, +0x00, -0x03, +0x01, +0x00, +0x00, +0x00, -0x02, -0x02, +0x00, -0x02, -0x05, +0x05, +0x01, +0x01, -0x06, -0x05, -0x01, +0x00, +0x00, +0x00, -0x0A], + [+0x01, +0x00, +0x01, +0x01, +0x00, +0x00, +0x01, +0x01, +0x00, -0x01, -0x03, +0x00, -0x01, -0x04, +0x01, +0x01, +0x01, -0x03, -0x03, -0x01, +0x01, +0x00, +0x00, -0x0A], + [+0x01, +0x00, +0x00, +0x00, -0x02, +0x00, +0x00, +0x01, -0x01, +0x00, -0x01, +0x00, +0x00, -0x03, +0x01, +0x01, +0x01, -0x06, -0x03, +0x00, +0x00, +0x00, +0x00, -0x0A], + [-0x07, +0x04, -0x05, -0x08, -0x0A, -0x05, -0x08, -0x08, -0x03, -0x06, -0x02, -0x03, -0x04, +0x02, -0x06, -0x03, -0x06, +0x1F, +0x02, -0x07, -0x06, -0x07, -0x04, -0x0A], + [-0x04, -0x05, -0x03, -0x05, +0x01, -0x04, -0x05, -0x06, +0x00, +0x00, +0x01, -0x05, -0x01, +0x0C, -0x05, -0x03, -0x03, +0x02, +0x0F, -0x02, -0x04, -0x05, -0x02, -0x0A], + [+0x00, -0x02, -0x01, -0x02, -0x02, -0x02, -0x02, -0x01, -0x02, +0x04, +0x03, -0x02, +0x02, +0x00, -0x01, -0x01, +0x00, -0x07, -0x02, +0x04, -0x02, -0x02, +0x00, -0x0A], + [+0x01, +0x00, +0x02, +0x03, -0x05, +0x02, +0x03, +0x01, +0x01, -0x02, -0x03, +0x01, -0x02, -0x05, +0x00, +0x01, +0x00, -0x06, -0x04, -0x02, +0x02, +0x02, +0x00, -0x0A], + [+0x00, +0x01, +0x02, +0x03, -0x06, +0x03, +0x03, +0x00, +0x02, -0x02, -0x03, +0x01, -0x01, -0x05, +0x00, +0x00, +0x00, -0x07, -0x05, -0x02, +0x02, +0x03, +0x00, -0x0A], + [+0x00, +0x00, +0x00, +0x00, -0x03, +0x00, +0x00, +0x00, +0x00, +0x00, -0x01, +0x00, +0x00, -0x02, +0x00, +0x00, +0x00, -0x04, -0x02, +0x00, +0x00, +0x00, -0x01, -0x0A], + [-0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, +0x01]] + +PAM430 = [[+0x01, -0x01, +0x00, +0x01, -0x02, +0x00, +0x01, +0x02, -0x01, +0x00, -0x02, +0x00, -0x01, -0x04, +0x01, +0x01, +0x01, -0x07, -0x04, +0x00, +0x01, +0x00, +0x00, -0x09], + [-0x01, +0x06, +0x01, +0x00, -0x04, +0x02, +0x00, -0x02, +0x02, -0x02, -0x03, +0x04, +0x00, -0x05, +0x00, +0x00, +0x00, +0x04, -0x04, -0x02, +0x00, +0x01, +0x00, -0x09], + [+0x00, +0x01, +0x01, +0x02, -0x04, +0x01, +0x02, +0x01, +0x01, -0x02, -0x03, +0x01, -0x01, -0x04, +0x00, +0x01, +0x00, -0x05, -0x03, -0x01, +0x02, +0x01, +0x00, -0x09], + [+0x01, +0x00, +0x02, +0x03, -0x05, +0x02, +0x03, +0x01, +0x01, -0x02, -0x04, +0x01, -0x02, -0x06, +0x00, +0x01, +0x00, -0x07, -0x05, -0x02, +0x03, +0x03, +0x00, -0x09], + [-0x02, -0x04, -0x04, -0x05, +0x14, -0x06, -0x05, -0x03, -0x04, -0x02, -0x06, -0x06, -0x05, -0x04, -0x03, +0x00, -0x02, -0x09, +0x01, -0x02, -0x04, -0x05, -0x03, -0x09], + [+0x00, +0x02, +0x01, +0x02, -0x06, +0x03, +0x02, +0x00, +0x03, -0x02, -0x02, +0x01, -0x01, -0x05, +0x01, +0x00, +0x00, -0x05, -0x04, -0x01, +0x02, +0x03, +0x00, -0x09], + [+0x01, +0x00, +0x02, +0x03, -0x05, +0x02, +0x03, +0x01, +0x01, -0x02, -0x03, +0x01, -0x02, -0x06, +0x00, +0x01, +0x00, -0x08, -0x05, -0x01, +0x02, +0x03, +0x00, -0x09], + [+0x02, -0x02, +0x01, +0x01, -0x03, +0x00, +0x01, +0x05, -0x01, -0x02, -0x04, -0x01, -0x02, -0x05, +0x00, +0x01, +0x01, -0x08, -0x05, -0x01, +0x01, +0x00, +0x00, -0x09], + [-0x01, +0x02, +0x01, +0x01, -0x04, +0x03, +0x01, -0x01, +0x05, -0x02, -0x02, +0x01, -0x01, -0x02, +0x00, +0x00, -0x01, -0x03, +0x00, -0x02, +0x01, +0x02, +0x00, -0x09], + [+0x00, -0x02, -0x02, -0x02, -0x02, -0x02, -0x02, -0x02, -0x02, +0x04, +0x04, -0x02, +0x03, +0x02, -0x01, -0x01, +0x00, -0x05, +0x00, +0x04, -0x02, -0x02, +0x00, -0x09], + [-0x02, -0x03, -0x03, -0x04, -0x06, -0x02, -0x03, -0x04, -0x02, +0x04, +0x07, -0x03, +0x05, +0x04, -0x02, -0x02, -0x01, -0x02, +0x01, +0x03, -0x03, -0x03, -0x01, -0x09], + [+0x00, +0x04, +0x01, +0x01, -0x06, +0x01, +0x01, -0x01, +0x01, -0x02, -0x03, +0x04, +0x00, -0x05, +0x00, +0x00, +0x00, -0x03, -0x05, -0x02, +0x01, +0x01, +0x00, -0x09], + [-0x01, +0x00, -0x01, -0x02, -0x05, -0x01, -0x02, -0x02, -0x01, +0x03, +0x05, +0x00, +0x05, +0x01, -0x02, -0x01, +0x00, -0x04, -0x01, +0x02, -0x02, -0x01, +0x00, -0x09], + [-0x04, -0x05, -0x04, -0x06, -0x04, -0x05, -0x06, -0x05, -0x02, +0x02, +0x04, -0x05, +0x01, +0x0D, -0x05, -0x04, -0x03, +0x02, +0x0C, +0x00, -0x05, -0x05, -0x02, -0x09], + [+0x01, +0x00, +0x00, +0x00, -0x03, +0x01, +0x00, +0x00, +0x00, -0x01, -0x02, +0x00, -0x02, -0x05, +0x05, +0x01, +0x01, -0x06, -0x05, -0x01, +0x00, +0x00, +0x00, -0x09], + [+0x01, +0x00, +0x01, +0x01, +0x00, +0x00, +0x01, +0x01, +0x00, -0x01, -0x02, +0x00, -0x01, -0x04, +0x01, +0x01, +0x01, -0x03, -0x03, -0x01, +0x01, +0x00, +0x00, -0x09], + [+0x01, +0x00, +0x00, +0x00, -0x02, +0x00, +0x00, +0x01, -0x01, +0x00, -0x01, +0x00, +0x00, -0x03, +0x01, +0x01, +0x01, -0x06, -0x03, +0x00, +0x00, +0x00, +0x00, -0x09], + [-0x07, +0x04, -0x05, -0x07, -0x09, -0x05, -0x08, -0x08, -0x03, -0x05, -0x02, -0x03, -0x04, +0x02, -0x06, -0x03, -0x06, +0x1F, +0x02, -0x07, -0x06, -0x06, -0x04, -0x09], + [-0x04, -0x04, -0x03, -0x05, +0x01, -0x04, -0x05, -0x05, +0x00, +0x00, +0x01, -0x05, -0x01, +0x0C, -0x05, -0x03, -0x03, +0x02, +0x0F, -0x02, -0x04, -0x05, -0x02, -0x09], + [+0x00, -0x02, -0x01, -0x02, -0x02, -0x01, -0x01, -0x01, -0x02, +0x04, +0x03, -0x02, +0x02, +0x00, -0x01, -0x01, +0x00, -0x07, -0x02, +0x04, -0x01, -0x01, +0x00, -0x09], + [+0x01, +0x00, +0x02, +0x03, -0x04, +0x02, +0x02, +0x01, +0x01, -0x02, -0x03, +0x01, -0x02, -0x05, +0x00, +0x01, +0x00, -0x06, -0x04, -0x01, +0x02, +0x02, +0x00, -0x09], + [+0x00, +0x01, +0x01, +0x03, -0x05, +0x03, +0x03, +0x00, +0x02, -0x02, -0x03, +0x01, -0x01, -0x05, +0x00, +0x00, +0x00, -0x06, -0x05, -0x01, +0x02, +0x03, +0x00, -0x09], + [+0x00, +0x00, +0x00, +0x00, -0x03, +0x00, +0x00, +0x00, +0x00, +0x00, -0x01, +0x00, +0x00, -0x02, +0x00, +0x00, +0x00, -0x04, -0x02, +0x00, +0x00, +0x00, -0x01, -0x09], + [-0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, +0x01]] + +PAM440 = [[+0x01, -0x01, +0x00, +0x01, -0x02, +0x00, +0x01, +0x02, -0x01, +0x00, -0x02, +0x00, -0x01, -0x04, +0x01, +0x01, +0x01, -0x06, -0x04, +0x00, +0x01, +0x00, +0x00, -0x09], + [-0x01, +0x05, +0x01, +0x00, -0x04, +0x02, +0x00, -0x02, +0x02, -0x02, -0x03, +0x04, +0x00, -0x05, +0x00, +0x00, +0x00, +0x04, -0x04, -0x02, +0x00, +0x01, +0x00, -0x09], + [+0x00, +0x01, +0x01, +0x02, -0x04, +0x01, +0x02, +0x01, +0x01, -0x02, -0x03, +0x01, -0x01, -0x04, +0x00, +0x01, +0x00, -0x05, -0x03, -0x01, +0x02, +0x01, +0x00, -0x09], + [+0x01, +0x00, +0x02, +0x03, -0x05, +0x02, +0x03, +0x01, +0x01, -0x02, -0x03, +0x01, -0x02, -0x06, +0x00, +0x01, +0x00, -0x07, -0x05, -0x02, +0x02, +0x02, +0x00, -0x09], + [-0x02, -0x04, -0x04, -0x05, +0x14, -0x05, -0x05, -0x03, -0x04, -0x02, -0x06, -0x05, -0x05, -0x04, -0x03, +0x00, -0x02, -0x09, +0x01, -0x02, -0x04, -0x05, -0x03, -0x09], + [+0x00, +0x02, +0x01, +0x02, -0x05, +0x03, +0x02, +0x00, +0x03, -0x02, -0x02, +0x01, -0x01, -0x04, +0x01, +0x00, +0x00, -0x05, -0x04, -0x01, +0x02, +0x02, +0x00, -0x09], + [+0x01, +0x00, +0x02, +0x03, -0x05, +0x02, +0x03, +0x01, +0x01, -0x02, -0x03, +0x01, -0x02, -0x05, +0x00, +0x01, +0x00, -0x07, -0x05, -0x01, +0x02, +0x03, +0x00, -0x09], + [+0x02, -0x02, +0x01, +0x01, -0x03, +0x00, +0x01, +0x04, -0x01, -0x02, -0x04, -0x01, -0x02, -0x05, +0x00, +0x01, +0x01, -0x08, -0x05, -0x01, +0x01, +0x00, +0x00, -0x09], + [-0x01, +0x02, +0x01, +0x01, -0x04, +0x03, +0x01, -0x01, +0x05, -0x02, -0x02, +0x01, -0x01, -0x02, +0x00, +0x00, -0x01, -0x03, +0x00, -0x02, +0x01, +0x02, +0x00, -0x09], + [+0x00, -0x02, -0x02, -0x02, -0x02, -0x02, -0x02, -0x02, -0x02, +0x04, +0x04, -0x02, +0x03, +0x02, -0x01, -0x01, +0x00, -0x05, +0x00, +0x03, -0x02, -0x02, +0x00, -0x09], + [-0x02, -0x03, -0x03, -0x03, -0x06, -0x02, -0x03, -0x04, -0x02, +0x04, +0x07, -0x03, +0x05, +0x04, -0x02, -0x02, -0x01, -0x02, +0x01, +0x03, -0x03, -0x02, -0x01, -0x09], + [+0x00, +0x04, +0x01, +0x01, -0x05, +0x01, +0x01, -0x01, +0x01, -0x02, -0x03, +0x04, +0x00, -0x05, +0x00, +0x00, +0x00, -0x03, -0x05, -0x02, +0x01, +0x01, +0x00, -0x09], + [-0x01, +0x00, -0x01, -0x02, -0x05, -0x01, -0x02, -0x02, -0x01, +0x03, +0x05, +0x00, +0x04, +0x01, -0x01, -0x01, +0x00, -0x04, -0x01, +0x02, -0x02, -0x01, +0x00, -0x09], + [-0x04, -0x05, -0x04, -0x06, -0x04, -0x04, -0x05, -0x05, -0x02, +0x02, +0x04, -0x05, +0x01, +0x0D, -0x05, -0x04, -0x03, +0x02, +0x0C, +0x00, -0x05, -0x05, -0x02, -0x09], + [+0x01, +0x00, +0x00, +0x00, -0x03, +0x01, +0x00, +0x00, +0x00, -0x01, -0x02, +0x00, -0x01, -0x05, +0x05, +0x01, +0x01, -0x06, -0x05, -0x01, +0x00, +0x00, +0x00, -0x09], + [+0x01, +0x00, +0x01, +0x01, +0x00, +0x00, +0x01, +0x01, +0x00, -0x01, -0x02, +0x00, -0x01, -0x04, +0x01, +0x01, +0x01, -0x03, -0x03, -0x01, +0x01, +0x00, +0x00, -0x09], + [+0x01, +0x00, +0x00, +0x00, -0x02, +0x00, +0x00, +0x01, -0x01, +0x00, -0x01, +0x00, +0x00, -0x03, +0x01, +0x01, +0x01, -0x06, -0x03, +0x00, +0x00, +0x00, +0x00, -0x09], + [-0x06, +0x04, -0x05, -0x07, -0x09, -0x05, -0x07, -0x08, -0x03, -0x05, -0x02, -0x03, -0x04, +0x02, -0x06, -0x03, -0x06, +0x1E, +0x02, -0x06, -0x06, -0x06, -0x04, -0x09], + [-0x04, -0x04, -0x03, -0x05, +0x01, -0x04, -0x05, -0x05, +0x00, +0x00, +0x01, -0x05, -0x01, +0x0C, -0x05, -0x03, -0x03, +0x02, +0x0F, -0x02, -0x04, -0x04, -0x02, -0x09], + [+0x00, -0x02, -0x01, -0x02, -0x02, -0x01, -0x01, -0x01, -0x02, +0x03, +0x03, -0x02, +0x02, +0x00, -0x01, -0x01, +0x00, -0x06, -0x02, +0x04, -0x01, -0x01, +0x00, -0x09], + [+0x01, +0x00, +0x02, +0x02, -0x04, +0x02, +0x02, +0x01, +0x01, -0x02, -0x03, +0x01, -0x02, -0x05, +0x00, +0x01, +0x00, -0x06, -0x04, -0x01, +0x02, +0x02, +0x00, -0x09], + [+0x00, +0x01, +0x01, +0x02, -0x05, +0x02, +0x03, +0x00, +0x02, -0x02, -0x02, +0x01, -0x01, -0x05, +0x00, +0x00, +0x00, -0x06, -0x04, -0x01, +0x02, +0x03, +0x00, -0x09], + [+0x00, +0x00, +0x00, +0x00, -0x03, +0x00, +0x00, +0x00, +0x00, +0x00, -0x01, +0x00, +0x00, -0x02, +0x00, +0x00, +0x00, -0x04, -0x02, +0x00, +0x00, +0x00, -0x01, -0x09], + [-0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, +0x01]] + +PAM450 = [[+0x01, -0x01, +0x00, +0x01, -0x02, +0x00, +0x01, +0x01, -0x01, +0x00, -0x02, +0x00, -0x01, -0x03, +0x01, +0x01, +0x01, -0x06, -0x04, +0x00, +0x01, +0x00, +0x00, -0x09], + [-0x01, +0x05, +0x01, +0x00, -0x04, +0x02, +0x00, -0x01, +0x02, -0x02, -0x03, +0x04, +0x00, -0x04, +0x00, +0x00, +0x00, +0x04, -0x04, -0x02, +0x00, +0x01, +0x00, -0x09], + [+0x00, +0x01, +0x01, +0x02, -0x04, +0x01, +0x02, +0x01, +0x01, -0x01, -0x02, +0x01, -0x01, -0x04, +0x00, +0x01, +0x00, -0x04, -0x03, -0x01, +0x01, +0x01, +0x00, -0x09], + [+0x01, +0x00, +0x02, +0x03, -0x05, +0x02, +0x03, +0x01, +0x01, -0x02, -0x03, +0x01, -0x02, -0x05, +0x00, +0x01, +0x00, -0x07, -0x05, -0x01, +0x02, +0x02, +0x00, -0x09], + [-0x02, -0x04, -0x04, -0x05, +0x14, -0x05, -0x05, -0x03, -0x04, -0x02, -0x06, -0x05, -0x05, -0x04, -0x02, +0x00, -0x02, -0x09, +0x01, -0x02, -0x04, -0x05, -0x02, -0x09], + [+0x00, +0x02, +0x01, +0x02, -0x05, +0x03, +0x02, +0x00, +0x03, -0x01, -0x02, +0x01, -0x01, -0x04, +0x01, +0x00, +0x00, -0x05, -0x04, -0x01, +0x02, +0x02, +0x00, -0x09], + [+0x01, +0x00, +0x02, +0x03, -0x05, +0x02, +0x03, +0x01, +0x01, -0x02, -0x03, +0x01, -0x02, -0x05, +0x00, +0x01, +0x00, -0x07, -0x05, -0x01, +0x02, +0x03, +0x00, -0x09], + [+0x01, -0x01, +0x01, +0x01, -0x03, +0x00, +0x01, +0x04, -0x01, -0x02, -0x03, -0x01, -0x02, -0x05, +0x00, +0x01, +0x01, -0x08, -0x05, -0x01, +0x01, +0x00, +0x00, -0x09], + [-0x01, +0x02, +0x01, +0x01, -0x04, +0x03, +0x01, -0x01, +0x05, -0x02, -0x02, +0x01, -0x01, -0x02, +0x00, +0x00, -0x01, -0x02, +0x00, -0x02, +0x01, +0x02, +0x00, -0x09], + [+0x00, -0x02, -0x01, -0x02, -0x02, -0x01, -0x02, -0x02, -0x02, +0x04, +0x03, -0x02, +0x03, +0x02, -0x01, -0x01, +0x00, -0x05, +0x00, +0x03, -0x02, -0x02, +0x00, -0x09], + [-0x02, -0x03, -0x02, -0x03, -0x06, -0x02, -0x03, -0x03, -0x02, +0x03, +0x07, -0x02, +0x04, +0x04, -0x02, -0x02, -0x01, -0x01, +0x01, +0x03, -0x03, -0x02, -0x01, -0x09], + [+0x00, +0x04, +0x01, +0x01, -0x05, +0x01, +0x01, -0x01, +0x01, -0x02, -0x02, +0x04, +0x00, -0x05, +0x00, +0x00, +0x00, -0x03, -0x05, -0x02, +0x01, +0x01, +0x00, -0x09], + [-0x01, +0x00, -0x01, -0x02, -0x05, -0x01, -0x02, -0x02, -0x01, +0x03, +0x04, +0x00, +0x04, +0x01, -0x01, -0x01, +0x00, -0x04, -0x01, +0x02, -0x02, -0x01, +0x00, -0x09], + [-0x03, -0x04, -0x04, -0x05, -0x04, -0x04, -0x05, -0x05, -0x02, +0x02, +0x04, -0x05, +0x01, +0x0D, -0x05, -0x03, -0x03, +0x02, +0x0C, +0x00, -0x04, -0x05, -0x02, -0x09], + [+0x01, +0x00, +0x00, +0x00, -0x02, +0x01, +0x00, +0x00, +0x00, -0x01, -0x02, +0x00, -0x01, -0x05, +0x05, +0x01, +0x01, -0x06, -0x05, -0x01, +0x00, +0x00, +0x00, -0x09], + [+0x01, +0x00, +0x01, +0x01, +0x00, +0x00, +0x01, +0x01, +0x00, -0x01, -0x02, +0x00, -0x01, -0x03, +0x01, +0x01, +0x01, -0x03, -0x03, -0x01, +0x01, +0x00, +0x00, -0x09], + [+0x01, +0x00, +0x00, +0x00, -0x02, +0x00, +0x00, +0x01, -0x01, +0x00, -0x01, +0x00, +0x00, -0x03, +0x01, +0x01, +0x01, -0x05, -0x03, +0x00, +0x00, +0x00, +0x00, -0x09], + [-0x06, +0x04, -0x04, -0x07, -0x09, -0x05, -0x07, -0x08, -0x02, -0x05, -0x01, -0x03, -0x04, +0x02, -0x06, -0x03, -0x05, +0x1E, +0x02, -0x06, -0x06, -0x06, -0x04, -0x09], + [-0x04, -0x04, -0x03, -0x05, +0x01, -0x04, -0x05, -0x05, +0x00, +0x00, +0x01, -0x05, -0x01, +0x0C, -0x05, -0x03, -0x03, +0x02, +0x0E, -0x02, -0x04, -0x04, -0x02, -0x09], + [+0x00, -0x02, -0x01, -0x01, -0x02, -0x01, -0x01, -0x01, -0x02, +0x03, +0x03, -0x02, +0x02, +0x00, -0x01, -0x01, +0x00, -0x06, -0x02, +0x03, -0x01, -0x01, +0x00, -0x09], + [+0x01, +0x00, +0x01, +0x02, -0x04, +0x02, +0x02, +0x01, +0x01, -0x02, -0x03, +0x01, -0x02, -0x04, +0x00, +0x01, +0x00, -0x06, -0x04, -0x01, +0x02, +0x02, +0x00, -0x09], + [+0x00, +0x01, +0x01, +0x02, -0x05, +0x02, +0x03, +0x00, +0x02, -0x02, -0x02, +0x01, -0x01, -0x05, +0x00, +0x00, +0x00, -0x06, -0x04, -0x01, +0x02, +0x02, +0x00, -0x09], + [+0x00, +0x00, +0x00, +0x00, -0x02, +0x00, +0x00, +0x00, +0x00, +0x00, -0x01, +0x00, +0x00, -0x02, +0x00, +0x00, +0x00, -0x04, -0x02, +0x00, +0x00, +0x00, +0x00, -0x09], + [-0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, +0x01]] + +PAM460 = [[+0x01, -0x01, +0x00, +0x01, -0x02, +0x00, +0x01, +0x01, +0x00, +0x00, -0x01, +0x00, -0x01, -0x03, +0x01, +0x01, +0x01, -0x06, -0x03, +0x00, +0x01, +0x00, +0x00, -0x09], + [-0x01, +0x05, +0x01, +0x00, -0x04, +0x01, +0x00, -0x01, +0x02, -0x02, -0x02, +0x04, +0x00, -0x04, +0x00, +0x00, +0x00, +0x04, -0x04, -0x02, +0x00, +0x01, +0x00, -0x09], + [+0x00, +0x01, +0x01, +0x02, -0x03, +0x01, +0x01, +0x01, +0x01, -0x01, -0x02, +0x01, -0x01, -0x03, +0x00, +0x01, +0x00, -0x04, -0x03, -0x01, +0x01, +0x01, +0x00, -0x09], + [+0x01, +0x00, +0x02, +0x03, -0x05, +0x02, +0x03, +0x01, +0x01, -0x02, -0x03, +0x01, -0x02, -0x05, +0x00, +0x01, +0x00, -0x07, -0x04, -0x01, +0x02, +0x02, +0x00, -0x09], + [-0x02, -0x04, -0x03, -0x05, +0x13, -0x05, -0x05, -0x03, -0x03, -0x02, -0x06, -0x05, -0x05, -0x03, -0x02, +0x00, -0x02, -0x09, +0x02, -0x02, -0x04, -0x05, -0x02, -0x09], + [+0x00, +0x01, +0x01, +0x02, -0x05, +0x02, +0x02, +0x00, +0x02, -0x01, -0x02, +0x01, -0x01, -0x04, +0x01, +0x00, +0x00, -0x05, -0x04, -0x01, +0x01, +0x02, +0x00, -0x09], + [+0x01, +0x00, +0x01, +0x03, -0x05, +0x02, +0x03, +0x01, +0x01, -0x02, -0x03, +0x01, -0x02, -0x05, +0x00, +0x01, +0x00, -0x07, -0x04, -0x01, +0x02, +0x02, +0x00, -0x09], + [+0x01, -0x01, +0x01, +0x01, -0x03, +0x00, +0x01, +0x04, -0x01, -0x02, -0x03, -0x01, -0x02, -0x05, +0x01, +0x01, +0x01, -0x07, -0x05, -0x01, +0x01, +0x00, +0x00, -0x09], + [+0x00, +0x02, +0x01, +0x01, -0x03, +0x02, +0x01, -0x01, +0x05, -0x02, -0x02, +0x01, -0x01, -0x02, +0x00, +0x00, +0x00, -0x02, +0x00, -0x02, +0x01, +0x02, +0x00, -0x09], + [+0x00, -0x02, -0x01, -0x02, -0x02, -0x01, -0x02, -0x02, -0x02, +0x03, +0x03, -0x02, +0x02, +0x02, -0x01, -0x01, +0x00, -0x05, +0x00, +0x03, -0x02, -0x02, +0x00, -0x09], + [-0x01, -0x02, -0x02, -0x03, -0x06, -0x02, -0x03, -0x03, -0x02, +0x03, +0x07, -0x02, +0x04, +0x03, -0x02, -0x02, -0x01, -0x01, +0x01, +0x03, -0x03, -0x02, -0x01, -0x09], + [+0x00, +0x04, +0x01, +0x01, -0x05, +0x01, +0x01, -0x01, +0x01, -0x02, -0x02, +0x04, +0x00, -0x05, +0x00, +0x00, +0x00, -0x03, -0x04, -0x02, +0x01, +0x01, +0x00, -0x09], + [-0x01, +0x00, -0x01, -0x02, -0x05, -0x01, -0x02, -0x02, -0x01, +0x02, +0x04, +0x00, +0x04, +0x01, -0x01, -0x01, +0x00, -0x04, -0x01, +0x02, -0x02, -0x01, +0x00, -0x09], + [-0x03, -0x04, -0x03, -0x05, -0x03, -0x04, -0x05, -0x05, -0x02, +0x02, +0x03, -0x05, +0x01, +0x0C, -0x04, -0x03, -0x03, +0x02, +0x0B, +0x00, -0x04, -0x05, -0x02, -0x09], + [+0x01, +0x00, +0x00, +0x00, -0x02, +0x01, +0x00, +0x01, +0x00, -0x01, -0x02, +0x00, -0x01, -0x04, +0x04, +0x01, +0x01, -0x06, -0x05, -0x01, +0x00, +0x00, +0x00, -0x09], + [+0x01, +0x00, +0x01, +0x01, +0x00, +0x00, +0x01, +0x01, +0x00, -0x01, -0x02, +0x00, -0x01, -0x03, +0x01, +0x01, +0x01, -0x03, -0x03, -0x01, +0x01, +0x00, +0x00, -0x09], + [+0x01, +0x00, +0x00, +0x00, -0x02, +0x00, +0x00, +0x01, +0x00, +0x00, -0x01, +0x00, +0x00, -0x03, +0x01, +0x01, +0x01, -0x05, -0x03, +0x00, +0x00, +0x00, +0x00, -0x09], + [-0x06, +0x04, -0x04, -0x07, -0x09, -0x05, -0x07, -0x07, -0x02, -0x05, -0x01, -0x03, -0x04, +0x02, -0x06, -0x03, -0x05, +0x1E, +0x02, -0x06, -0x06, -0x06, -0x04, -0x09], + [-0x03, -0x04, -0x03, -0x04, +0x02, -0x04, -0x04, -0x05, +0x00, +0x00, +0x01, -0x04, -0x01, +0x0B, -0x05, -0x03, -0x03, +0x02, +0x0E, -0x02, -0x04, -0x04, -0x02, -0x09], + [+0x00, -0x02, -0x01, -0x01, -0x02, -0x01, -0x01, -0x01, -0x02, +0x03, +0x03, -0x02, +0x02, +0x00, -0x01, -0x01, +0x00, -0x06, -0x02, +0x03, -0x01, -0x01, +0x00, -0x09], + [+0x01, +0x00, +0x01, +0x02, -0x04, +0x01, +0x02, +0x01, +0x01, -0x02, -0x03, +0x01, -0x02, -0x04, +0x00, +0x01, +0x00, -0x06, -0x04, -0x01, +0x02, +0x02, +0x00, -0x09], + [+0x00, +0x01, +0x01, +0x02, -0x05, +0x02, +0x02, +0x00, +0x02, -0x02, -0x02, +0x01, -0x01, -0x05, +0x00, +0x00, +0x00, -0x06, -0x04, -0x01, +0x02, +0x02, +0x00, -0x09], + [+0x00, +0x00, +0x00, +0x00, -0x02, +0x00, +0x00, +0x00, +0x00, +0x00, -0x01, +0x00, +0x00, -0x02, +0x00, +0x00, +0x00, -0x04, -0x02, +0x00, +0x00, +0x00, +0x00, -0x09], + [-0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, +0x01]] + +PAM470 = [[+0x01, -0x01, +0x01, +0x01, -0x02, +0x00, +0x01, +0x02, -0x01, +0x00, -0x02, +0x00, -0x01, -0x04, +0x01, +0x01, +0x01, -0x07, -0x04, +0x00, +0x01, +0x00, +0x00, -0x0A], + [-0x01, +0x06, +0x01, +0x00, -0x04, +0x02, +0x00, -0x01, +0x02, -0x02, -0x03, +0x04, +0x00, -0x05, +0x00, +0x00, +0x00, +0x04, -0x05, -0x02, +0x00, +0x01, +0x00, -0x0A], + [+0x01, +0x01, +0x01, +0x02, -0x04, +0x01, +0x02, +0x01, +0x01, -0x02, -0x03, +0x01, -0x01, -0x04, +0x00, +0x01, +0x00, -0x05, -0x03, -0x01, +0x02, +0x01, +0x00, -0x0A], + [+0x01, +0x00, +0x02, +0x03, -0x05, +0x02, +0x03, +0x01, +0x01, -0x02, -0x04, +0x01, -0x02, -0x06, +0x00, +0x01, +0x00, -0x08, -0x05, -0x02, +0x03, +0x03, +0x00, -0x0A], + [-0x02, -0x04, -0x04, -0x05, +0x16, -0x06, -0x05, -0x03, -0x04, -0x02, -0x06, -0x06, -0x06, -0x04, -0x03, +0x00, -0x02, -0x0A, +0x02, -0x02, -0x05, -0x06, -0x03, -0x0A], + [+0x00, +0x02, +0x01, +0x02, -0x06, +0x03, +0x02, +0x00, +0x03, -0x02, -0x02, +0x01, -0x01, -0x05, +0x01, +0x00, +0x00, -0x05, -0x04, -0x01, +0x02, +0x02, +0x00, -0x0A], + [+0x01, +0x00, +0x02, +0x03, -0x05, +0x02, +0x03, +0x01, +0x01, -0x02, -0x03, +0x01, -0x02, -0x06, +0x00, +0x01, +0x00, -0x08, -0x05, -0x01, +0x02, +0x03, +0x00, -0x0A], + [+0x02, -0x01, +0x01, +0x01, -0x03, +0x00, +0x01, +0x05, -0x01, -0x02, -0x04, -0x01, -0x02, -0x06, +0x01, +0x01, +0x01, -0x08, -0x06, -0x01, +0x01, +0x01, +0x00, -0x0A], + [-0x01, +0x02, +0x01, +0x01, -0x04, +0x03, +0x01, -0x01, +0x05, -0x02, -0x02, +0x01, -0x01, -0x02, +0x00, +0x00, +0x00, -0x03, +0x00, -0x02, +0x01, +0x02, +0x00, -0x0A], + [+0x00, -0x02, -0x02, -0x02, -0x02, -0x02, -0x02, -0x02, -0x02, +0x04, +0x04, -0x02, +0x03, +0x02, -0x01, -0x01, +0x00, -0x05, +0x00, +0x03, -0x02, -0x02, +0x00, -0x0A], + [-0x02, -0x03, -0x03, -0x04, -0x06, -0x02, -0x03, -0x04, -0x02, +0x04, +0x08, -0x03, +0x05, +0x04, -0x02, -0x02, -0x01, -0x02, +0x01, +0x03, -0x03, -0x03, -0x01, -0x0A], + [+0x00, +0x04, +0x01, +0x01, -0x06, +0x01, +0x01, -0x01, +0x01, -0x02, -0x03, +0x04, +0x00, -0x05, +0x00, +0x00, +0x00, -0x03, -0x05, -0x02, +0x01, +0x01, +0x00, -0x0A], + [-0x01, +0x00, -0x01, -0x02, -0x06, -0x01, -0x02, -0x02, -0x01, +0x03, +0x05, +0x00, +0x04, +0x01, -0x01, -0x01, +0x00, -0x04, -0x01, +0x02, -0x02, -0x01, +0x00, -0x0A], + [-0x04, -0x05, -0x04, -0x06, -0x04, -0x05, -0x06, -0x06, -0x02, +0x02, +0x04, -0x05, +0x01, +0x0E, -0x05, -0x04, -0x03, +0x03, +0x0D, +0x00, -0x05, -0x05, -0x02, -0x0A], + [+0x01, +0x00, +0x00, +0x00, -0x03, +0x01, +0x00, +0x01, +0x00, -0x01, -0x02, +0x00, -0x01, -0x05, +0x05, +0x01, +0x01, -0x06, -0x05, -0x01, +0x00, +0x01, +0x00, -0x0A], + [+0x01, +0x00, +0x01, +0x01, +0x00, +0x00, +0x01, +0x01, +0x00, -0x01, -0x02, +0x00, -0x01, -0x04, +0x01, +0x01, +0x01, -0x04, -0x03, -0x01, +0x01, +0x00, +0x00, -0x0A], + [+0x01, +0x00, +0x00, +0x00, -0x02, +0x00, +0x00, +0x01, +0x00, +0x00, -0x01, +0x00, +0x00, -0x03, +0x01, +0x01, +0x01, -0x06, -0x03, +0x00, +0x00, +0x00, +0x00, -0x0A], + [-0x07, +0x04, -0x05, -0x08, -0x0A, -0x05, -0x08, -0x08, -0x03, -0x05, -0x02, -0x03, -0x04, +0x03, -0x06, -0x04, -0x06, +0x23, +0x02, -0x07, -0x06, -0x07, -0x04, -0x0A], + [-0x04, -0x05, -0x03, -0x05, +0x02, -0x04, -0x05, -0x06, +0x00, +0x00, +0x01, -0x05, -0x01, +0x0D, -0x05, -0x03, -0x03, +0x02, +0x10, -0x02, -0x04, -0x05, -0x02, -0x0A], + [+0x00, -0x02, -0x01, -0x02, -0x02, -0x01, -0x01, -0x01, -0x02, +0x03, +0x03, -0x02, +0x02, +0x00, -0x01, -0x01, +0x00, -0x07, -0x02, +0x04, -0x01, -0x01, +0x00, -0x0A], + [+0x01, +0x00, +0x02, +0x03, -0x05, +0x02, +0x02, +0x01, +0x01, -0x02, -0x03, +0x01, -0x02, -0x05, +0x00, +0x01, +0x00, -0x06, -0x04, -0x01, +0x02, +0x02, +0x00, -0x0A], + [+0x00, +0x01, +0x01, +0x03, -0x06, +0x02, +0x03, +0x01, +0x02, -0x02, -0x03, +0x01, -0x01, -0x05, +0x01, +0x00, +0x00, -0x07, -0x05, -0x01, +0x02, +0x03, +0x00, -0x0A], + [+0x00, +0x00, +0x00, +0x00, -0x03, +0x00, +0x00, +0x00, +0x00, +0x00, -0x01, +0x00, +0x00, -0x02, +0x00, +0x00, +0x00, -0x04, -0x02, +0x00, +0x00, +0x00, +0x00, -0x0A], + [-0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, +0x01]] + +PAM480 = [[+0x01, -0x01, +0x01, +0x01, -0x02, +0x00, +0x01, +0x02, +0x00, +0x00, -0x02, +0x00, -0x01, -0x04, +0x01, +0x01, +0x01, -0x07, -0x04, +0x00, +0x01, +0x00, +0x00, -0x0A], + [-0x01, +0x05, +0x01, +0x00, -0x04, +0x02, +0x00, -0x01, +0x02, -0x02, -0x03, +0x04, +0x00, -0x05, +0x00, +0x00, +0x00, +0x04, -0x04, -0x02, +0x00, +0x01, +0x00, -0x0A], + [+0x01, +0x01, +0x01, +0x02, -0x04, +0x01, +0x02, +0x01, +0x01, -0x01, -0x03, +0x01, -0x01, -0x04, +0x00, +0x01, +0x00, -0x05, -0x03, -0x01, +0x02, +0x01, +0x00, -0x0A], + [+0x01, +0x00, +0x02, +0x03, -0x05, +0x02, +0x03, +0x01, +0x01, -0x02, -0x03, +0x01, -0x02, -0x06, +0x00, +0x01, +0x00, -0x07, -0x05, -0x01, +0x02, +0x02, +0x00, -0x0A], + [-0x02, -0x04, -0x04, -0x05, +0x16, -0x05, -0x05, -0x03, -0x04, -0x02, -0x06, -0x06, -0x05, -0x04, -0x03, +0x00, -0x02, -0x0A, +0x02, -0x02, -0x04, -0x05, -0x03, -0x0A], + [+0x00, +0x02, +0x01, +0x02, -0x05, +0x03, +0x02, +0x00, +0x03, -0x02, -0x02, +0x01, -0x01, -0x05, +0x01, +0x00, +0x00, -0x05, -0x04, -0x01, +0x02, +0x02, +0x00, -0x0A], + [+0x01, +0x00, +0x02, +0x03, -0x05, +0x02, +0x03, +0x01, +0x01, -0x02, -0x03, +0x01, -0x02, -0x05, +0x00, +0x01, +0x00, -0x08, -0x05, -0x01, +0x02, +0x03, +0x00, -0x0A], + [+0x02, -0x01, +0x01, +0x01, -0x03, +0x00, +0x01, +0x04, -0x01, -0x02, -0x04, -0x01, -0x02, -0x05, +0x01, +0x01, +0x01, -0x08, -0x05, -0x01, +0x01, +0x01, +0x00, -0x0A], + [+0x00, +0x02, +0x01, +0x01, -0x04, +0x03, +0x01, -0x01, +0x05, -0x02, -0x02, +0x01, -0x01, -0x02, +0x00, +0x00, +0x00, -0x03, +0x00, -0x02, +0x01, +0x02, +0x00, -0x0A], + [+0x00, -0x02, -0x01, -0x02, -0x02, -0x02, -0x02, -0x02, -0x02, +0x04, +0x04, -0x02, +0x03, +0x02, -0x01, -0x01, +0x00, -0x05, +0x00, +0x03, -0x02, -0x02, +0x00, -0x0A], + [-0x02, -0x03, -0x03, -0x03, -0x06, -0x02, -0x03, -0x04, -0x02, +0x04, +0x07, -0x03, +0x05, +0x04, -0x02, -0x02, -0x01, -0x02, +0x01, +0x03, -0x03, -0x03, -0x01, -0x0A], + [+0x00, +0x04, +0x01, +0x01, -0x06, +0x01, +0x01, -0x01, +0x01, -0x02, -0x03, +0x04, +0x00, -0x05, +0x00, +0x00, +0x00, -0x03, -0x05, -0x02, +0x01, +0x01, +0x00, -0x0A], + [-0x01, +0x00, -0x01, -0x02, -0x05, -0x01, -0x02, -0x02, -0x01, +0x03, +0x05, +0x00, +0x04, +0x01, -0x01, -0x01, +0x00, -0x04, -0x01, +0x02, -0x02, -0x01, +0x00, -0x0A], + [-0x04, -0x05, -0x04, -0x06, -0x04, -0x05, -0x05, -0x05, -0x02, +0x02, +0x04, -0x05, +0x01, +0x0E, -0x05, -0x04, -0x03, +0x03, +0x0D, +0x00, -0x05, -0x05, -0x02, -0x0A], + [+0x01, +0x00, +0x00, +0x00, -0x03, +0x01, +0x00, +0x01, +0x00, -0x01, -0x02, +0x00, -0x01, -0x05, +0x05, +0x01, +0x01, -0x06, -0x05, -0x01, +0x00, +0x01, +0x00, -0x0A], + [+0x01, +0x00, +0x01, +0x01, +0x00, +0x00, +0x01, +0x01, +0x00, -0x01, -0x02, +0x00, -0x01, -0x04, +0x01, +0x01, +0x01, -0x03, -0x03, -0x01, +0x01, +0x00, +0x00, -0x0A], + [+0x01, +0x00, +0x00, +0x00, -0x02, +0x00, +0x00, +0x01, +0x00, +0x00, -0x01, +0x00, +0x00, -0x03, +0x01, +0x01, +0x01, -0x06, -0x03, +0x00, +0x00, +0x00, +0x00, -0x0A], + [-0x07, +0x04, -0x05, -0x07, -0x0A, -0x05, -0x08, -0x08, -0x03, -0x05, -0x02, -0x03, -0x04, +0x03, -0x06, -0x03, -0x06, +0x23, +0x02, -0x07, -0x06, -0x06, -0x04, -0x0A], + [-0x04, -0x04, -0x03, -0x05, +0x02, -0x04, -0x05, -0x05, +0x00, +0x00, +0x01, -0x05, -0x01, +0x0D, -0x05, -0x03, -0x03, +0x02, +0x10, -0x02, -0x04, -0x05, -0x02, -0x0A], + [+0x00, -0x02, -0x01, -0x01, -0x02, -0x01, -0x01, -0x01, -0x02, +0x03, +0x03, -0x02, +0x02, +0x00, -0x01, -0x01, +0x00, -0x07, -0x02, +0x03, -0x01, -0x01, +0x00, -0x0A], + [+0x01, +0x00, +0x02, +0x02, -0x04, +0x02, +0x02, +0x01, +0x01, -0x02, -0x03, +0x01, -0x02, -0x05, +0x00, +0x01, +0x00, -0x06, -0x04, -0x01, +0x02, +0x02, +0x00, -0x0A], + [+0x00, +0x01, +0x01, +0x02, -0x05, +0x02, +0x03, +0x01, +0x02, -0x02, -0x03, +0x01, -0x01, -0x05, +0x01, +0x00, +0x00, -0x06, -0x05, -0x01, +0x02, +0x02, +0x00, -0x0A], + [+0x00, +0x00, +0x00, +0x00, -0x03, +0x00, +0x00, +0x00, +0x00, +0x00, -0x01, +0x00, +0x00, -0x02, +0x00, +0x00, +0x00, -0x04, -0x02, +0x00, +0x00, +0x00, +0x00, -0x0A], + [-0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, -0x0A, +0x01]] + +PAM490 = [[+0x01, -0x01, +0x00, +0x01, -0x02, +0x00, +0x01, +0x02, +0x00, +0x00, -0x01, +0x00, -0x01, -0x03, +0x01, +0x01, +0x01, -0x06, -0x04, +0x00, +0x01, +0x00, +0x00, -0x09], + [-0x01, +0x05, +0x01, +0x00, -0x04, +0x02, +0x00, -0x01, +0x02, -0x02, -0x03, +0x04, +0x00, -0x05, +0x00, +0x00, +0x00, +0x04, -0x04, -0x02, +0x00, +0x01, +0x00, -0x09], + [+0x00, +0x01, +0x01, +0x02, -0x04, +0x01, +0x02, +0x01, +0x01, -0x01, -0x02, +0x01, -0x01, -0x04, +0x00, +0x01, +0x00, -0x05, -0x03, -0x01, +0x01, +0x01, +0x00, -0x09], + [+0x01, +0x00, +0x02, +0x03, -0x05, +0x02, +0x03, +0x01, +0x01, -0x02, -0x03, +0x01, -0x02, -0x05, +0x00, +0x01, +0x00, -0x07, -0x05, -0x01, +0x02, +0x02, +0x00, -0x09], + [-0x02, -0x04, -0x04, -0x05, +0x16, -0x05, -0x05, -0x03, -0x04, -0x02, -0x06, -0x05, -0x05, -0x04, -0x03, +0x00, -0x02, -0x09, +0x02, -0x02, -0x04, -0x05, -0x02, -0x09], + [+0x00, +0x02, +0x01, +0x02, -0x05, +0x02, +0x02, +0x00, +0x02, -0x01, -0x02, +0x01, -0x01, -0x04, +0x01, +0x00, +0x00, -0x05, -0x04, -0x01, +0x02, +0x02, +0x00, -0x09], + [+0x01, +0x00, +0x02, +0x03, -0x05, +0x02, +0x03, +0x01, +0x01, -0x02, -0x03, +0x01, -0x02, -0x05, +0x00, +0x01, +0x00, -0x07, -0x05, -0x01, +0x02, +0x02, +0x00, -0x09], + [+0x02, -0x01, +0x01, +0x01, -0x03, +0x00, +0x01, +0x04, -0x01, -0x02, -0x03, -0x01, -0x02, -0x05, +0x01, +0x01, +0x01, -0x08, -0x05, -0x01, +0x01, +0x01, +0x00, -0x09], + [+0x00, +0x02, +0x01, +0x01, -0x04, +0x02, +0x01, -0x01, +0x05, -0x02, -0x02, +0x01, -0x01, -0x02, +0x00, +0x00, +0x00, -0x03, +0x00, -0x02, +0x01, +0x02, +0x00, -0x09], + [+0x00, -0x02, -0x01, -0x02, -0x02, -0x01, -0x02, -0x02, -0x02, +0x03, +0x04, -0x02, +0x03, +0x02, -0x01, -0x01, +0x00, -0x05, +0x00, +0x03, -0x02, -0x02, +0x00, -0x09], + [-0x01, -0x03, -0x02, -0x03, -0x06, -0x02, -0x03, -0x03, -0x02, +0x04, +0x07, -0x02, +0x05, +0x04, -0x02, -0x02, -0x01, -0x01, +0x01, +0x03, -0x03, -0x02, -0x01, -0x09], + [+0x00, +0x04, +0x01, +0x01, -0x05, +0x01, +0x01, -0x01, +0x01, -0x02, -0x02, +0x04, +0x00, -0x05, +0x00, +0x00, +0x00, -0x03, -0x05, -0x02, +0x01, +0x01, +0x00, -0x09], + [-0x01, +0x00, -0x01, -0x02, -0x05, -0x01, -0x02, -0x02, -0x01, +0x03, +0x05, +0x00, +0x04, +0x01, -0x01, -0x01, +0x00, -0x04, -0x01, +0x02, -0x02, -0x01, +0x00, -0x09], + [-0x03, -0x05, -0x04, -0x05, -0x04, -0x04, -0x05, -0x05, -0x02, +0x02, +0x04, -0x05, +0x01, +0x0E, -0x05, -0x04, -0x03, +0x03, +0x0D, +0x00, -0x05, -0x05, -0x02, -0x09], + [+0x01, +0x00, +0x00, +0x00, -0x03, +0x01, +0x00, +0x01, +0x00, -0x01, -0x02, +0x00, -0x01, -0x05, +0x04, +0x01, +0x01, -0x06, -0x05, -0x01, +0x00, +0x01, +0x00, -0x09], + [+0x01, +0x00, +0x01, +0x01, +0x00, +0x00, +0x01, +0x01, +0x00, -0x01, -0x02, +0x00, -0x01, -0x04, +0x01, +0x01, +0x01, -0x03, -0x03, -0x01, +0x01, +0x00, +0x00, -0x09], + [+0x01, +0x00, +0x00, +0x00, -0x02, +0x00, +0x00, +0x01, +0x00, +0x00, -0x01, +0x00, +0x00, -0x03, +0x01, +0x01, +0x01, -0x06, -0x03, +0x00, +0x00, +0x00, +0x00, -0x09], + [-0x06, +0x04, -0x05, -0x07, -0x09, -0x05, -0x07, -0x08, -0x03, -0x05, -0x01, -0x03, -0x04, +0x03, -0x06, -0x03, -0x06, +0x22, +0x02, -0x06, -0x06, -0x06, -0x04, -0x09], + [-0x04, -0x04, -0x03, -0x05, +0x02, -0x04, -0x05, -0x05, +0x00, +0x00, +0x01, -0x05, -0x01, +0x0D, -0x05, -0x03, -0x03, +0x02, +0x0F, -0x02, -0x04, -0x04, -0x02, -0x09], + [+0x00, -0x02, -0x01, -0x01, -0x02, -0x01, -0x01, -0x01, -0x02, +0x03, +0x03, -0x02, +0x02, +0x00, -0x01, -0x01, +0x00, -0x06, -0x02, +0x03, -0x01, -0x01, +0x00, -0x09], + [+0x01, +0x00, +0x01, +0x02, -0x04, +0x02, +0x02, +0x01, +0x01, -0x02, -0x03, +0x01, -0x02, -0x05, +0x00, +0x01, +0x00, -0x06, -0x04, -0x01, +0x02, +0x02, +0x00, -0x09], + [+0x00, +0x01, +0x01, +0x02, -0x05, +0x02, +0x02, +0x01, +0x02, -0x02, -0x02, +0x01, -0x01, -0x05, +0x01, +0x00, +0x00, -0x06, -0x04, -0x01, +0x02, +0x02, +0x00, -0x09], + [+0x00, +0x00, +0x00, +0x00, -0x02, +0x00, +0x00, +0x00, +0x00, +0x00, -0x01, +0x00, +0x00, -0x02, +0x00, +0x00, +0x00, -0x04, -0x02, +0x00, +0x00, +0x00, +0x00, -0x09], + [-0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, +0x01]] + +PAM500 = [[+0x01, -0x01, +0x00, +0x01, -0x02, +0x00, +0x01, +0x01, +0x00, +0x00, -0x01, +0x00, -0x01, -0x03, +0x01, +0x01, +0x01, -0x06, -0x03, +0x00, +0x01, +0x00, +0x00, -0x09], + [-0x01, +0x05, +0x01, +0x00, -0x04, +0x02, +0x00, -0x01, +0x02, -0x02, -0x02, +0x04, +0x00, -0x04, +0x00, +0x00, +0x00, +0x04, -0x04, -0x02, +0x00, +0x01, +0x00, -0x09], + [+0x00, +0x01, +0x01, +0x02, -0x03, +0x01, +0x01, +0x01, +0x01, -0x01, -0x02, +0x01, -0x01, -0x04, +0x00, +0x01, +0x00, -0x05, -0x03, -0x01, +0x01, +0x01, +0x00, -0x09], + [+0x01, +0x00, +0x02, +0x03, -0x05, +0x02, +0x03, +0x01, +0x01, -0x02, -0x03, +0x01, -0x02, -0x05, +0x00, +0x01, +0x00, -0x07, -0x05, -0x01, +0x02, +0x02, +0x00, -0x09], + [-0x02, -0x04, -0x03, -0x05, +0x16, -0x05, -0x05, -0x03, -0x04, -0x02, -0x06, -0x05, -0x05, -0x03, -0x02, +0x00, -0x02, -0x09, +0x02, -0x02, -0x04, -0x05, -0x02, -0x09], + [+0x00, +0x02, +0x01, +0x02, -0x05, +0x02, +0x02, +0x00, +0x02, -0x01, -0x02, +0x01, -0x01, -0x04, +0x01, +0x00, +0x00, -0x05, -0x04, -0x01, +0x02, +0x02, +0x00, -0x09], + [+0x01, +0x00, +0x01, +0x03, -0x05, +0x02, +0x03, +0x01, +0x01, -0x02, -0x03, +0x01, -0x01, -0x05, +0x00, +0x01, +0x00, -0x07, -0x05, -0x01, +0x02, +0x02, +0x00, -0x09], + [+0x01, -0x01, +0x01, +0x01, -0x03, +0x00, +0x01, +0x04, -0x01, -0x02, -0x03, +0x00, -0x02, -0x05, +0x01, +0x01, +0x01, -0x08, -0x05, -0x01, +0x01, +0x01, +0x00, -0x09], + [+0x00, +0x02, +0x01, +0x01, -0x04, +0x02, +0x01, -0x01, +0x04, -0x02, -0x02, +0x01, -0x01, -0x02, +0x00, +0x00, +0x00, -0x02, +0x00, -0x02, +0x01, +0x02, +0x00, -0x09], + [+0x00, -0x02, -0x01, -0x02, -0x02, -0x01, -0x02, -0x02, -0x02, +0x03, +0x04, -0x02, +0x03, +0x02, -0x01, -0x01, +0x00, -0x05, +0x00, +0x03, -0x02, -0x02, +0x00, -0x09], + [-0x01, -0x02, -0x02, -0x03, -0x06, -0x02, -0x03, -0x03, -0x02, +0x04, +0x07, -0x02, +0x04, +0x04, -0x02, -0x02, -0x01, -0x01, +0x01, +0x03, -0x03, -0x02, -0x01, -0x09], + [+0x00, +0x04, +0x01, +0x01, -0x05, +0x01, +0x01, +0x00, +0x01, -0x02, -0x02, +0x04, +0x00, -0x05, +0x00, +0x00, +0x00, -0x03, -0x05, -0x02, +0x01, +0x01, +0x00, -0x09], + [-0x01, +0x00, -0x01, -0x02, -0x05, -0x01, -0x01, -0x02, -0x01, +0x03, +0x04, +0x00, +0x04, +0x01, -0x01, -0x01, +0x00, -0x04, -0x01, +0x02, -0x01, -0x01, +0x00, -0x09], + [-0x03, -0x04, -0x04, -0x05, -0x03, -0x04, -0x05, -0x05, -0x02, +0x02, +0x04, -0x05, +0x01, +0x0D, -0x04, -0x03, -0x03, +0x03, +0x0D, +0x00, -0x04, -0x05, -0x02, -0x09], + [+0x01, +0x00, +0x00, +0x00, -0x02, +0x01, +0x00, +0x01, +0x00, -0x01, -0x02, +0x00, -0x01, -0x04, +0x04, +0x01, +0x01, -0x06, -0x05, -0x01, +0x00, +0x01, +0x00, -0x09], + [+0x01, +0x00, +0x01, +0x01, +0x00, +0x00, +0x01, +0x01, +0x00, -0x01, -0x02, +0x00, -0x01, -0x03, +0x01, +0x01, +0x01, -0x03, -0x03, -0x01, +0x01, +0x00, +0x00, -0x09], + [+0x01, +0x00, +0x00, +0x00, -0x02, +0x00, +0x00, +0x01, +0x00, +0x00, -0x01, +0x00, +0x00, -0x03, +0x01, +0x01, +0x01, -0x06, -0x03, +0x00, +0x00, +0x00, +0x00, -0x09], + [-0x06, +0x04, -0x05, -0x07, -0x09, -0x05, -0x07, -0x08, -0x02, -0x05, -0x01, -0x03, -0x04, +0x03, -0x06, -0x03, -0x06, +0x22, +0x02, -0x06, -0x06, -0x06, -0x04, -0x09], + [-0x03, -0x04, -0x03, -0x05, +0x02, -0x04, -0x05, -0x05, +0x00, +0x00, +0x01, -0x05, -0x01, +0x0D, -0x05, -0x03, -0x03, +0x02, +0x0F, -0x01, -0x04, -0x04, -0x02, -0x09], + [+0x00, -0x02, -0x01, -0x01, -0x02, -0x01, -0x01, -0x01, -0x02, +0x03, +0x03, -0x02, +0x02, +0x00, -0x01, -0x01, +0x00, -0x06, -0x01, +0x03, -0x01, -0x01, +0x00, -0x09], + [+0x01, +0x00, +0x01, +0x02, -0x04, +0x02, +0x02, +0x01, +0x01, -0x02, -0x03, +0x01, -0x01, -0x04, +0x00, +0x01, +0x00, -0x06, -0x04, -0x01, +0x02, +0x02, +0x00, -0x09], + [+0x00, +0x01, +0x01, +0x02, -0x05, +0x02, +0x02, +0x01, +0x02, -0x02, -0x02, +0x01, -0x01, -0x05, +0x01, +0x00, +0x00, -0x06, -0x04, -0x01, +0x02, +0x02, +0x00, -0x09], + [+0x00, +0x00, +0x00, +0x00, -0x02, +0x00, +0x00, +0x00, +0x00, +0x00, -0x01, +0x00, +0x00, -0x02, +0x00, +0x00, +0x00, -0x04, -0x02, +0x00, +0x00, +0x00, +0x00, -0x09], + [-0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, -0x09, +0x01]] + +PAM_VOCABULARY = { + "A": 0, + "R": 1, + "N": 2, + "D": 3, + "C": 4, + "Q": 5, + "E": 6, + "G": 7, + "H": 8, + "I": 9, + "L": 10, + "K": 11, + "M": 12, + "F": 13, + "P": 14, + "S": 15, + "T": 16, + "W": 17, + "Y": 18, + "V": 19, + "B": 20, + "J": 21, + "Z": 22, + "X": 23, + "*": 24, +} diff --git a/src/beignet/datasets/_msa_dataset.py b/src/beignet/datasets/_msa_dataset.py new file mode 100644 index 0000000000..f367f0c6fa --- /dev/null +++ b/src/beignet/datasets/_msa_dataset.py @@ -0,0 +1,104 @@ +from pathlib import Path +from typing import Callable + +from torch import Tensor +from torch.utils.data import Dataset + +import numpy +import pooch +import torch + +class MSADataset(Dataset): + def __init__( + self, + root: str | Path, + *, + download: bool = False, + transform: Callable | None = None, + target_transform: Callable | None = None, + ): + if isinstance(root, str): + root = Path(root) + + name = self.__class__.__name__ + + if download: + pooch.retrieve( + f"https://files.ipd.uw.edu/krypton/data_unalign.npz", + fname=f"{name}.npz", + known_hash="9cc22e381619b66fc353c079221fd02450705d4e3ee23e4e23a052b6e70a95ec", + path=root / name, + ) + + self.all_data = numpy.load(root / name / f"{name}.npz", allow_pickle=True) + + all_sequences = [] + all_alignments = [] + all_sizes = [] + all_matrices = [] + + # process each subset + for subset in self.all_data.files: + data = self.all_data[subset].tolist() + + # pad sequences + sequences = torch.nested.to_padded_tensor( + torch.nested.nested_tensor(data["ms"]), + 0.0, + ) + sequences = torch.concatenate( + [ + torch.eye(torch.max(sequences) + 1), + torch.zeros([1, torch.max(sequences) + 1]), + ], + )[sequences] + + reference_sequence, sequences = sequences[0].unsqueeze(0), sequences[1:] + all_sequences.append(sequences) + + sizes = torch.tensor([len(seq) for seq in sequences]) + all_sizes.append(sizes) + + # pad alignments + alignments = torch.nested.to_padded_tensor( + torch.nested.nested_tensor(data["aln"]), + 0.0, + ) + + alignments = torch.concatenate( + [ + torch.eye(torch.max(alignments) + 1), + torch.zeros([1, torch.max(alignments) + 1]), + ], + )[alignments] + + _, alignments = alignments[0], alignments[1:] # ignore first alignment + all_alignments.append(alignments) + + matrices = make_similarity_matrices(sequences, reference_sequence) # TODO (Edith): make matrices + all_matrices.append(matrices) + + self.sequences = torch.stack(all_sequences, dim=1) + self.alignments = torch.stack(all_alignments, dim=1) + self.sizes = torch.stack(all_sizes, dim=1) + self.matrices = torch.stack(all_matrices, dim=1) + + self.transform = transform + + self.target_transform = target_transform + + def __len__(self): + return self.sequences.size(0) + + def __getitem__(self, index: int) -> tuple[Tensor, Tensor]: + inputs = self.matrices[index], self.sizes[index] + + if self.transform: + inputs = self.transform(*inputs) + + target = self.alignments[index] + + if self.target_transform: + target = self.target_transform(target) + + return inputs, target \ No newline at end of file diff --git a/src/beignet/lightning/__init__.py b/src/beignet/lightning/__init__.py new file mode 100644 index 0000000000..70119e4981 --- /dev/null +++ b/src/beignet/lightning/__init__.py @@ -0,0 +1 @@ +from ._msa_lightning_module import MSALightningModule diff --git a/src/beignet/lightning/_msa_lightning_module.py b/src/beignet/lightning/_msa_lightning_module.py new file mode 100644 index 0000000000..20c64760b8 --- /dev/null +++ b/src/beignet/lightning/_msa_lightning_module.py @@ -0,0 +1,27 @@ +from lightning import LightningModule + +from beignet.nn import MSA + + +class MSALightningModule(LightningModule): + def __init__( + self, + in_channels: int, + out_channels: int = 512, + kernel_size: int = 18, + *, + gap_penalty: float = 0.0, + temperature: float = 1.0, + ): + super().__init__() + + self.module = MSA( + in_channels, + out_channels, + kernel_size, + gap_penalty=gap_penalty, + temperature=temperature, + ) + + def forward(self, x): + return self.model(x) diff --git a/src/beignet/nn/__init__.py b/src/beignet/nn/__init__.py new file mode 100644 index 0000000000..d56ceb7aee --- /dev/null +++ b/src/beignet/nn/__init__.py @@ -0,0 +1 @@ +from ._msa import MSA diff --git a/src/beignet/nn/_msa.py b/src/beignet/nn/_msa.py new file mode 100644 index 0000000000..92d6b7eeac --- /dev/null +++ b/src/beignet/nn/_msa.py @@ -0,0 +1,56 @@ +import torch +from torch import Tensor +from torch.nn import Conv1d, Module + +import beignet.operators + + +class MSA(Module): + def __init__( + self, + in_channels: int, + out_channels: int = 512, + kernel_size: int = 18, + *, + gap_penalty: float = 0.0, + temperature: float = 1.0, + ): + super().__init__() + + self.gap_penalty = gap_penalty + + self.temperature = temperature + + self.embedding = Conv1d( + in_channels, + out_channels, + kernel_size, + padding="same", + ) + + def forward(self, inputs: (Tensor, Tensor)) -> Tensor: + matrices, shapes = inputs + + embedding = self.embedding(matrices) + + embedding = embedding @ embedding[0].T + + output = beignet.operators.needleman_wunsch( + embedding, + shapes, + gap_penalty=self.gap_penalty, + temperature=self.temperature, + ) + + return torch.einsum( + "ja, nij -> nia", + torch.mean( + torch.einsum( + "nia, nij -> nja", + matrices, + output, + ), + dim=0, + ), + output, + ) diff --git a/src/beignet/operators/__init__.py b/src/beignet/operators/__init__.py new file mode 100644 index 0000000000..e281919d3c --- /dev/null +++ b/src/beignet/operators/__init__.py @@ -0,0 +1,7 @@ +from ._needleman_wunsch import needleman_wunsch +from ._smith_waterman import smith_waterman + +__all__ = [ + "needleman_wunsch", + "smith_waterman", +] diff --git a/src/beignet/operators/_needleman_wunsch.py b/src/beignet/operators/_needleman_wunsch.py new file mode 100644 index 0000000000..166f294ab7 --- /dev/null +++ b/src/beignet/operators/_needleman_wunsch.py @@ -0,0 +1,194 @@ +import math +import operator + +import torch +import torch.func +import torch.nn.functional +from torch import Tensor + + +def needleman_wunsch( + input: Tensor, + lengths: Tensor, + gap_penalty: float = 0.0, + temperature: float = 1.0, +): + def fn(x: Tensor, shape: Tensor) -> Tensor: + padded = torch.nn.functional.pad(x, [1, 0, 1, 0]) + + i = torch.add( + torch.subtract( + torch.arange( + padded.size(1), + )[None, :], + torch.flip( + torch.arange( + padded.size(0), + ), + dims=[0], + )[:, None], + ), + operator.sub( + padded.size(0), + 1, + ), + ) + + j = torch.floor_divide( + torch.add( + torch.flip( + torch.arange( + padded.size(0), + ), + dims=[0], + )[:, None], + torch.arange( + padded.size(1), + )[None, :], + ), + 2, + ) + + m = operator.sub( + operator.add( + padded.size(0), + padded.size(1), + ), + 1, + ) + + n = operator.floordiv( + operator.add( + padded.size(0), + padded.size(1), + ), + 2, + ) + + y = torch.zeros([m, n], dtype=padded.dtype) + + initialization = torch.zeros( + [ + padded.size(0), + padded.size(1), + ], + dtype=padded.dtype, + ) + + initialization[:, 0] = torch.multiply( + torch.arange(padded.size(0)), + gap_penalty, + ) + + initialization[0, :] = torch.multiply( + torch.arange(padded.size(1)), + gap_penalty, + ) + + initialization = y.index_put( + [i, j], + initialization, + ) + + previous = torch.zeros(n) + + previous_previous = torch.zeros(n) + + traceback = torch.zeros([m, n]) + + mask = y.index_put( + [i, j], + torch.nn.functional.pad( + torch.multiply( + torch.less( + torch.arange(x.size(0)), + shape[0], + )[:, None], + torch.less( + torch.arange(x.size(1)), + shape[1], + )[None, :], + ), + [1, 0, 1, 0], + ).to(x.dtype), + ) + + striped_indexes = torch.fmod( + torch.add( + torch.arange(m), + math.fmod( + padded.size(0), + 2, + ), + ), + 2, + ) + + padded = y.index_put([i, j], padded) + + for index in range(m): + # TRACEBACK: + traceback[index] = torch.add( + # APPLY MASK: + torch.multiply( + # SMOOTH: + torch.multiply( + # APPLY SOFTMAX: + torch.logsumexp( + torch.divide( + torch.stack( + [ + # ALIGN: + torch.add( + previous_previous, + padded[index], + ), + previous + gap_penalty, + # CHANGE DIRECTION: + torch.add( + torch.add( + # INSERT: + torch.multiply( + torch.nn.functional.pad( + previous[:-1], + [1, 0], + ), + striped_indexes[index], + ), + # DELETE: + torch.multiply( + torch.nn.functional.pad( + previous[+1:], + [0, 1], + ), + operator.sub( + 1, + striped_indexes[index], + ), + ), + ), + gap_penalty, + ), + ], + ), + temperature, + ), + dim=0, + ), + temperature, + ), + mask[index], + ), + initialization[index], + ) + + previous_previous, previous = previous, traceback[index] + + return traceback[i, j][shape[0], shape[1]] + + output = torch.empty_like(input) + + for index in range(input.shape[0]): + output[index] = torch.func.grad(fn)(input[index], lengths[index]) + + return output diff --git a/src/beignet/operators/_smith_waterman.py b/src/beignet/operators/_smith_waterman.py new file mode 100644 index 0000000000..63041583e1 --- /dev/null +++ b/src/beignet/operators/_smith_waterman.py @@ -0,0 +1,199 @@ +# @title `smith_waterman` + + +import torch +import torch.func +from torch import Tensor + + +def smith_waterman( + input: Tensor, + lengths: (int, int), + gap_penalty: float = 0.0, + temperature: float = 1.0, +) -> Tensor: + """ + Compute the Smith-Waterman alignment score for two sequences. + + The Smith-Waterman algorithm is a local sequence alignment method used + to identify regions of similarity between two sequences. + + Parameters + ---------- + input : Tensor + The similarity matrix of the two sequences. + + lengths : Sequence[int, int] + A sequence containing the lengths of the two sequences being aligned. + + gap_penalty : float, optional + The penalty for creating a gap in alignment. Default is 0. + + temperature : float, optional + Scaling factor to control the sharpness of the score distribution. + Default is 1.0. + + Returns + ------- + Tensor + Smith-Waterman alignment score for the given sequences. + """ + + def fn( + input: Tensor, + lengths: (int, int), + ) -> Tensor: + if input.is_complex() or input.is_floating_point(): + initial_value = torch.finfo(input.dtype).min + else: + initial_value = torch.iinfo(input.dtype).min + + # BOOLEAN MASK TO IDENTIFY VALID POSITIONS: + + a = torch.arange(input.shape[0], device=input.device) + b = torch.arange(input.shape[1], device=input.device) + mask = torch.multiply( + torch.less( + a, + lengths[0], + )[:, None], + torch.less( + b, + lengths[1], + )[None, :], + ) + + # MASK INVALID POSITIONS: + # INVERT MASK TO IDENTIFY INVALID POSITIONS: + # VALUE APPLIED TO INVALID POSITIONS: + + masked_similarity_matrices = input + ~mask * initial_value + + # EXCLUDED LAST ROW AND COLUMN FROM MASKED SIMILARITY MATRICES: + x_1 = masked_similarity_matrices[ + : masked_similarity_matrices.shape[0] - 1, + : masked_similarity_matrices.shape[1] - 1, + ] + + # INDICES FOR ROTATING THE MATRICES TO ALIGN DIAGONALS FOR SCORING: + rotation_i = torch.flip(torch.arange(x_1.shape[0]), dims=[0])[:, None] + rotation_j = torch.arange(x_1.shape[1])[None, :] + + # INDICES FOR SCORING ALIGNMENT PATHS THROUGH THE MATRIX MATRICES: + indexes_i = rotation_j - rotation_i + x_1.shape[0] - 1 + indexes_j = (rotation_i + rotation_j) // 2 + + # DIMENSIONS OF THE SCORING MATRICES: + scores_shape_0 = x_1.shape[0] + x_1.shape[1] - 1 + scores_shape_1 = (x_1.shape[0] + x_1.shape[1]) // 2 + + initial_value = -1e10 + + # PREVIOUS SCORING MATRICES: + previous_scores = torch.full( + [scores_shape_1], initial_value, device=input.device + ) + + previous_scores = (previous_scores, previous_scores) + + # LIST TO ACCUMULATE SCORING MATRICES FOR EACH STEP OF THE ALIGNMENT: + scores = [] + + # INDICES TO MANAGE ALTERNATING UPDATES: + current_scores_i = torch.fmod( + torch.arange(scores_shape_0) + x_1.shape[0] % 2, 2 + ) + + # SCORING MATRICES WITH `initial_value`: + current_scores_j = torch.full( + [ + scores_shape_0, + scores_shape_1, + ], + initial_value, + device=input.device, + ) + + # INITIAL SCORING MATRICES WITH VALUES FROM THE MASKED SIMILARITY MATRICES: + current_scores_j = current_scores_j.index_put([indexes_i, indexes_j], x_1) + + current_scores_j[indexes_i, indexes_j] = x_1 + + initial_value = torch.tensor([initial_value], device=input.device) + + # LOOP THROUGH EACH SCORE: + for current_scores in zip(current_scores_i, current_scores_j, strict=False): + # SCORE FOR EXTENDING ALIGNMENT WITHOUT A GAP: + torch_add = previous_scores[0] + current_scores[1] + + # SCORE FOR INTRODUCING A GAP: + t = previous_scores[1] + gap_penalty + + # SCORE FOR OPENING OR EXTENDING A GAP: + torch_concatenate = torch.concatenate( + [ + initial_value, + previous_scores[1][:-1], + ], + ) + + concatenate = torch.concatenate( + [ + previous_scores[1][1:], + initial_value, + ], + ) + + tensor = ( + current_scores[0] * torch_concatenate + + (1 - current_scores[0]) * concatenate + + gap_penalty + ) + + # APPLYING GAP PENALTIES: + current_scores = torch.stack( + [ + torch_add, + t, + tensor, + # ORIGINAL SCORE FOR THE POSITION: + current_scores[1], + ], + dim=-1, + ) + + current_scores = current_scores / temperature + + current_scores = torch.maximum(current_scores, initial_value) + + # LOG-SUM-EXP FOR NUMERICAL STABILITY: + current_scores = torch.special.logsumexp(current_scores, dim=-1) + + # SCORING MATRICES: + current_scores = current_scores * temperature + + # UPDATE THE SCORES FOR THE NEXT ITERATION: + previous_scores = previous_scores[1], current_scores + + # ACCUMULATE UPDATED SCORES: + scores = [*scores, current_scores] + + scores = torch.stack(scores)[indexes_i, indexes_j] + + # COMBINE THE FINAL SCORES AND THE ORIGINAL SIMILARITY MATRIX: + scores = scores + masked_similarity_matrices[1:, 1:] + + # ADJUST FOR TEMPERATURE: + scores = scores / temperature + + score = torch.exp(scores - torch.max(scores)) + + # APPLY MASK TO SCORING MATRICES: + # SMITH-WATERMAN SCORES: + score = ( + torch.log(torch.sum(score * mask[1:, 1:])) + torch.max(scores) + ) * temperature + + return score + + return torch.func.vmap(torch.func.grad(fn), (0, 0))(input, lengths) diff --git a/src/beignet/ops/__init__.py b/src/beignet/ops/__init__.py new file mode 100644 index 0000000000..90534a8648 --- /dev/null +++ b/src/beignet/ops/__init__.py @@ -0,0 +1,89 @@ +from ._geometry import ( + apply_euler_angle, + apply_quaternion, + apply_rotation_matrix, + apply_rotation_vector, + compose_euler_angle, + compose_quaternion, + compose_rotation_matrix, + compose_rotation_vector, + euler_angle_identity, + euler_angle_magnitude, + euler_angle_mean, + euler_angle_to_quaternion, + euler_angle_to_rotation_matrix, + euler_angle_to_rotation_vector, + invert_euler_angle, + invert_quaternion, + invert_rotation_matrix, + invert_rotation_vector, + quaternion_identity, + quaternion_magnitude, + quaternion_mean, + quaternion_slerp, + quaternion_to_euler_angle, + quaternion_to_rotation_matrix, + quaternion_to_rotation_vector, + random_euler_angle, + random_quaternion, + random_rotation_matrix, + random_rotation_vector, + rotation_matrix_identity, + rotation_matrix_magnitude, + rotation_matrix_mean, + rotation_matrix_to_euler_angle, + rotation_matrix_to_quaternion, + rotation_matrix_to_rotation_vector, + rotation_vector_identity, + rotation_vector_magnitude, + rotation_vector_mean, + rotation_vector_to_euler_angle, + rotation_vector_to_quaternion, + rotation_vector_to_rotation_matrix, + translation_identity, +) + +__all__ = [ + "apply_euler_angle", + "apply_quaternion", + "apply_rotation_matrix", + "apply_rotation_vector", + "compose_euler_angle", + "compose_quaternion", + "compose_rotation_matrix", + "compose_rotation_vector", + "euler_angle_identity", + "euler_angle_magnitude", + "euler_angle_mean", + "euler_angle_to_quaternion", + "euler_angle_to_rotation_matrix", + "euler_angle_to_rotation_vector", + "invert_euler_angle", + "invert_quaternion", + "invert_rotation_matrix", + "invert_rotation_vector", + "quaternion_identity", + "quaternion_magnitude", + "quaternion_mean", + "quaternion_to_euler_angle", + "quaternion_to_rotation_matrix", + "quaternion_to_rotation_vector", + "random_euler_angle", + "random_quaternion", + "random_rotation_matrix", + "random_rotation_vector", + "rotation_matrix_identity", + "rotation_matrix_magnitude", + "rotation_matrix_mean", + "rotation_matrix_to_euler_angle", + "rotation_matrix_to_quaternion", + "rotation_matrix_to_rotation_vector", + "rotation_vector_identity", + "rotation_vector_magnitude", + "rotation_vector_mean", + "rotation_vector_to_euler_angle", + "rotation_vector_to_quaternion", + "rotation_vector_to_rotation_matrix", + "quaternion_slerp", + "translation_identity", +] diff --git a/src/beignet/ops/_geometry/__init__.py b/src/beignet/ops/_geometry/__init__.py new file mode 100644 index 0000000000..2d065e7f7f --- /dev/null +++ b/src/beignet/ops/_geometry/__init__.py @@ -0,0 +1,44 @@ +from ._transformations import ( + apply_euler_angle, + apply_quaternion, + apply_rotation_matrix, + apply_rotation_vector, + compose_euler_angle, + compose_quaternion, + compose_rotation_matrix, + compose_rotation_vector, + euler_angle_identity, + euler_angle_magnitude, + euler_angle_mean, + euler_angle_to_quaternion, + euler_angle_to_rotation_matrix, + euler_angle_to_rotation_vector, + invert_euler_angle, + invert_quaternion, + invert_rotation_matrix, + invert_rotation_vector, + quaternion_identity, + quaternion_magnitude, + quaternion_mean, + quaternion_slerp, + quaternion_to_euler_angle, + quaternion_to_rotation_matrix, + quaternion_to_rotation_vector, + random_euler_angle, + random_quaternion, + random_rotation_matrix, + random_rotation_vector, + rotation_matrix_identity, + rotation_matrix_magnitude, + rotation_matrix_mean, + rotation_matrix_to_euler_angle, + rotation_matrix_to_quaternion, + rotation_matrix_to_rotation_vector, + rotation_vector_identity, + rotation_vector_magnitude, + rotation_vector_mean, + rotation_vector_to_euler_angle, + rotation_vector_to_quaternion, + rotation_vector_to_rotation_matrix, + translation_identity, +) diff --git a/src/beignet/ops/_geometry/_transformations/__init__.py b/src/beignet/ops/_geometry/_transformations/__init__.py new file mode 100644 index 0000000000..5f64c220b5 --- /dev/null +++ b/src/beignet/ops/_geometry/_transformations/__init__.py @@ -0,0 +1,60 @@ +from ._apply_euler_angle import apply_euler_angle +from ._apply_quaternion import ( + apply_quaternion, +) +from ._apply_rotation_matrix import apply_rotation_matrix +from ._apply_rotation_vector import apply_rotation_vector +from ._compose_euler_angle import compose_euler_angle +from ._compose_quaternion import compose_quaternion +from ._compose_rotation_matrix import compose_rotation_matrix +from ._compose_rotation_vector import compose_rotation_vector +from ._euler_angle_identity import euler_angle_identity +from ._euler_angle_magnitude import euler_angle_magnitude +from ._euler_angle_mean import euler_angle_mean +from ._euler_angle_to_quaternion import ( + euler_angle_to_quaternion, +) +from ._euler_angle_to_rotation_matrix import euler_angle_to_rotation_matrix +from ._euler_angle_to_rotation_vector import euler_angle_to_rotation_vector +from ._invert_euler_angle import invert_euler_angle +from ._invert_quaternion import invert_quaternion +from ._invert_rotation_matrix import invert_rotation_matrix +from ._invert_rotation_vector import invert_rotation_vector +from ._quaternion_identity import quaternion_identity +from ._quaternion_magnitude import quaternion_magnitude +from ._quaternion_mean import quaternion_mean +from ._quaternion_slerp import quaternion_slerp +from ._quaternion_to_euler_angle import ( + quaternion_to_euler_angle, +) +from ._quaternion_to_rotation_matrix import ( + quaternion_to_rotation_matrix, +) +from ._quaternion_to_rotation_vector import ( + quaternion_to_rotation_vector, +) +from ._random_euler_angle import random_euler_angle +from ._random_quaternion import random_quaternion +from ._random_rotation_matrix import random_rotation_matrix +from ._random_rotation_vector import random_rotation_vector +from ._rotation_matrix_identity import rotation_matrix_identity +from ._rotation_matrix_magnitude import rotation_matrix_magnitude +from ._rotation_matrix_mean import rotation_matrix_mean +from ._rotation_matrix_to_euler_angle import rotation_matrix_to_euler_angle +from ._rotation_matrix_to_quaternion import ( + rotation_matrix_to_quaternion, +) +from ._rotation_matrix_to_rotation_vector import ( + rotation_matrix_to_rotation_vector, +) +from ._rotation_vector_identity import rotation_vector_identity +from ._rotation_vector_magnitude import rotation_vector_magnitude +from ._rotation_vector_mean import rotation_vector_mean +from ._rotation_vector_to_euler_angle import rotation_vector_to_euler_angle +from ._rotation_vector_to_quaternion import ( + rotation_vector_to_quaternion, +) +from ._rotation_vector_to_rotation_matrix import ( + rotation_vector_to_rotation_matrix, +) +from ._translation_identity import translation_identity diff --git a/src/beignet/ops/_geometry/_transformations/_apply_euler_angle.py b/src/beignet/ops/_geometry/_transformations/_apply_euler_angle.py new file mode 100644 index 0000000000..3cb9f09079 --- /dev/null +++ b/src/beignet/ops/_geometry/_transformations/_apply_euler_angle.py @@ -0,0 +1,63 @@ +from torch import Tensor + +from ._apply_rotation_matrix import apply_rotation_matrix +from ._euler_angle_to_rotation_matrix import euler_angle_to_rotation_matrix + + +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, + ) diff --git a/src/beignet/ops/_geometry/_transformations/_apply_quaternion.py b/src/beignet/ops/_geometry/_transformations/_apply_quaternion.py new file mode 100644 index 0000000000..1410453b88 --- /dev/null +++ b/src/beignet/ops/_geometry/_transformations/_apply_quaternion.py @@ -0,0 +1,52 @@ +from torch import Tensor + +from ._apply_rotation_matrix import apply_rotation_matrix +from ._quaternion_to_rotation_matrix import ( + quaternion_to_rotation_matrix, +) + + +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, + ) diff --git a/src/beignet/ops/_geometry/_transformations/_apply_rotation_matrix.py b/src/beignet/ops/_geometry/_transformations/_apply_rotation_matrix.py new file mode 100644 index 0000000000..fcac443401 --- /dev/null +++ b/src/beignet/ops/_geometry/_transformations/_apply_rotation_matrix.py @@ -0,0 +1,47 @@ +import torch +from torch import Tensor + + +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 diff --git a/src/beignet/ops/_geometry/_transformations/_apply_rotation_vector.py b/src/beignet/ops/_geometry/_transformations/_apply_rotation_vector.py new file mode 100644 index 0000000000..0682bd4ac6 --- /dev/null +++ b/src/beignet/ops/_geometry/_transformations/_apply_rotation_vector.py @@ -0,0 +1,63 @@ +from torch import Tensor + +from ._apply_rotation_matrix import apply_rotation_matrix +from ._quaternion_to_rotation_matrix import ( + quaternion_to_rotation_matrix, +) +from ._rotation_vector_to_quaternion import ( + rotation_vector_to_quaternion, +) + + +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, + ) diff --git a/src/beignet/ops/_geometry/_transformations/_compose_euler_angle.py b/src/beignet/ops/_geometry/_transformations/_compose_euler_angle.py new file mode 100644 index 0000000000..3427d724dc --- /dev/null +++ b/src/beignet/ops/_geometry/_transformations/_compose_euler_angle.py @@ -0,0 +1,53 @@ +from torch import Tensor + +from ._compose_quaternion import compose_quaternion +from ._euler_angle_to_quaternion import euler_angle_to_quaternion +from ._quaternion_to_euler_angle import quaternion_to_euler_angle + + +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, + ) diff --git a/src/beignet/ops/_geometry/_transformations/_compose_quaternion.py b/src/beignet/ops/_geometry/_transformations/_compose_quaternion.py new file mode 100644 index 0000000000..35d0b30ae9 --- /dev/null +++ b/src/beignet/ops/_geometry/_transformations/_compose_quaternion.py @@ -0,0 +1,73 @@ +import torch +from torch import Tensor + + +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 diff --git a/src/beignet/ops/_geometry/_transformations/_compose_rotation_matrix.py b/src/beignet/ops/_geometry/_transformations/_compose_rotation_matrix.py new file mode 100644 index 0000000000..10b6ce1582 --- /dev/null +++ b/src/beignet/ops/_geometry/_transformations/_compose_rotation_matrix.py @@ -0,0 +1,33 @@ +from torch import Tensor + +from ._compose_quaternion import compose_quaternion +from ._quaternion_to_rotation_matrix import quaternion_to_rotation_matrix +from ._rotation_matrix_to_quaternion import rotation_matrix_to_quaternion + + +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), + ), + ) diff --git a/src/beignet/ops/_geometry/_transformations/_compose_rotation_vector.py b/src/beignet/ops/_geometry/_transformations/_compose_rotation_vector.py new file mode 100644 index 0000000000..d15223e489 --- /dev/null +++ b/src/beignet/ops/_geometry/_transformations/_compose_rotation_vector.py @@ -0,0 +1,45 @@ +from torch import Tensor + +from ._compose_quaternion import compose_quaternion +from ._quaternion_to_rotation_vector import quaternion_to_rotation_vector +from ._rotation_vector_to_quaternion import rotation_vector_to_quaternion + + +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, + ) diff --git a/src/beignet/ops/_geometry/_transformations/_euler_angle_identity.py b/src/beignet/ops/_geometry/_transformations/_euler_angle_identity.py new file mode 100644 index 0000000000..40c716cf3a --- /dev/null +++ b/src/beignet/ops/_geometry/_transformations/_euler_angle_identity.py @@ -0,0 +1,70 @@ +import torch +from torch import Tensor + +from ._quaternion_identity import quaternion_identity +from ._quaternion_to_euler_angle import ( + quaternion_to_euler_angle, +) + + +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, + ) diff --git a/src/beignet/ops/_geometry/_transformations/_euler_angle_magnitude.py b/src/beignet/ops/_geometry/_transformations/_euler_angle_magnitude.py new file mode 100644 index 0000000000..3429062d09 --- /dev/null +++ b/src/beignet/ops/_geometry/_transformations/_euler_angle_magnitude.py @@ -0,0 +1,41 @@ +from torch import Tensor + +from ._euler_angle_to_quaternion import ( + euler_angle_to_quaternion, +) +from ._quaternion_magnitude import quaternion_magnitude + + +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, + ), + ) diff --git a/src/beignet/ops/_geometry/_transformations/_euler_angle_mean.py b/src/beignet/ops/_geometry/_transformations/_euler_angle_mean.py new file mode 100644 index 0000000000..5e711958bc --- /dev/null +++ b/src/beignet/ops/_geometry/_transformations/_euler_angle_mean.py @@ -0,0 +1,49 @@ +from torch import Tensor + +from ._euler_angle_to_quaternion import euler_angle_to_quaternion +from ._quaternion_mean import quaternion_mean +from ._quaternion_to_euler_angle import quaternion_to_euler_angle + + +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, + ) diff --git a/src/beignet/ops/_geometry/_transformations/_euler_angle_to_quaternion.py b/src/beignet/ops/_geometry/_transformations/_euler_angle_to_quaternion.py new file mode 100644 index 0000000000..7736d8171b --- /dev/null +++ b/src/beignet/ops/_geometry/_transformations/_euler_angle_to_quaternion.py @@ -0,0 +1,170 @@ +import re + +import torch +from torch import Tensor + + +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 diff --git a/src/beignet/ops/_geometry/_transformations/_euler_angle_to_rotation_matrix.py b/src/beignet/ops/_geometry/_transformations/_euler_angle_to_rotation_matrix.py new file mode 100644 index 0000000000..2d1baf1c28 --- /dev/null +++ b/src/beignet/ops/_geometry/_transformations/_euler_angle_to_rotation_matrix.py @@ -0,0 +1,80 @@ +import torch +from torch import Tensor + + +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 diff --git a/src/beignet/ops/_geometry/_transformations/_euler_angle_to_rotation_vector.py b/src/beignet/ops/_geometry/_transformations/_euler_angle_to_rotation_vector.py new file mode 100644 index 0000000000..19dd27cc48 --- /dev/null +++ b/src/beignet/ops/_geometry/_transformations/_euler_angle_to_rotation_vector.py @@ -0,0 +1,253 @@ +import re + +import torch +from torch import Tensor + + +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 diff --git a/src/beignet/ops/_geometry/_transformations/_invert_euler_angle.py b/src/beignet/ops/_geometry/_transformations/_invert_euler_angle.py new file mode 100644 index 0000000000..9a7c3c6a6d --- /dev/null +++ b/src/beignet/ops/_geometry/_transformations/_invert_euler_angle.py @@ -0,0 +1,48 @@ +from torch import Tensor + +from ._euler_angle_to_quaternion import ( + euler_angle_to_quaternion, +) +from ._invert_quaternion import invert_quaternion +from ._quaternion_to_euler_angle import ( + quaternion_to_euler_angle, +) + + +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, + ) diff --git a/src/beignet/ops/_geometry/_transformations/_invert_quaternion.py b/src/beignet/ops/_geometry/_transformations/_invert_quaternion.py new file mode 100644 index 0000000000..9762327f75 --- /dev/null +++ b/src/beignet/ops/_geometry/_transformations/_invert_quaternion.py @@ -0,0 +1,31 @@ +from torch import Tensor + + +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 diff --git a/src/beignet/ops/_geometry/_transformations/_invert_rotation_matrix.py b/src/beignet/ops/_geometry/_transformations/_invert_rotation_matrix.py new file mode 100644 index 0000000000..4ceba7d74a --- /dev/null +++ b/src/beignet/ops/_geometry/_transformations/_invert_rotation_matrix.py @@ -0,0 +1,19 @@ +import torch +from torch import Tensor + + +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) diff --git a/src/beignet/ops/_geometry/_transformations/_invert_rotation_vector.py b/src/beignet/ops/_geometry/_transformations/_invert_rotation_vector.py new file mode 100644 index 0000000000..c592cdbb91 --- /dev/null +++ b/src/beignet/ops/_geometry/_transformations/_invert_rotation_vector.py @@ -0,0 +1,20 @@ +from torch import Tensor + + +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 diff --git a/src/beignet/ops/_geometry/_transformations/_quaternion_identity.py b/src/beignet/ops/_geometry/_transformations/_quaternion_identity.py new file mode 100644 index 0000000000..9474cb9669 --- /dev/null +++ b/src/beignet/ops/_geometry/_transformations/_quaternion_identity.py @@ -0,0 +1,64 @@ +import torch +from torch import Tensor + + +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 diff --git a/src/beignet/ops/_geometry/_transformations/_quaternion_magnitude.py b/src/beignet/ops/_geometry/_transformations/_quaternion_magnitude.py new file mode 100644 index 0000000000..7d2179c094 --- /dev/null +++ b/src/beignet/ops/_geometry/_transformations/_quaternion_magnitude.py @@ -0,0 +1,37 @@ +import torch +from torch import Tensor + + +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 diff --git a/src/beignet/ops/_geometry/_transformations/_quaternion_mean.py b/src/beignet/ops/_geometry/_transformations/_quaternion_mean.py new file mode 100644 index 0000000000..c6c0d369be --- /dev/null +++ b/src/beignet/ops/_geometry/_transformations/_quaternion_mean.py @@ -0,0 +1,34 @@ +import torch +from torch import Tensor + + +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 diff --git a/src/beignet/ops/_geometry/_transformations/_quaternion_slerp.py b/src/beignet/ops/_geometry/_transformations/_quaternion_slerp.py new file mode 100644 index 0000000000..694052a637 --- /dev/null +++ b/src/beignet/ops/_geometry/_transformations/_quaternion_slerp.py @@ -0,0 +1,93 @@ +import torch +import torch.testing +from torch import Tensor + + +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 diff --git a/src/beignet/ops/_geometry/_transformations/_quaternion_to_euler_angle.py b/src/beignet/ops/_geometry/_transformations/_quaternion_to_euler_angle.py new file mode 100644 index 0000000000..e66d7a6459 --- /dev/null +++ b/src/beignet/ops/_geometry/_transformations/_quaternion_to_euler_angle.py @@ -0,0 +1,143 @@ +import math +import re + +import torch +from torch import Tensor + + +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 diff --git a/src/beignet/ops/_geometry/_transformations/_quaternion_to_rotation_matrix.py b/src/beignet/ops/_geometry/_transformations/_quaternion_to_rotation_matrix.py new file mode 100644 index 0000000000..20d753af6b --- /dev/null +++ b/src/beignet/ops/_geometry/_transformations/_quaternion_to_rotation_matrix.py @@ -0,0 +1,43 @@ +import torch +from torch import Tensor + + +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 diff --git a/src/beignet/ops/_geometry/_transformations/_quaternion_to_rotation_vector.py b/src/beignet/ops/_geometry/_transformations/_quaternion_to_rotation_vector.py new file mode 100644 index 0000000000..6827c672e8 --- /dev/null +++ b/src/beignet/ops/_geometry/_transformations/_quaternion_to_rotation_vector.py @@ -0,0 +1,57 @@ +import torch +from torch import Tensor + + +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 diff --git a/src/beignet/ops/_geometry/_transformations/_random_euler_angle.py b/src/beignet/ops/_geometry/_transformations/_random_euler_angle.py new file mode 100644 index 0000000000..f41bea8995 --- /dev/null +++ b/src/beignet/ops/_geometry/_transformations/_random_euler_angle.py @@ -0,0 +1,91 @@ +import torch +from torch import Generator, Tensor + +from ._quaternion_to_euler_angle import ( + quaternion_to_euler_angle, +) +from ._random_quaternion import random_quaternion + + +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, + ) diff --git a/src/beignet/ops/_geometry/_transformations/_random_quaternion.py b/src/beignet/ops/_geometry/_transformations/_random_quaternion.py new file mode 100644 index 0000000000..468e4c3e8e --- /dev/null +++ b/src/beignet/ops/_geometry/_transformations/_random_quaternion.py @@ -0,0 +1,95 @@ +import torch +from torch import Generator, Tensor + + +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 diff --git a/src/beignet/ops/_geometry/_transformations/_random_rotation_matrix.py b/src/beignet/ops/_geometry/_transformations/_random_rotation_matrix.py new file mode 100644 index 0000000000..8d9368a1c4 --- /dev/null +++ b/src/beignet/ops/_geometry/_transformations/_random_rotation_matrix.py @@ -0,0 +1,69 @@ +import torch +from torch import Generator, Tensor + +from ._quaternion_to_rotation_matrix import ( + quaternion_to_rotation_matrix, +) +from ._random_quaternion import random_quaternion + + +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, + ), + ) diff --git a/src/beignet/ops/_geometry/_transformations/_random_rotation_vector.py b/src/beignet/ops/_geometry/_transformations/_random_rotation_vector.py new file mode 100644 index 0000000000..1cfb578a42 --- /dev/null +++ b/src/beignet/ops/_geometry/_transformations/_random_rotation_vector.py @@ -0,0 +1,73 @@ +import torch +from torch import Generator, Tensor + +from ._quaternion_to_rotation_vector import ( + quaternion_to_rotation_vector, +) +from ._random_quaternion import random_quaternion + + +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, + ) diff --git a/src/beignet/ops/_geometry/_transformations/_rotation_matrix_identity.py b/src/beignet/ops/_geometry/_transformations/_rotation_matrix_identity.py new file mode 100644 index 0000000000..4e646a5d85 --- /dev/null +++ b/src/beignet/ops/_geometry/_transformations/_rotation_matrix_identity.py @@ -0,0 +1,58 @@ +import torch +from torch import Tensor + +from ._quaternion_identity import quaternion_identity +from ._quaternion_to_rotation_matrix import ( + quaternion_to_rotation_matrix, +) + + +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, + ), + ) diff --git a/src/beignet/ops/_geometry/_transformations/_rotation_matrix_magnitude.py b/src/beignet/ops/_geometry/_transformations/_rotation_matrix_magnitude.py new file mode 100644 index 0000000000..74c39721c7 --- /dev/null +++ b/src/beignet/ops/_geometry/_transformations/_rotation_matrix_magnitude.py @@ -0,0 +1,27 @@ +from torch import Tensor + +from ._quaternion_magnitude import quaternion_magnitude +from ._rotation_matrix_to_quaternion import ( + rotation_matrix_to_quaternion, +) + + +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, + ), + ) diff --git a/src/beignet/ops/_geometry/_transformations/_rotation_matrix_mean.py b/src/beignet/ops/_geometry/_transformations/_rotation_matrix_mean.py new file mode 100644 index 0000000000..0fb8bce5a5 --- /dev/null +++ b/src/beignet/ops/_geometry/_transformations/_rotation_matrix_mean.py @@ -0,0 +1,32 @@ +from torch import Tensor + +from ._quaternion_mean import quaternion_mean +from ._quaternion_to_rotation_matrix import quaternion_to_rotation_matrix +from ._rotation_matrix_to_quaternion import rotation_matrix_to_quaternion + + +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, + ), + ) diff --git a/src/beignet/ops/_geometry/_transformations/_rotation_matrix_to_euler_angle.py b/src/beignet/ops/_geometry/_transformations/_rotation_matrix_to_euler_angle.py new file mode 100644 index 0000000000..cf6515a939 --- /dev/null +++ b/src/beignet/ops/_geometry/_transformations/_rotation_matrix_to_euler_angle.py @@ -0,0 +1,51 @@ +from torch import Tensor + +from ._quaternion_to_euler_angle import ( + quaternion_to_euler_angle, +) +from ._rotation_matrix_to_quaternion import ( + rotation_matrix_to_quaternion, +) + + +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, + ) diff --git a/src/beignet/ops/_geometry/_transformations/_rotation_matrix_to_quaternion.py b/src/beignet/ops/_geometry/_transformations/_rotation_matrix_to_quaternion.py new file mode 100644 index 0000000000..c415a6f888 --- /dev/null +++ b/src/beignet/ops/_geometry/_transformations/_rotation_matrix_to_quaternion.py @@ -0,0 +1,88 @@ +import torch +from torch import Tensor + + +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 diff --git a/src/beignet/ops/_geometry/_transformations/_rotation_matrix_to_rotation_vector.py b/src/beignet/ops/_geometry/_transformations/_rotation_matrix_to_rotation_vector.py new file mode 100644 index 0000000000..75409a01b0 --- /dev/null +++ b/src/beignet/ops/_geometry/_transformations/_rotation_matrix_to_rotation_vector.py @@ -0,0 +1,37 @@ +from torch import Tensor + +from ._quaternion_to_rotation_vector import ( + quaternion_to_rotation_vector, +) +from ._rotation_matrix_to_quaternion import ( + rotation_matrix_to_quaternion, +) + + +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, + ) diff --git a/src/beignet/ops/_geometry/_transformations/_rotation_vector_identity.py b/src/beignet/ops/_geometry/_transformations/_rotation_vector_identity.py new file mode 100644 index 0000000000..29a0d0ad38 --- /dev/null +++ b/src/beignet/ops/_geometry/_transformations/_rotation_vector_identity.py @@ -0,0 +1,64 @@ +import torch +from torch import Tensor + +from ._quaternion_identity import quaternion_identity +from ._quaternion_to_rotation_vector import ( + quaternion_to_rotation_vector, +) + + +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, + ) diff --git a/src/beignet/ops/_geometry/_transformations/_rotation_vector_magnitude.py b/src/beignet/ops/_geometry/_transformations/_rotation_vector_magnitude.py new file mode 100644 index 0000000000..ceb1725235 --- /dev/null +++ b/src/beignet/ops/_geometry/_transformations/_rotation_vector_magnitude.py @@ -0,0 +1,34 @@ +from torch import Tensor + +from ._quaternion_magnitude import quaternion_magnitude +from ._rotation_vector_to_quaternion import ( + rotation_vector_to_quaternion, +) + + +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, + ), + ) diff --git a/src/beignet/ops/_geometry/_transformations/_rotation_vector_mean.py b/src/beignet/ops/_geometry/_transformations/_rotation_vector_mean.py new file mode 100644 index 0000000000..8fb8c2a968 --- /dev/null +++ b/src/beignet/ops/_geometry/_transformations/_rotation_vector_mean.py @@ -0,0 +1,42 @@ +from torch import Tensor + +from ._quaternion_mean import quaternion_mean +from ._quaternion_to_rotation_vector import quaternion_to_rotation_vector +from ._rotation_vector_to_quaternion import rotation_vector_to_quaternion + + +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, + ) diff --git a/src/beignet/ops/_geometry/_transformations/_rotation_vector_to_euler_angle.py b/src/beignet/ops/_geometry/_transformations/_rotation_vector_to_euler_angle.py new file mode 100644 index 0000000000..8ae5503d5c --- /dev/null +++ b/src/beignet/ops/_geometry/_transformations/_rotation_vector_to_euler_angle.py @@ -0,0 +1,48 @@ +from torch import Tensor + +from ._quaternion_to_euler_angle import ( + quaternion_to_euler_angle, +) +from ._rotation_vector_to_quaternion import ( + rotation_vector_to_quaternion, +) + + +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, + ) diff --git a/src/beignet/ops/_geometry/_transformations/_rotation_vector_to_quaternion.py b/src/beignet/ops/_geometry/_transformations/_rotation_vector_to_quaternion.py new file mode 100644 index 0000000000..92bd81b65a --- /dev/null +++ b/src/beignet/ops/_geometry/_transformations/_rotation_vector_to_quaternion.py @@ -0,0 +1,71 @@ +import torch +from torch import Tensor + + +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 diff --git a/src/beignet/ops/_geometry/_transformations/_rotation_vector_to_rotation_matrix.py b/src/beignet/ops/_geometry/_transformations/_rotation_vector_to_rotation_matrix.py new file mode 100644 index 0000000000..9259f8b233 --- /dev/null +++ b/src/beignet/ops/_geometry/_transformations/_rotation_vector_to_rotation_matrix.py @@ -0,0 +1,37 @@ +from torch import Tensor + +from ._quaternion_to_rotation_matrix import ( + quaternion_to_rotation_matrix, +) +from ._rotation_vector_to_quaternion import ( + rotation_vector_to_quaternion, +) + + +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, + ), + ) diff --git a/src/beignet/ops/_geometry/_transformations/_translation_identity.py b/src/beignet/ops/_geometry/_transformations/_translation_identity.py new file mode 100644 index 0000000000..1fa2b6966a --- /dev/null +++ b/src/beignet/ops/_geometry/_transformations/_translation_identity.py @@ -0,0 +1,51 @@ +import torch +from torch import Tensor + + +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, + ) diff --git a/tests/beignet/operators/test__needleman_wunsch.py b/tests/beignet/operators/test__needleman_wunsch.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/beignet/operators/test__smith_waterman.py b/tests/beignet/operators/test__smith_waterman.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/beignet/ops/_geometry/_transformations/test__apply_euler_angle.py b/tests/beignet/ops/_geometry/_transformations/test__apply_euler_angle.py new file mode 100644 index 0000000000..86aa0a1296 --- /dev/null +++ b/tests/beignet/ops/_geometry/_transformations/test__apply_euler_angle.py @@ -0,0 +1,94 @@ +import beignet.ops +import hypothesis.extra.numpy +import hypothesis.strategies +import numpy +import torch.testing +from scipy.spatial.transform import Rotation + + +@hypothesis.strategies.composite +def _strategy(function): + size = function( + hypothesis.strategies.integers( + min_value=1, + max_value=8, + ), + ) + + input = function( + hypothesis.extra.numpy.arrays( + numpy.float64, + (size, 3), + elements={ + "allow_infinity": False, + "min_value": numpy.finfo(numpy.float32).min, + "max_value": numpy.finfo(numpy.float32).max, + }, + ), + ) + + rotation = Rotation.random( + size, + ) + + axes = function( + hypothesis.strategies.sampled_from( + [ + "xyz", + "xzy", + "yxz", + "yzx", + "zxy", + "zyx", + "XYZ", + "XZY", + "YXZ", + "YZX", + "ZXY", + "ZYX", + ] + ), + ) + + degrees = function( + hypothesis.strategies.booleans(), + ) + + inverse = function( + hypothesis.strategies.booleans(), + ) + + return ( + { + "input": torch.from_numpy( + input, + ), + "rotation": torch.from_numpy( + rotation.as_euler( + axes, + degrees, + ), + ), + "axes": axes, + "degrees": degrees, + "inverse": inverse, + }, + torch.from_numpy( + rotation.apply( + input, + inverse, + ), + ), + ) + + +@hypothesis.given(_strategy()) +def test_apply_euler_angle(data): + parameters, expected = data + + torch.testing.assert_close( + beignet.ops.apply_euler_angle( + **parameters, + ), + expected, + ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__apply_quaternion.py b/tests/beignet/ops/_geometry/_transformations/test__apply_quaternion.py new file mode 100644 index 0000000000..83a874f815 --- /dev/null +++ b/tests/beignet/ops/_geometry/_transformations/test__apply_quaternion.py @@ -0,0 +1,53 @@ +import beignet.ops +import hypothesis.extra.numpy +import hypothesis.strategies +import numpy +import torch.testing +from scipy.spatial.transform import Rotation + + +@hypothesis.strategies.composite +def _strategy(function): + size = function( + hypothesis.strategies.integers( + min_value=1, + max_value=8, + ), + ) + + input = function( + hypothesis.extra.numpy.arrays( + numpy.float64, + (size, 3), + elements={ + "allow_infinity": False, + "min_value": numpy.finfo(numpy.float32).min, + "max_value": numpy.finfo(numpy.float32).max, + }, + ), + ) + + rotation = Rotation.random(size) + + canonical = function(hypothesis.strategies.booleans()) + + inverse = function(hypothesis.strategies.booleans()) + + return ( + { + "input": torch.from_numpy(input), + "rotation": torch.from_numpy(rotation.as_quat(canonical)), + "inverse": inverse, + }, + torch.from_numpy(rotation.apply(input, inverse)), + ) + + +@hypothesis.given(_strategy()) +def test_apply_quaternion(data): + parameters, expected = data + + torch.testing.assert_close( + beignet.ops.apply_quaternion(**parameters), + expected, + ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__apply_rotation_matrix.py b/tests/beignet/ops/_geometry/_transformations/test__apply_rotation_matrix.py new file mode 100644 index 0000000000..4ce23b05ac --- /dev/null +++ b/tests/beignet/ops/_geometry/_transformations/test__apply_rotation_matrix.py @@ -0,0 +1,65 @@ +import beignet.ops +import hypothesis.extra.numpy +import hypothesis.strategies +import numpy +import torch.testing +from scipy.spatial.transform import Rotation + + +@hypothesis.strategies.composite +def _strategy(function): + size = function( + hypothesis.strategies.integers( + min_value=1, + max_value=8, + ), + ) + + input = function( + hypothesis.extra.numpy.arrays( + numpy.float64, + (size, 3), + elements={ + "allow_infinity": False, + "min_value": numpy.finfo(numpy.float32).min, + "max_value": numpy.finfo(numpy.float32).max, + }, + ), + ) + + rotation = Rotation.random(size) + + inverse = function(hypothesis.strategies.booleans()) + + return ( + { + "input": torch.from_numpy( + input, + ), + "rotation": torch.from_numpy( + rotation.as_matrix(), + ), + "inverse": inverse, + }, + torch.from_numpy( + rotation.apply( + input, + inverse, + ), + ), + ) + + +@hypothesis.given(_strategy()) +def test_apply_rotation_matrix(data): + parameters, expected = data + + torch.testing.assert_close( + beignet.ops.apply_rotation_matrix( + **parameters, + ), + expected, + equal_nan=True, + atol=1e-06, + rtol=1e-06, + ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__apply_rotation_vector.py b/tests/beignet/ops/_geometry/_transformations/test__apply_rotation_vector.py new file mode 100644 index 0000000000..33a5aa31ec --- /dev/null +++ b/tests/beignet/ops/_geometry/_transformations/test__apply_rotation_vector.py @@ -0,0 +1,54 @@ +import beignet.ops +import hypothesis.extra.numpy +import hypothesis.strategies +import numpy +import torch.testing +from scipy.spatial.transform import Rotation + + +@hypothesis.strategies.composite +def _strategy(function): + size = function( + hypothesis.strategies.integers( + min_value=1, + max_value=8, + ), + ) + + input = function( + hypothesis.extra.numpy.arrays( + numpy.float64, + (size, 3), + elements={ + "allow_infinity": False, + "min_value": numpy.finfo(numpy.float32).min, + "max_value": numpy.finfo(numpy.float32).max, + }, + ), + ) + + rotation = Rotation.random(size) + + degrees = function(hypothesis.strategies.booleans()) + + inverse = function(hypothesis.strategies.booleans()) + + return ( + { + "input": torch.from_numpy(input), + "rotation": torch.from_numpy(rotation.as_rotvec(degrees)), + "degrees": degrees, + "inverse": inverse, + }, + torch.from_numpy(rotation.apply(input, inverse)), + ) + + +@hypothesis.given(_strategy()) +def test_apply_rotation_vector(data): + parameters, expected = data + + torch.testing.assert_close( + beignet.ops.apply_rotation_vector(**parameters), + expected, + ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__compose_euler_angle.py b/tests/beignet/ops/_geometry/_transformations/test__compose_euler_angle.py new file mode 100644 index 0000000000..814e397bdc --- /dev/null +++ b/tests/beignet/ops/_geometry/_transformations/test__compose_euler_angle.py @@ -0,0 +1,60 @@ +import operator + +import beignet.ops +import hypothesis.strategies +import torch.testing +from scipy.spatial.transform import Rotation + + +@hypothesis.strategies.composite +def _strategy(function): + size = function( + hypothesis.strategies.integers( + min_value=16, + max_value=32, + ), + ) + + input = Rotation.random(size) + other = Rotation.random(size) + + axes = function( + hypothesis.strategies.sampled_from( + [ + "xyz", + "xzy", + "yxz", + "yzx", + "zxy", + "zyx", + "XYZ", + "XZY", + "YXZ", + "YZX", + "ZXY", + "ZYX", + ] + ), + ) + + degrees = function(hypothesis.strategies.booleans()) + + return ( + { + "input": torch.from_numpy(input.as_euler(axes, degrees)), + "other": torch.from_numpy(other.as_euler(axes, degrees)), + "axes": axes, + "degrees": degrees, + }, + torch.from_numpy(operator.mul(input, other).as_euler(axes, degrees)), + ) + + +@hypothesis.given(_strategy()) +def test_compose_euler_angle(data): + parameters, expected = data + + torch.testing.assert_close( + beignet.ops.compose_euler_angle(**parameters), + expected, + ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__compose_quaternion.py b/tests/beignet/ops/_geometry/_transformations/test__compose_quaternion.py new file mode 100644 index 0000000000..a0f51f686b --- /dev/null +++ b/tests/beignet/ops/_geometry/_transformations/test__compose_quaternion.py @@ -0,0 +1,40 @@ +import operator + +import beignet.ops +import hypothesis.strategies +import torch.testing +from scipy.spatial.transform import Rotation + + +@hypothesis.strategies.composite +def _strategy(function): + size = function( + hypothesis.strategies.integers( + min_value=16, + max_value=32, + ), + ) + + input = Rotation.random(size) + other = Rotation.random(size) + + canonical = function(hypothesis.strategies.booleans()) + + return ( + { + "input": torch.from_numpy(input.as_quat(canonical)), + "other": torch.from_numpy(other.as_quat(canonical)), + "canonical": canonical, + }, + torch.abs(torch.from_numpy(operator.mul(input, other).as_quat(canonical))), + ) + + +@hypothesis.given(_strategy()) +def test_compose_quaternion(data): + parameters, expected = data + + torch.testing.assert_close( + torch.abs(beignet.ops.compose_quaternion(**parameters)), + expected, + ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__compose_rotation_matrix.py b/tests/beignet/ops/_geometry/_transformations/test__compose_rotation_matrix.py new file mode 100644 index 0000000000..a6e042d524 --- /dev/null +++ b/tests/beignet/ops/_geometry/_transformations/test__compose_rotation_matrix.py @@ -0,0 +1,37 @@ +import operator + +import beignet.ops +import hypothesis.strategies +import torch.testing +from scipy.spatial.transform import Rotation + + +@hypothesis.strategies.composite +def _strategy(function): + size = function( + hypothesis.strategies.integers( + min_value=16, + max_value=32, + ), + ) + + input = Rotation.random(size) + other = Rotation.random(size) + + return ( + { + "input": torch.from_numpy(input.as_matrix()), + "other": torch.from_numpy(other.as_matrix()), + }, + torch.from_numpy(operator.mul(input, other).as_matrix()), + ) + + +@hypothesis.given(_strategy()) +def test_compose_rotation_matrix(data): + parameters, expected = data + + torch.testing.assert_close( + beignet.ops.compose_rotation_matrix(**parameters), + expected, + ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__compose_rotation_vector.py b/tests/beignet/ops/_geometry/_transformations/test__compose_rotation_vector.py new file mode 100644 index 0000000000..2a6f3e09ae --- /dev/null +++ b/tests/beignet/ops/_geometry/_transformations/test__compose_rotation_vector.py @@ -0,0 +1,40 @@ +import operator + +import beignet.ops +import hypothesis.strategies +import torch.testing +from scipy.spatial.transform import Rotation + + +@hypothesis.strategies.composite +def _strategy(function): + size = function( + hypothesis.strategies.integers( + min_value=16, + max_value=32, + ), + ) + + input = Rotation.random(size) + other = Rotation.random(size) + + degrees = function(hypothesis.strategies.booleans()) + + return ( + { + "input": torch.from_numpy(input.as_rotvec(degrees)), + "other": torch.from_numpy(other.as_rotvec(degrees)), + "degrees": degrees, + }, + torch.from_numpy(operator.mul(input, other).as_rotvec(degrees)), + ) + + +@hypothesis.given(_strategy()) +def test_compose_rotation_vector(data): + parameters, expected = data + + torch.testing.assert_close( + beignet.ops.compose_rotation_vector(**parameters), + expected, + ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__euler_angle_identity.py b/tests/beignet/ops/_geometry/_transformations/test__euler_angle_identity.py new file mode 100644 index 0000000000..f9706d7bd8 --- /dev/null +++ b/tests/beignet/ops/_geometry/_transformations/test__euler_angle_identity.py @@ -0,0 +1,11 @@ +import hypothesis.strategies + + +@hypothesis.strategies.composite +def strategy(f): + return + + +@hypothesis.given(strategy()) +def test_euler_angle_identity(data): + assert True diff --git a/tests/beignet/ops/_geometry/_transformations/test__euler_angle_magnitude.py b/tests/beignet/ops/_geometry/_transformations/test__euler_angle_magnitude.py new file mode 100644 index 0000000000..169376b4c5 --- /dev/null +++ b/tests/beignet/ops/_geometry/_transformations/test__euler_angle_magnitude.py @@ -0,0 +1,56 @@ +import beignet.ops +import hypothesis.strategies +import torch.testing +from scipy.spatial.transform import Rotation + + +@hypothesis.strategies.composite +def _strategy(function): + axes = function( + hypothesis.strategies.sampled_from( + [ + "xyz", + "xzy", + "yxz", + "yzx", + "zxy", + "zyx", + "XYZ", + "XZY", + "YXZ", + "YZX", + "ZXY", + "ZYX", + ] + ), + ) + + degrees = function(hypothesis.strategies.booleans()) + + rotations = Rotation.random( + function( + hypothesis.strategies.integers( + min_value=1, + max_value=8, + ), + ), + ) + + return ( + { + "input": torch.from_numpy(rotations.as_euler(axes, degrees)), + "axes": axes, + "degrees": degrees, + }, + torch.from_numpy(rotations.magnitude()), + ) + + +@hypothesis.given(_strategy()) +def test_euler_angle_magnitude(data): + parameters, expected = data + + torch.testing.assert_close( + beignet.ops.euler_angle_magnitude(**parameters), + expected, + ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__euler_angle_mean.py b/tests/beignet/ops/_geometry/_transformations/test__euler_angle_mean.py new file mode 100644 index 0000000000..31a568d598 --- /dev/null +++ b/tests/beignet/ops/_geometry/_transformations/test__euler_angle_mean.py @@ -0,0 +1,61 @@ +import beignet.ops +import hypothesis.strategies +import torch.testing +from scipy.spatial.transform import Rotation + + +@hypothesis.strategies.composite +def _strategy(function): + size = function( + hypothesis.strategies.integers( + min_value=16, + max_value=32, + ), + ) + + input = Rotation.random(size) + + axes = function( + hypothesis.strategies.sampled_from( + [ + "xyz", + "xzy", + "yxz", + "yzx", + "zxy", + "zyx", + "XYZ", + "XZY", + "YXZ", + "YZX", + "ZXY", + "ZYX", + ] + ), + ) + + degrees = function(hypothesis.strategies.booleans()) + + return ( + { + "input": torch.from_numpy(input.as_euler(axes, degrees)), + "axes": axes, + "degrees": degrees, + }, + torch.unsqueeze( + torch.from_numpy( + input.mean().as_euler(axes, degrees), + ), + dim=0, + ), + ) + + +@hypothesis.given(_strategy()) +def test_euler_angle_mean(data): + parameters, expected = data + + torch.testing.assert_close( + beignet.ops.euler_angle_mean(**parameters), + expected, + ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__euler_angle_to_quaternion.py b/tests/beignet/ops/_geometry/_transformations/test__euler_angle_to_quaternion.py new file mode 100644 index 0000000000..1043a994c2 --- /dev/null +++ b/tests/beignet/ops/_geometry/_transformations/test__euler_angle_to_quaternion.py @@ -0,0 +1,75 @@ +import beignet.ops +import hypothesis.extra.numpy +import hypothesis.strategies +import torch +from scipy.spatial.transform import Rotation + + +@hypothesis.strategies.composite +def _strategy(function): + rotation = Rotation.random( + function( + hypothesis.strategies.integers( + min_value=16, + max_value=32, + ), + ), + ) + + axes = function( + hypothesis.strategies.sampled_from( + [ + "xyz", + "xzy", + "yxz", + "yzx", + "zxy", + "zyx", + "XYZ", + "XZY", + "YXZ", + "YZX", + "ZXY", + "ZYX", + ] + ), + ) + + degrees = function(hypothesis.strategies.booleans()) + + canonical = function(hypothesis.strategies.booleans()) + + return ( + { + "input": torch.from_numpy( + rotation.as_euler( + axes, + degrees, + ), + ), + "axes": axes, + "degrees": degrees, + "canonical": canonical, + }, + torch.abs( + torch.from_numpy( + rotation.as_quat( + canonical, + ), + ), + ), + ) + + +@hypothesis.given(_strategy()) +def test_euler_angle_to_quaternion(data): + parameters, expected = data + + torch.testing.assert_close( + torch.abs( + beignet.ops.euler_angle_to_quaternion( + **parameters, + ), + ), + expected, + ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__euler_angle_to_rotation_matrix.py b/tests/beignet/ops/_geometry/_transformations/test__euler_angle_to_rotation_matrix.py new file mode 100644 index 0000000000..4e63942c86 --- /dev/null +++ b/tests/beignet/ops/_geometry/_transformations/test__euler_angle_to_rotation_matrix.py @@ -0,0 +1,65 @@ +import beignet.ops +import hypothesis.strategies +import torch.testing +from scipy.spatial.transform import Rotation + + +@hypothesis.strategies.composite +def _strategy(function): + rotation = Rotation.random( + function( + hypothesis.strategies.integers( + min_value=16, + max_value=32, + ), + ), + ) + + axes = function( + hypothesis.strategies.sampled_from( + [ + "xyz", + "xzy", + "yxz", + "yzx", + "zxy", + "zyx", + "XYZ", + "XZY", + "YXZ", + "YZX", + "ZXY", + "ZYX", + ] + ), + ) + + degrees = function(hypothesis.strategies.booleans()) + + return ( + { + "input": torch.from_numpy( + rotation.as_euler( + axes, + degrees, + ), + ), + "axes": axes, + "degrees": degrees, + }, + torch.from_numpy( + rotation.as_matrix(), + ), + ) + + +@hypothesis.given(_strategy()) +def test_euler_angle_to_rotation_matrix(data): + parameters, expected = data + + torch.testing.assert_close( + beignet.ops.euler_angle_to_rotation_matrix( + **parameters, + ), + expected, + ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__euler_angle_to_rotation_vector.py b/tests/beignet/ops/_geometry/_transformations/test__euler_angle_to_rotation_vector.py new file mode 100644 index 0000000000..20f2adea53 --- /dev/null +++ b/tests/beignet/ops/_geometry/_transformations/test__euler_angle_to_rotation_vector.py @@ -0,0 +1,63 @@ +import beignet.ops +import hypothesis.strategies +import torch +from scipy.spatial.transform import Rotation + + +@hypothesis.strategies.composite +def _strategy(function): + rotation = Rotation.random( + function( + hypothesis.strategies.integers( + min_value=16, + max_value=32, + ), + ), + ) + + axes = function( + hypothesis.strategies.sampled_from( + [ + "xyz", + "xzy", + "yxz", + "yzx", + "zxy", + "zyx", + "XYZ", + "XZY", + "YXZ", + "YZX", + "ZXY", + "ZYX", + ] + ), + ) + + degrees = function(hypothesis.strategies.booleans()) + + return ( + { + "input": torch.from_numpy( + rotation.as_euler( + axes, + degrees, + ), + ), + "axes": axes, + "degrees": degrees, + }, + torch.from_numpy(rotation.as_rotvec(degrees)), + ) + + +@hypothesis.given(_strategy()) +def test_euler_angle_to_rotation_vector(data): + parameters, expected = data + + torch.testing.assert_close( + beignet.ops.euler_angle_to_rotation_vector( + **parameters, + ), + expected, + ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__invert_euler_angle.py b/tests/beignet/ops/_geometry/_transformations/test__invert_euler_angle.py new file mode 100644 index 0000000000..d6505e2b31 --- /dev/null +++ b/tests/beignet/ops/_geometry/_transformations/test__invert_euler_angle.py @@ -0,0 +1,56 @@ +import beignet.ops +import hypothesis.strategies +import torch.testing +from scipy.spatial.transform import Rotation + + +@hypothesis.strategies.composite +def _strategy(function): + axes = function( + hypothesis.strategies.sampled_from( + [ + "xyz", + "xzy", + "yxz", + "yzx", + "zxy", + "zyx", + "XYZ", + "XZY", + "YXZ", + "YZX", + "ZXY", + "ZYX", + ] + ), + ) + + degrees = function(hypothesis.strategies.booleans()) + + rotations = Rotation.random( + function( + hypothesis.strategies.integers( + min_value=1, + max_value=8, + ), + ), + ) + + return ( + { + "input": torch.from_numpy(rotations.as_euler(axes, degrees)), + "axes": axes, + "degrees": degrees, + }, + torch.from_numpy(rotations.inv().as_euler(axes, degrees)), + ) + + +@hypothesis.given(_strategy()) +def test_invert_euler_angle(data): + parameters, expected = data + + torch.testing.assert_close( + beignet.ops.invert_euler_angle(**parameters), + expected, + ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__invert_quaternion.py b/tests/beignet/ops/_geometry/_transformations/test__invert_quaternion.py new file mode 100644 index 0000000000..78cc7f5195 --- /dev/null +++ b/tests/beignet/ops/_geometry/_transformations/test__invert_quaternion.py @@ -0,0 +1,36 @@ +import beignet.ops +import hypothesis.strategies +import torch.testing +from scipy.spatial.transform import Rotation + + +@hypothesis.strategies.composite +def _strategy(function): + canonical = function(hypothesis.strategies.booleans()) + + rotations = Rotation.random( + function( + hypothesis.strategies.integers( + min_value=1, + max_value=8, + ), + ), + ) + + return ( + { + "input": torch.from_numpy(rotations.as_quat(canonical)), + "canonical": canonical, + }, + torch.from_numpy(rotations.inv().as_quat(canonical)), + ) + + +@hypothesis.given(_strategy()) +def test_invert_quaternion(data): + parameters, expected = data + + torch.testing.assert_close( + beignet.ops.invert_quaternion(**parameters), + expected, + ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__invert_rotation_matrix.py b/tests/beignet/ops/_geometry/_transformations/test__invert_rotation_matrix.py new file mode 100644 index 0000000000..9267f65c22 --- /dev/null +++ b/tests/beignet/ops/_geometry/_transformations/test__invert_rotation_matrix.py @@ -0,0 +1,33 @@ +import beignet.ops +import hypothesis.strategies +import torch.testing +from scipy.spatial.transform import Rotation + + +@hypothesis.strategies.composite +def _strategy(function): + rotations = Rotation.random( + function( + hypothesis.strategies.integers( + min_value=1, + max_value=8, + ), + ), + ) + + return ( + { + "input": torch.from_numpy(rotations.as_matrix()), + }, + torch.from_numpy(rotations.inv().as_matrix()), + ) + + +@hypothesis.given(_strategy()) +def test_invert_rotation_matrix(data): + parameters, expected = data + + torch.testing.assert_close( + beignet.ops.invert_rotation_matrix(**parameters), + expected, + ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__invert_rotation_vector.py b/tests/beignet/ops/_geometry/_transformations/test__invert_rotation_vector.py new file mode 100644 index 0000000000..a215243901 --- /dev/null +++ b/tests/beignet/ops/_geometry/_transformations/test__invert_rotation_vector.py @@ -0,0 +1,35 @@ +import beignet.ops +import hypothesis.strategies +import torch.testing +from scipy.spatial.transform import Rotation + + +@hypothesis.strategies.composite +def _strategy(function): + degrees = function(hypothesis.strategies.booleans()) + + rotations = Rotation.random( + function( + hypothesis.strategies.integers( + min_value=1, + max_value=8, + ), + ), + ) + + return ( + { + "input": torch.from_numpy(rotations.as_rotvec(degrees)), + }, + torch.from_numpy(rotations.inv().as_rotvec(degrees)), + ) + + +@hypothesis.given(_strategy()) +def test_invert_rotation_vector(data): + parameters, expected = data + + torch.testing.assert_close( + beignet.ops.invert_rotation_vector(**parameters), + expected, + ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__quaternion_identity.py b/tests/beignet/ops/_geometry/_transformations/test__quaternion_identity.py new file mode 100644 index 0000000000..f7f69c6f77 --- /dev/null +++ b/tests/beignet/ops/_geometry/_transformations/test__quaternion_identity.py @@ -0,0 +1,37 @@ +import beignet.ops +import hypothesis.strategies +import torch +from scipy.spatial.transform import Rotation + + +@hypothesis.strategies.composite +def _strategy(function): + size = function( + hypothesis.strategies.integers( + min_value=1, + max_value=8, + ), + ) + + rotation = Rotation.identity(size) + + canonical = function(hypothesis.strategies.booleans()) + + return ( + { + "size": size, + "canonical": canonical, + "dtype": torch.float64, + }, + torch.from_numpy(rotation.as_quat(canonical)), + ) + + +@hypothesis.given(_strategy()) +def test_quaternion_identity(data): + parameters, expected = data + + torch.testing.assert_close( + beignet.ops.quaternion_identity(**parameters), + expected, + ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__quaternion_magnitude.py b/tests/beignet/ops/_geometry/_transformations/test__quaternion_magnitude.py new file mode 100644 index 0000000000..1bfe4e8a24 --- /dev/null +++ b/tests/beignet/ops/_geometry/_transformations/test__quaternion_magnitude.py @@ -0,0 +1,36 @@ +import beignet.ops +import hypothesis.strategies +import torch.testing +from scipy.spatial.transform import Rotation + + +@hypothesis.strategies.composite +def _strategy(function): + canonical = function(hypothesis.strategies.booleans()) + + rotations = Rotation.random( + function( + hypothesis.strategies.integers( + min_value=1, + max_value=8, + ), + ), + ) + + return ( + { + "input": torch.from_numpy(rotations.as_quat(canonical)), + "canonical": canonical, + }, + torch.from_numpy(rotations.magnitude()), + ) + + +@hypothesis.given(_strategy()) +def test_quaternion_magnitude(data): + parameters, expected = data + + torch.testing.assert_close( + beignet.ops.quaternion_magnitude(**parameters), + expected, + ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__quaternion_mean.py b/tests/beignet/ops/_geometry/_transformations/test__quaternion_mean.py new file mode 100644 index 0000000000..01d3b1baac --- /dev/null +++ b/tests/beignet/ops/_geometry/_transformations/test__quaternion_mean.py @@ -0,0 +1,50 @@ +import beignet.ops +import hypothesis.strategies +import torch.testing +from scipy.spatial.transform import Rotation + + +@hypothesis.strategies.composite +def _strategy(function): + rotation = Rotation.random( + function( + hypothesis.strategies.integers( + min_value=1, + max_value=8, + ), + ), + ) + + return ( + { + "input": torch.from_numpy( + rotation.as_quat( + canonical=False, + ), + ), + }, + torch.unsqueeze( + torch.abs( + torch.from_numpy( + rotation.mean().as_quat( + canonical=False, + ), + ), + ), + dim=0, + ), + ) + + +@hypothesis.given(_strategy()) +def test_quaternion_mean(data): + parameters, expected = data + + torch.testing.assert_close( + torch.abs( + beignet.ops.quaternion_mean( + **parameters, + ), + ), + expected, + ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__quaternion_to_euler_angle.py b/tests/beignet/ops/_geometry/_transformations/test__quaternion_to_euler_angle.py new file mode 100644 index 0000000000..9f2b6129e4 --- /dev/null +++ b/tests/beignet/ops/_geometry/_transformations/test__quaternion_to_euler_angle.py @@ -0,0 +1,67 @@ +import beignet.ops +import hypothesis.strategies +import torch +from scipy.spatial.transform import Rotation + + +@hypothesis.strategies.composite +def _strategy(function): + rotation = Rotation.random( + function( + hypothesis.strategies.integers( + min_value=16, + max_value=32, + ), + ), + ) + + axes = function( + hypothesis.strategies.sampled_from( + [ + "xyz", + "xzy", + "yxz", + "yzx", + "zxy", + "zyx", + "XYZ", + "XZY", + "YXZ", + "YZX", + "ZXY", + "ZYX", + ] + ), + ) + + degrees = function(hypothesis.strategies.booleans()) + + return ( + { + "input": torch.from_numpy( + rotation.as_quat( + canonical=False, + ), + ), + "axes": axes, + "degrees": degrees, + }, + torch.from_numpy( + rotation.as_euler( + axes, + degrees, + ), + ), + ) + + +@hypothesis.given(_strategy()) +def test_quaternion_to_euler_angle(data): + parameters, expected = data + + torch.testing.assert_close( + beignet.ops.quaternion_to_euler_angle( + **parameters, + ), + expected, + ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__quaternion_to_rotation_matrix.py b/tests/beignet/ops/_geometry/_transformations/test__quaternion_to_rotation_matrix.py new file mode 100644 index 0000000000..ebea9a70ed --- /dev/null +++ b/tests/beignet/ops/_geometry/_transformations/test__quaternion_to_rotation_matrix.py @@ -0,0 +1,41 @@ +import beignet.ops +import hypothesis.strategies +import torch +from scipy.spatial.transform import Rotation + + +@hypothesis.strategies.composite +def _strategy(function): + rotation = Rotation.random( + function( + hypothesis.strategies.integers( + min_value=16, + max_value=32, + ), + ), + ) + + return ( + { + "input": torch.from_numpy( + rotation.as_quat( + canonical=False, + ), + ), + }, + torch.from_numpy( + rotation.as_matrix(), + ), + ) + + +@hypothesis.given(_strategy()) +def test_quaternion_to_rotation_matrix(data): + parameters, expected = data + + torch.testing.assert_close( + beignet.ops.quaternion_to_rotation_matrix( + **parameters, + ), + expected, + ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__quaternion_to_rotation_vector.py b/tests/beignet/ops/_geometry/_transformations/test__quaternion_to_rotation_vector.py new file mode 100644 index 0000000000..5c69a9e1b3 --- /dev/null +++ b/tests/beignet/ops/_geometry/_transformations/test__quaternion_to_rotation_vector.py @@ -0,0 +1,46 @@ +import beignet.ops +import hypothesis.strategies +import torch +from scipy.spatial.transform import Rotation + + +@hypothesis.strategies.composite +def _strategy(function): + rotation = Rotation.random( + function( + hypothesis.strategies.integers( + min_value=16, + max_value=32, + ), + ), + ) + + degrees = function(hypothesis.strategies.booleans()) + + return ( + { + "input": torch.from_numpy( + rotation.as_quat( + canonical=False, + ), + ), + "degrees": degrees, + }, + torch.from_numpy( + rotation.as_rotvec( + degrees, + ), + ), + ) + + +@hypothesis.given(_strategy()) +def test_quaternion_to_rotation_vector(data): + parameters, expected = data + + torch.testing.assert_close( + beignet.ops.quaternion_to_rotation_vector( + **parameters, + ), + expected, + ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__random_euler_angle.py b/tests/beignet/ops/_geometry/_transformations/test__random_euler_angle.py new file mode 100644 index 0000000000..ca0ef5fb2c --- /dev/null +++ b/tests/beignet/ops/_geometry/_transformations/test__random_euler_angle.py @@ -0,0 +1,51 @@ +import beignet.ops +import hypothesis.strategies + + +@hypothesis.strategies.composite +def _strategy(function): + size = function( + hypothesis.strategies.integers( + min_value=1, + max_value=8, + ), + ) + + axes = function( + hypothesis.strategies.sampled_from( + [ + "xyz", + "xzy", + "yxz", + "yzx", + "zxy", + "zyx", + "XYZ", + "XZY", + "YXZ", + "YZX", + "ZXY", + "ZYX", + ] + ), + ) + + degrees = function(hypothesis.strategies.booleans()) + + return ( + { + "size": size, + "axes": axes, + "degrees": degrees, + }, + None, + ) + + +@hypothesis.given(_strategy()) +def test_random_euler_angle(data): + parameters, _ = data + + assert beignet.ops.random_euler_angle( + **parameters, + ).shape == (parameters["size"], 3) diff --git a/tests/beignet/ops/_geometry/_transformations/test__random_quaternion.py b/tests/beignet/ops/_geometry/_transformations/test__random_quaternion.py new file mode 100644 index 0000000000..938e79339c --- /dev/null +++ b/tests/beignet/ops/_geometry/_transformations/test__random_quaternion.py @@ -0,0 +1,31 @@ +import beignet.ops +import hypothesis.strategies + + +@hypothesis.strategies.composite +def _strategy(function): + size = function( + hypothesis.strategies.integers( + min_value=1, + max_value=8, + ), + ) + + canonical = function(hypothesis.strategies.booleans()) + + return ( + { + "size": size, + "canonical": canonical, + }, + None, + ) + + +@hypothesis.given(_strategy()) +def test_random_quaternion(data): + parameters, _ = data + + assert beignet.ops.random_quaternion( + **parameters, + ).shape == (parameters["size"], 4) diff --git a/tests/beignet/ops/_geometry/_transformations/test__random_rotation_matrix.py b/tests/beignet/ops/_geometry/_transformations/test__random_rotation_matrix.py new file mode 100644 index 0000000000..7e007b2b2f --- /dev/null +++ b/tests/beignet/ops/_geometry/_transformations/test__random_rotation_matrix.py @@ -0,0 +1,28 @@ +import beignet.ops +import hypothesis.strategies + + +@hypothesis.strategies.composite +def _strategy(function): + size = function( + hypothesis.strategies.integers( + min_value=1, + max_value=8, + ), + ) + + return ( + { + "size": size, + }, + None, + ) + + +@hypothesis.given(_strategy()) +def test_random_rotation_matrix(data): + parameters, _ = data + + assert beignet.ops.random_rotation_matrix( + **parameters, + ).shape == (parameters["size"], 3, 3) diff --git a/tests/beignet/ops/_geometry/_transformations/test__random_rotation_vector.py b/tests/beignet/ops/_geometry/_transformations/test__random_rotation_vector.py new file mode 100644 index 0000000000..c214441eb9 --- /dev/null +++ b/tests/beignet/ops/_geometry/_transformations/test__random_rotation_vector.py @@ -0,0 +1,31 @@ +import beignet.ops +import hypothesis.strategies + + +@hypothesis.strategies.composite +def _strategy(function): + size = function( + hypothesis.strategies.integers( + min_value=1, + max_value=8, + ), + ) + + degrees = function(hypothesis.strategies.booleans()) + + return ( + { + "size": size, + "degrees": degrees, + }, + None, + ) + + +@hypothesis.given(_strategy()) +def test_random_rotation_vector(data): + parameters, _ = data + + assert beignet.ops.random_rotation_vector( + **parameters, + ).shape == (parameters["size"], 3) diff --git a/tests/beignet/ops/_geometry/_transformations/test__rotation_matrix_identity.py b/tests/beignet/ops/_geometry/_transformations/test__rotation_matrix_identity.py new file mode 100644 index 0000000000..13d163f692 --- /dev/null +++ b/tests/beignet/ops/_geometry/_transformations/test__rotation_matrix_identity.py @@ -0,0 +1,34 @@ +import beignet.ops +import hypothesis.strategies +import torch +from scipy.spatial.transform import Rotation + + +@hypothesis.strategies.composite +def _strategy(function): + size = function( + hypothesis.strategies.integers( + min_value=1, + max_value=8, + ), + ) + + rotation = Rotation.identity(size) + + return ( + { + "size": size, + "dtype": torch.float64, + }, + torch.from_numpy(rotation.as_matrix()), + ) + + +@hypothesis.given(_strategy()) +def test_rotation_matrix_identity(data): + parameters, expected = data + + torch.testing.assert_close( + beignet.ops.rotation_matrix_identity(**parameters), + expected, + ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__rotation_matrix_magnitude.py b/tests/beignet/ops/_geometry/_transformations/test__rotation_matrix_magnitude.py new file mode 100644 index 0000000000..85fb6d94d9 --- /dev/null +++ b/tests/beignet/ops/_geometry/_transformations/test__rotation_matrix_magnitude.py @@ -0,0 +1,33 @@ +import beignet.ops +import hypothesis.strategies +import torch.testing +from scipy.spatial.transform import Rotation + + +@hypothesis.strategies.composite +def _strategy(function): + rotations = Rotation.random( + function( + hypothesis.strategies.integers( + min_value=1, + max_value=8, + ), + ), + ) + + return ( + { + "input": torch.from_numpy(rotations.as_matrix()), + }, + torch.from_numpy(rotations.magnitude()), + ) + + +@hypothesis.given(_strategy()) +def test_rotation_matrix_magnitude(data): + parameters, expected = data + + torch.testing.assert_close( + beignet.ops.rotation_matrix_magnitude(**parameters), + expected, + ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__rotation_matrix_mean.py b/tests/beignet/ops/_geometry/_transformations/test__rotation_matrix_mean.py new file mode 100644 index 0000000000..22af4a1bbf --- /dev/null +++ b/tests/beignet/ops/_geometry/_transformations/test__rotation_matrix_mean.py @@ -0,0 +1,33 @@ +import beignet.ops +import hypothesis.strategies +import torch.testing +from scipy.spatial.transform import Rotation + + +@hypothesis.strategies.composite +def _strategy(function): + size = function( + hypothesis.strategies.integers( + min_value=16, + max_value=32, + ), + ) + + input = Rotation.random(size) + + return ( + { + "input": torch.from_numpy(input.as_matrix()), + }, + torch.unsqueeze(torch.from_numpy(input.mean().as_matrix()), dim=0), + ) + + +@hypothesis.given(_strategy()) +def test_rotation_matrix_mean(data): + parameters, expected = data + + torch.testing.assert_close( + beignet.ops.rotation_matrix_mean(**parameters), + expected, + ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__rotation_matrix_to_euler_angle.py b/tests/beignet/ops/_geometry/_transformations/test__rotation_matrix_to_euler_angle.py new file mode 100644 index 0000000000..b143e9aa4f --- /dev/null +++ b/tests/beignet/ops/_geometry/_transformations/test__rotation_matrix_to_euler_angle.py @@ -0,0 +1,65 @@ +import beignet.ops +import hypothesis.strategies +import torch +from scipy.spatial.transform import Rotation + + +@hypothesis.strategies.composite +def _strategy(function): + rotation = Rotation.random( + function( + hypothesis.strategies.integers( + min_value=16, + max_value=32, + ), + ), + ) + + axes = function( + hypothesis.strategies.sampled_from( + [ + "xyz", + "xzy", + "yxz", + "yzx", + "zxy", + "zyx", + "XYZ", + "XZY", + "YXZ", + "YZX", + "ZXY", + "ZYX", + ] + ), + ) + + degrees = function(hypothesis.strategies.booleans()) + + return ( + { + "input": torch.from_numpy( + rotation.as_matrix(), + ), + "axes": axes, + "degrees": degrees, + }, + torch.from_numpy( + rotation.as_euler( + axes, + degrees, + ), + ), + ) + + +@hypothesis.given(_strategy()) +def test_rotation_matrix_to_euler_angle(data): + parameters, expected = data + + torch.testing.assert_close( + beignet.ops.rotation_matrix_to_euler_angle( + **parameters, + ), + expected, + ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__rotation_matrix_to_quaternion.py b/tests/beignet/ops/_geometry/_transformations/test__rotation_matrix_to_quaternion.py new file mode 100644 index 0000000000..fde6a951ff --- /dev/null +++ b/tests/beignet/ops/_geometry/_transformations/test__rotation_matrix_to_quaternion.py @@ -0,0 +1,49 @@ +import beignet.ops +import hypothesis.extra.numpy +import hypothesis.strategies +import torch +from scipy.spatial.transform import Rotation + + +@hypothesis.strategies.composite +def _strategy(function): + rotation = Rotation.random( + function( + hypothesis.strategies.integers( + min_value=16, + max_value=32, + ), + ), + ) + + canonical = function(hypothesis.strategies.booleans()) + + return ( + { + "input": torch.from_numpy( + rotation.as_matrix(), + ), + "canonical": canonical, + }, + torch.abs( + torch.from_numpy( + rotation.as_quat( + canonical, + ), + ), + ), + ) + + +@hypothesis.given(_strategy()) +def test_rotation_matrix_to_quaternion(data): + parameters, expected = data + + torch.testing.assert_close( + torch.abs( + beignet.ops.rotation_matrix_to_quaternion( + **parameters, + ), + ), + expected, + ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__rotation_matrix_to_rotation_vector.py b/tests/beignet/ops/_geometry/_transformations/test__rotation_matrix_to_rotation_vector.py new file mode 100644 index 0000000000..491690a13a --- /dev/null +++ b/tests/beignet/ops/_geometry/_transformations/test__rotation_matrix_to_rotation_vector.py @@ -0,0 +1,45 @@ +import beignet.ops +import hypothesis.extra.numpy +import hypothesis.strategies +import torch +from scipy.spatial.transform import Rotation + + +@hypothesis.strategies.composite +def _strategy(function): + rotation = Rotation.random( + function( + hypothesis.strategies.integers( + min_value=16, + max_value=32, + ), + ), + ) + + degrees = function(hypothesis.strategies.booleans()) + + return ( + { + "input": torch.from_numpy( + rotation.as_matrix(), + ), + "degrees": degrees, + }, + torch.from_numpy( + rotation.as_rotvec( + degrees, + ), + ), + ) + + +@hypothesis.given(_strategy()) +def test_rotation_matrix_to_rotation_vector(data): + parameters, expected = data + + torch.testing.assert_close( + beignet.ops.rotation_matrix_to_rotation_vector( + **parameters, + ), + expected, + ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__rotation_vector_identity.py b/tests/beignet/ops/_geometry/_transformations/test__rotation_vector_identity.py new file mode 100644 index 0000000000..d84b97d9fa --- /dev/null +++ b/tests/beignet/ops/_geometry/_transformations/test__rotation_vector_identity.py @@ -0,0 +1,36 @@ +import beignet.ops +import hypothesis.strategies +import torch +from scipy.spatial.transform import Rotation + + +@hypothesis.strategies.composite +def _strategy(function): + size = function( + hypothesis.strategies.integers( + min_value=1, + max_value=8, + ), + ) + + rotation = Rotation.identity(size) + + degrees = function(hypothesis.strategies.booleans()) + + return ( + { + "size": size, + "dtype": torch.float64, + }, + torch.from_numpy(rotation.as_rotvec(degrees)), + ) + + +@hypothesis.given(_strategy()) +def test_rotation_vector_identity(data): + parameters, expected = data + + torch.testing.assert_close( + beignet.ops.rotation_vector_identity(**parameters), + expected, + ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__rotation_vector_magnitude.py b/tests/beignet/ops/_geometry/_transformations/test__rotation_vector_magnitude.py new file mode 100644 index 0000000000..a065bbed5f --- /dev/null +++ b/tests/beignet/ops/_geometry/_transformations/test__rotation_vector_magnitude.py @@ -0,0 +1,36 @@ +import beignet.ops +import hypothesis.strategies +import torch.testing +from scipy.spatial.transform import Rotation + + +@hypothesis.strategies.composite +def _strategy(function): + degrees = function(hypothesis.strategies.booleans()) + + rotations = Rotation.random( + function( + hypothesis.strategies.integers( + min_value=1, + max_value=8, + ), + ), + ) + + return ( + { + "input": torch.from_numpy(rotations.as_rotvec(degrees)), + "degrees": degrees, + }, + torch.from_numpy(rotations.magnitude()), + ) + + +@hypothesis.given(_strategy()) +def test_rotation_vector_magnitude(data): + parameters, expected = data + + torch.testing.assert_close( + beignet.ops.rotation_vector_magnitude(**parameters), + expected, + ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__rotation_vector_mean.py b/tests/beignet/ops/_geometry/_transformations/test__rotation_vector_mean.py new file mode 100644 index 0000000000..6ae68d159f --- /dev/null +++ b/tests/beignet/ops/_geometry/_transformations/test__rotation_vector_mean.py @@ -0,0 +1,39 @@ +import beignet.ops +import hypothesis.strategies +import torch.testing +from scipy.spatial.transform import Rotation + + +@hypothesis.strategies.composite +def _strategy(function): + size = function( + hypothesis.strategies.integers( + min_value=16, + max_value=32, + ), + ) + + input = Rotation.random(size) + + degrees = function(hypothesis.strategies.booleans()) + + return ( + { + "input": torch.from_numpy(input.as_rotvec(degrees)), + "degrees": degrees, + }, + torch.unsqueeze( + torch.from_numpy(input.mean().as_rotvec(degrees)), + dim=0, + ), + ) + + +@hypothesis.given(_strategy()) +def test_rotation_vector_mean(data): + parameters, expected = data + + torch.testing.assert_close( + beignet.ops.rotation_vector_mean(**parameters), + expected, + ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__rotation_vector_to_euler_angle.py b/tests/beignet/ops/_geometry/_transformations/test__rotation_vector_to_euler_angle.py new file mode 100644 index 0000000000..f49ab3ed1b --- /dev/null +++ b/tests/beignet/ops/_geometry/_transformations/test__rotation_vector_to_euler_angle.py @@ -0,0 +1,67 @@ +import beignet.ops +import hypothesis.strategies +import torch +from scipy.spatial.transform import Rotation + + +@hypothesis.strategies.composite +def _strategy(function): + rotation = Rotation.random( + function( + hypothesis.strategies.integers( + min_value=16, + max_value=32, + ), + ), + ) + + axes = function( + hypothesis.strategies.sampled_from( + [ + "xyz", + "xzy", + "yxz", + "yzx", + "zxy", + "zyx", + "XYZ", + "XZY", + "YXZ", + "YZX", + "ZXY", + "ZYX", + ] + ), + ) + + degrees = function(hypothesis.strategies.booleans()) + + return ( + { + "input": torch.from_numpy( + rotation.as_rotvec( + degrees, + ), + ), + "axes": axes, + "degrees": degrees, + }, + torch.from_numpy( + rotation.as_euler( + axes, + degrees, + ), + ), + ) + + +@hypothesis.given(_strategy()) +def test_rotation_vector_to_euler_angle(data): + parameters, expected = data + + torch.testing.assert_close( + beignet.ops.rotation_vector_to_euler_angle( + **parameters, + ), + expected, + ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__rotation_vector_to_quaternion.py b/tests/beignet/ops/_geometry/_transformations/test__rotation_vector_to_quaternion.py new file mode 100644 index 0000000000..9017271dbc --- /dev/null +++ b/tests/beignet/ops/_geometry/_transformations/test__rotation_vector_to_quaternion.py @@ -0,0 +1,54 @@ +import beignet.ops +import hypothesis.extra.numpy +import hypothesis.strategies +import torch +from scipy.spatial.transform import Rotation + + +@hypothesis.strategies.composite +def _strategy(function): + rotation = Rotation.random( + function( + hypothesis.strategies.integers( + min_value=16, + max_value=32, + ), + ), + ) + + degrees = function(hypothesis.strategies.booleans()) + + canonical = function(hypothesis.strategies.booleans()) + + return ( + { + "input": torch.from_numpy( + rotation.as_rotvec( + degrees, + ), + ), + "degrees": degrees, + "canonical": canonical, + }, + torch.abs( + torch.from_numpy( + rotation.as_quat( + canonical, + ), + ), + ), + ) + + +@hypothesis.given(_strategy()) +def test_rotation_vector_to_quaternion(data): + parameters, expected = data + + torch.testing.assert_close( + torch.abs( + beignet.ops.rotation_vector_to_quaternion( + **parameters, + ), + ), + expected, + ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__rotation_vector_to_rotation_matrix.py b/tests/beignet/ops/_geometry/_transformations/test__rotation_vector_to_rotation_matrix.py new file mode 100644 index 0000000000..0c8e699e2a --- /dev/null +++ b/tests/beignet/ops/_geometry/_transformations/test__rotation_vector_to_rotation_matrix.py @@ -0,0 +1,42 @@ +import beignet.ops +import hypothesis.strategies +import torch +from scipy.spatial.transform import Rotation + + +@hypothesis.strategies.composite +def _strategy(function): + rotation = Rotation.random( + function( + hypothesis.strategies.integers( + min_value=16, + max_value=32, + ), + ), + ) + + degrees = function(hypothesis.strategies.booleans()) + + return ( + { + "input": torch.from_numpy( + rotation.as_rotvec(degrees), + ), + "degrees": degrees, + }, + torch.from_numpy( + rotation.as_matrix(), + ), + ) + + +@hypothesis.given(_strategy()) +def test_rotation_vector_to_rotation_matrix(data): + parameters, expected = data + + torch.testing.assert_close( + beignet.ops.rotation_vector_to_rotation_matrix( + **parameters, + ), + expected, + ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__slerp.py b/tests/beignet/ops/_geometry/_transformations/test__slerp.py new file mode 100644 index 0000000000..5b09726995 --- /dev/null +++ b/tests/beignet/ops/_geometry/_transformations/test__slerp.py @@ -0,0 +1,151 @@ +import beignet.ops +import hypothesis.strategies +import numpy +import torch +from scipy.spatial.transform import Rotation, Slerp + + +def test_slerp(): + # t = 0 + torch.testing.assert_close( + beignet.ops.quaternion_slerp( + torch.tensor([+0.00000]), + torch.tensor([+0.00000, +1.00000]), + torch.tensor( + [ + [+1.00000, +0.00000, +0.00000, +0.00000], + [+0.00000, +1.00000, +0.00000, +0.00000], + ] + ), + ), + torch.tensor([[+1.00000, +0.00000, +0.00000, +0.00000]]), + ) + + # t = 1 + torch.testing.assert_close( + beignet.ops.quaternion_slerp( + torch.tensor([+1.00000]), + torch.tensor([+0.00000, +1.00000]), + torch.tensor( + [ + [+1.00000, +0.00000, +0.00000, +0.00000], + [+0.00000, +1.00000, +0.00000, +0.00000], + ] + ), + ), + torch.tensor([[+0.00000, +1.00000, +0.00000, +0.00000]]), + ) + + # SMALL (ACUTE) ANGLE BETWEEN QUATERNIONS + torch.testing.assert_close( + beignet.ops.quaternion_slerp( + torch.tensor([+0.50000]), + torch.tensor([+0.00000, +1.00000]), + torch.tensor( + [ + [+1.00000, +0.00000, +0.00000, +0.00000], + [+0.70710, +0.70710, +0.00000, +0.00000], + ], + ), + ), + torch.reshape( + torch.tensor([+0.92388, +0.38268, +0.00000, +0.00000]), + [1, -1], + ), + ) + + # LARGE (OBTUSE) ANGLE BETWEEN QUATERNIONS + torch.testing.assert_close( + beignet.ops.quaternion_slerp( + torch.tensor([+0.50000]), + torch.tensor([+0.00000, +1.00000]), + torch.tensor( + [ + [+1.00000, +0.00000, +0.00000, +0.00000], + [-1.00000, +0.00000, +0.00000, +0.00000], + ] + ), + ), + torch.reshape( + torch.tensor([+1.00000, +0.00000, +0.00000, +0.00000]), + [1, -1], + ), + ) + + +@hypothesis.strategies.composite +def slerp_parameters(f): + n = f( + hypothesis.strategies.integers( + min_value=2, + max_value=8, + ), + ) + + times = numpy.sort( + f( + hypothesis.strategies.lists( + hypothesis.strategies.floats( + allow_infinity=False, + allow_nan=False, + ), + min_size=n, + max_size=n, + unique=True, + ), + ), + ) + + min_value = numpy.min(times) + max_value = numpy.max(times) + + input = numpy.sort( + f( + hypothesis.strategies.lists( + hypothesis.strategies.floats( + min_value=min_value, + max_value=max_value, + ), + min_size=1, + max_size=8, + unique=True, + ), + ), + ) + + rotations = f( + hypothesis.strategies.lists( + hypothesis.strategies.lists( + hypothesis.strategies.floats( + numpy.finfo(numpy.float32).eps, + 1.0, + ), + min_size=4, + max_size=4, + ), + min_size=n, + max_size=n, + ), + ) + + rotations = Rotation.from_quat(rotations) + + return [ + [ + torch.from_numpy(input), + torch.from_numpy(times), + torch.from_numpy(rotations.as_quat(canonical=True)), + ], + torch.from_numpy( + Slerp(times, rotations)(input).as_quat(canonical=True), + ), + ] + + +@hypothesis.given(slerp_parameters()) +def test_slerp_properties(data): + parameters, expected_rotations = data + + torch.testing.assert_close( + beignet.ops.quaternion_slerp(*parameters), expected_rotations + ) From d05ad11e816d851fb29e28565c910d16e3da3d22 Mon Sep 17 00:00:00 2001 From: Allen Goodman Date: Mon, 13 May 2024 11:25:24 -0400 Subject: [PATCH 02/14] cleanup --- src/beignet/ops/__init__.py | 89 ------ src/beignet/ops/_geometry/__init__.py | 44 --- .../_geometry/_transformations/__init__.py | 60 ----- .../_transformations/_apply_euler_angle.py | 63 ----- .../_transformations/_apply_quaternion.py | 52 ---- .../_apply_rotation_matrix.py | 47 ---- .../_apply_rotation_vector.py | 63 ----- .../_transformations/_compose_euler_angle.py | 53 ---- .../_transformations/_compose_quaternion.py | 73 ----- .../_compose_rotation_matrix.py | 33 --- .../_compose_rotation_vector.py | 45 ---- .../_transformations/_euler_angle_identity.py | 70 ----- .../_euler_angle_magnitude.py | 41 --- .../_transformations/_euler_angle_mean.py | 49 ---- .../_euler_angle_to_quaternion.py | 170 ------------ .../_euler_angle_to_rotation_matrix.py | 80 ------ .../_euler_angle_to_rotation_vector.py | 253 ------------------ .../_transformations/_invert_euler_angle.py | 48 ---- .../_transformations/_invert_quaternion.py | 31 --- .../_invert_rotation_matrix.py | 19 -- .../_invert_rotation_vector.py | 20 -- .../_transformations/_quaternion_identity.py | 64 ----- .../_transformations/_quaternion_magnitude.py | 37 --- .../_transformations/_quaternion_mean.py | 34 --- .../_transformations/_quaternion_slerp.py | 93 ------- .../_quaternion_to_euler_angle.py | 143 ---------- .../_quaternion_to_rotation_matrix.py | 43 --- .../_quaternion_to_rotation_vector.py | 57 ---- .../_transformations/_random_euler_angle.py | 91 ------- .../_transformations/_random_quaternion.py | 95 ------- .../_random_rotation_matrix.py | 69 ----- .../_random_rotation_vector.py | 73 ----- .../_rotation_matrix_identity.py | 58 ---- .../_rotation_matrix_magnitude.py | 27 -- .../_transformations/_rotation_matrix_mean.py | 32 --- .../_rotation_matrix_to_euler_angle.py | 51 ---- .../_rotation_matrix_to_quaternion.py | 88 ------ .../_rotation_matrix_to_rotation_vector.py | 37 --- .../_rotation_vector_identity.py | 64 ----- .../_rotation_vector_magnitude.py | 34 --- .../_transformations/_rotation_vector_mean.py | 42 --- .../_rotation_vector_to_euler_angle.py | 48 ---- .../_rotation_vector_to_quaternion.py | 71 ----- .../_rotation_vector_to_rotation_matrix.py | 37 --- .../_transformations/_translation_identity.py | 51 ---- .../test__apply_euler_angle.py | 94 ------- .../test__apply_quaternion.py | 53 ---- .../test__apply_rotation_matrix.py | 65 ----- .../test__apply_rotation_vector.py | 54 ---- .../test__compose_euler_angle.py | 60 ----- .../test__compose_quaternion.py | 40 --- .../test__compose_rotation_matrix.py | 37 --- .../test__compose_rotation_vector.py | 40 --- .../test__euler_angle_identity.py | 11 - .../test__euler_angle_magnitude.py | 56 ---- .../test__euler_angle_mean.py | 61 ----- .../test__euler_angle_to_quaternion.py | 75 ------ .../test__euler_angle_to_rotation_matrix.py | 65 ----- .../test__euler_angle_to_rotation_vector.py | 63 ----- .../test__invert_euler_angle.py | 56 ---- .../test__invert_quaternion.py | 36 --- .../test__invert_rotation_matrix.py | 33 --- .../test__invert_rotation_vector.py | 35 --- .../test__quaternion_identity.py | 37 --- .../test__quaternion_magnitude.py | 36 --- .../_transformations/test__quaternion_mean.py | 50 ---- .../test__quaternion_to_euler_angle.py | 67 ----- .../test__quaternion_to_rotation_matrix.py | 41 --- .../test__quaternion_to_rotation_vector.py | 46 ---- .../test__random_euler_angle.py | 51 ---- .../test__random_quaternion.py | 31 --- .../test__random_rotation_matrix.py | 28 -- .../test__random_rotation_vector.py | 31 --- .../test__rotation_matrix_identity.py | 34 --- .../test__rotation_matrix_magnitude.py | 33 --- .../test__rotation_matrix_mean.py | 33 --- .../test__rotation_matrix_to_euler_angle.py | 65 ----- .../test__rotation_matrix_to_quaternion.py | 49 ---- ...est__rotation_matrix_to_rotation_vector.py | 45 ---- .../test__rotation_vector_identity.py | 36 --- .../test__rotation_vector_magnitude.py | 36 --- .../test__rotation_vector_mean.py | 39 --- .../test__rotation_vector_to_euler_angle.py | 67 ----- .../test__rotation_vector_to_quaternion.py | 54 ---- ...est__rotation_vector_to_rotation_matrix.py | 42 --- .../_geometry/_transformations/test__slerp.py | 151 ----------- 86 files changed, 4878 deletions(-) delete mode 100644 src/beignet/ops/__init__.py delete mode 100644 src/beignet/ops/_geometry/__init__.py delete mode 100644 src/beignet/ops/_geometry/_transformations/__init__.py delete mode 100644 src/beignet/ops/_geometry/_transformations/_apply_euler_angle.py delete mode 100644 src/beignet/ops/_geometry/_transformations/_apply_quaternion.py delete mode 100644 src/beignet/ops/_geometry/_transformations/_apply_rotation_matrix.py delete mode 100644 src/beignet/ops/_geometry/_transformations/_apply_rotation_vector.py delete mode 100644 src/beignet/ops/_geometry/_transformations/_compose_euler_angle.py delete mode 100644 src/beignet/ops/_geometry/_transformations/_compose_quaternion.py delete mode 100644 src/beignet/ops/_geometry/_transformations/_compose_rotation_matrix.py delete mode 100644 src/beignet/ops/_geometry/_transformations/_compose_rotation_vector.py delete mode 100644 src/beignet/ops/_geometry/_transformations/_euler_angle_identity.py delete mode 100644 src/beignet/ops/_geometry/_transformations/_euler_angle_magnitude.py delete mode 100644 src/beignet/ops/_geometry/_transformations/_euler_angle_mean.py delete mode 100644 src/beignet/ops/_geometry/_transformations/_euler_angle_to_quaternion.py delete mode 100644 src/beignet/ops/_geometry/_transformations/_euler_angle_to_rotation_matrix.py delete mode 100644 src/beignet/ops/_geometry/_transformations/_euler_angle_to_rotation_vector.py delete mode 100644 src/beignet/ops/_geometry/_transformations/_invert_euler_angle.py delete mode 100644 src/beignet/ops/_geometry/_transformations/_invert_quaternion.py delete mode 100644 src/beignet/ops/_geometry/_transformations/_invert_rotation_matrix.py delete mode 100644 src/beignet/ops/_geometry/_transformations/_invert_rotation_vector.py delete mode 100644 src/beignet/ops/_geometry/_transformations/_quaternion_identity.py delete mode 100644 src/beignet/ops/_geometry/_transformations/_quaternion_magnitude.py delete mode 100644 src/beignet/ops/_geometry/_transformations/_quaternion_mean.py delete mode 100644 src/beignet/ops/_geometry/_transformations/_quaternion_slerp.py delete mode 100644 src/beignet/ops/_geometry/_transformations/_quaternion_to_euler_angle.py delete mode 100644 src/beignet/ops/_geometry/_transformations/_quaternion_to_rotation_matrix.py delete mode 100644 src/beignet/ops/_geometry/_transformations/_quaternion_to_rotation_vector.py delete mode 100644 src/beignet/ops/_geometry/_transformations/_random_euler_angle.py delete mode 100644 src/beignet/ops/_geometry/_transformations/_random_quaternion.py delete mode 100644 src/beignet/ops/_geometry/_transformations/_random_rotation_matrix.py delete mode 100644 src/beignet/ops/_geometry/_transformations/_random_rotation_vector.py delete mode 100644 src/beignet/ops/_geometry/_transformations/_rotation_matrix_identity.py delete mode 100644 src/beignet/ops/_geometry/_transformations/_rotation_matrix_magnitude.py delete mode 100644 src/beignet/ops/_geometry/_transformations/_rotation_matrix_mean.py delete mode 100644 src/beignet/ops/_geometry/_transformations/_rotation_matrix_to_euler_angle.py delete mode 100644 src/beignet/ops/_geometry/_transformations/_rotation_matrix_to_quaternion.py delete mode 100644 src/beignet/ops/_geometry/_transformations/_rotation_matrix_to_rotation_vector.py delete mode 100644 src/beignet/ops/_geometry/_transformations/_rotation_vector_identity.py delete mode 100644 src/beignet/ops/_geometry/_transformations/_rotation_vector_magnitude.py delete mode 100644 src/beignet/ops/_geometry/_transformations/_rotation_vector_mean.py delete mode 100644 src/beignet/ops/_geometry/_transformations/_rotation_vector_to_euler_angle.py delete mode 100644 src/beignet/ops/_geometry/_transformations/_rotation_vector_to_quaternion.py delete mode 100644 src/beignet/ops/_geometry/_transformations/_rotation_vector_to_rotation_matrix.py delete mode 100644 src/beignet/ops/_geometry/_transformations/_translation_identity.py delete mode 100644 tests/beignet/ops/_geometry/_transformations/test__apply_euler_angle.py delete mode 100644 tests/beignet/ops/_geometry/_transformations/test__apply_quaternion.py delete mode 100644 tests/beignet/ops/_geometry/_transformations/test__apply_rotation_matrix.py delete mode 100644 tests/beignet/ops/_geometry/_transformations/test__apply_rotation_vector.py delete mode 100644 tests/beignet/ops/_geometry/_transformations/test__compose_euler_angle.py delete mode 100644 tests/beignet/ops/_geometry/_transformations/test__compose_quaternion.py delete mode 100644 tests/beignet/ops/_geometry/_transformations/test__compose_rotation_matrix.py delete mode 100644 tests/beignet/ops/_geometry/_transformations/test__compose_rotation_vector.py delete mode 100644 tests/beignet/ops/_geometry/_transformations/test__euler_angle_identity.py delete mode 100644 tests/beignet/ops/_geometry/_transformations/test__euler_angle_magnitude.py delete mode 100644 tests/beignet/ops/_geometry/_transformations/test__euler_angle_mean.py delete mode 100644 tests/beignet/ops/_geometry/_transformations/test__euler_angle_to_quaternion.py delete mode 100644 tests/beignet/ops/_geometry/_transformations/test__euler_angle_to_rotation_matrix.py delete mode 100644 tests/beignet/ops/_geometry/_transformations/test__euler_angle_to_rotation_vector.py delete mode 100644 tests/beignet/ops/_geometry/_transformations/test__invert_euler_angle.py delete mode 100644 tests/beignet/ops/_geometry/_transformations/test__invert_quaternion.py delete mode 100644 tests/beignet/ops/_geometry/_transformations/test__invert_rotation_matrix.py delete mode 100644 tests/beignet/ops/_geometry/_transformations/test__invert_rotation_vector.py delete mode 100644 tests/beignet/ops/_geometry/_transformations/test__quaternion_identity.py delete mode 100644 tests/beignet/ops/_geometry/_transformations/test__quaternion_magnitude.py delete mode 100644 tests/beignet/ops/_geometry/_transformations/test__quaternion_mean.py delete mode 100644 tests/beignet/ops/_geometry/_transformations/test__quaternion_to_euler_angle.py delete mode 100644 tests/beignet/ops/_geometry/_transformations/test__quaternion_to_rotation_matrix.py delete mode 100644 tests/beignet/ops/_geometry/_transformations/test__quaternion_to_rotation_vector.py delete mode 100644 tests/beignet/ops/_geometry/_transformations/test__random_euler_angle.py delete mode 100644 tests/beignet/ops/_geometry/_transformations/test__random_quaternion.py delete mode 100644 tests/beignet/ops/_geometry/_transformations/test__random_rotation_matrix.py delete mode 100644 tests/beignet/ops/_geometry/_transformations/test__random_rotation_vector.py delete mode 100644 tests/beignet/ops/_geometry/_transformations/test__rotation_matrix_identity.py delete mode 100644 tests/beignet/ops/_geometry/_transformations/test__rotation_matrix_magnitude.py delete mode 100644 tests/beignet/ops/_geometry/_transformations/test__rotation_matrix_mean.py delete mode 100644 tests/beignet/ops/_geometry/_transformations/test__rotation_matrix_to_euler_angle.py delete mode 100644 tests/beignet/ops/_geometry/_transformations/test__rotation_matrix_to_quaternion.py delete mode 100644 tests/beignet/ops/_geometry/_transformations/test__rotation_matrix_to_rotation_vector.py delete mode 100644 tests/beignet/ops/_geometry/_transformations/test__rotation_vector_identity.py delete mode 100644 tests/beignet/ops/_geometry/_transformations/test__rotation_vector_magnitude.py delete mode 100644 tests/beignet/ops/_geometry/_transformations/test__rotation_vector_mean.py delete mode 100644 tests/beignet/ops/_geometry/_transformations/test__rotation_vector_to_euler_angle.py delete mode 100644 tests/beignet/ops/_geometry/_transformations/test__rotation_vector_to_quaternion.py delete mode 100644 tests/beignet/ops/_geometry/_transformations/test__rotation_vector_to_rotation_matrix.py delete mode 100644 tests/beignet/ops/_geometry/_transformations/test__slerp.py diff --git a/src/beignet/ops/__init__.py b/src/beignet/ops/__init__.py deleted file mode 100644 index 90534a8648..0000000000 --- a/src/beignet/ops/__init__.py +++ /dev/null @@ -1,89 +0,0 @@ -from ._geometry import ( - apply_euler_angle, - apply_quaternion, - apply_rotation_matrix, - apply_rotation_vector, - compose_euler_angle, - compose_quaternion, - compose_rotation_matrix, - compose_rotation_vector, - euler_angle_identity, - euler_angle_magnitude, - euler_angle_mean, - euler_angle_to_quaternion, - euler_angle_to_rotation_matrix, - euler_angle_to_rotation_vector, - invert_euler_angle, - invert_quaternion, - invert_rotation_matrix, - invert_rotation_vector, - quaternion_identity, - quaternion_magnitude, - quaternion_mean, - quaternion_slerp, - quaternion_to_euler_angle, - quaternion_to_rotation_matrix, - quaternion_to_rotation_vector, - random_euler_angle, - random_quaternion, - random_rotation_matrix, - random_rotation_vector, - rotation_matrix_identity, - rotation_matrix_magnitude, - rotation_matrix_mean, - rotation_matrix_to_euler_angle, - rotation_matrix_to_quaternion, - rotation_matrix_to_rotation_vector, - rotation_vector_identity, - rotation_vector_magnitude, - rotation_vector_mean, - rotation_vector_to_euler_angle, - rotation_vector_to_quaternion, - rotation_vector_to_rotation_matrix, - translation_identity, -) - -__all__ = [ - "apply_euler_angle", - "apply_quaternion", - "apply_rotation_matrix", - "apply_rotation_vector", - "compose_euler_angle", - "compose_quaternion", - "compose_rotation_matrix", - "compose_rotation_vector", - "euler_angle_identity", - "euler_angle_magnitude", - "euler_angle_mean", - "euler_angle_to_quaternion", - "euler_angle_to_rotation_matrix", - "euler_angle_to_rotation_vector", - "invert_euler_angle", - "invert_quaternion", - "invert_rotation_matrix", - "invert_rotation_vector", - "quaternion_identity", - "quaternion_magnitude", - "quaternion_mean", - "quaternion_to_euler_angle", - "quaternion_to_rotation_matrix", - "quaternion_to_rotation_vector", - "random_euler_angle", - "random_quaternion", - "random_rotation_matrix", - "random_rotation_vector", - "rotation_matrix_identity", - "rotation_matrix_magnitude", - "rotation_matrix_mean", - "rotation_matrix_to_euler_angle", - "rotation_matrix_to_quaternion", - "rotation_matrix_to_rotation_vector", - "rotation_vector_identity", - "rotation_vector_magnitude", - "rotation_vector_mean", - "rotation_vector_to_euler_angle", - "rotation_vector_to_quaternion", - "rotation_vector_to_rotation_matrix", - "quaternion_slerp", - "translation_identity", -] diff --git a/src/beignet/ops/_geometry/__init__.py b/src/beignet/ops/_geometry/__init__.py deleted file mode 100644 index 2d065e7f7f..0000000000 --- a/src/beignet/ops/_geometry/__init__.py +++ /dev/null @@ -1,44 +0,0 @@ -from ._transformations import ( - apply_euler_angle, - apply_quaternion, - apply_rotation_matrix, - apply_rotation_vector, - compose_euler_angle, - compose_quaternion, - compose_rotation_matrix, - compose_rotation_vector, - euler_angle_identity, - euler_angle_magnitude, - euler_angle_mean, - euler_angle_to_quaternion, - euler_angle_to_rotation_matrix, - euler_angle_to_rotation_vector, - invert_euler_angle, - invert_quaternion, - invert_rotation_matrix, - invert_rotation_vector, - quaternion_identity, - quaternion_magnitude, - quaternion_mean, - quaternion_slerp, - quaternion_to_euler_angle, - quaternion_to_rotation_matrix, - quaternion_to_rotation_vector, - random_euler_angle, - random_quaternion, - random_rotation_matrix, - random_rotation_vector, - rotation_matrix_identity, - rotation_matrix_magnitude, - rotation_matrix_mean, - rotation_matrix_to_euler_angle, - rotation_matrix_to_quaternion, - rotation_matrix_to_rotation_vector, - rotation_vector_identity, - rotation_vector_magnitude, - rotation_vector_mean, - rotation_vector_to_euler_angle, - rotation_vector_to_quaternion, - rotation_vector_to_rotation_matrix, - translation_identity, -) diff --git a/src/beignet/ops/_geometry/_transformations/__init__.py b/src/beignet/ops/_geometry/_transformations/__init__.py deleted file mode 100644 index 5f64c220b5..0000000000 --- a/src/beignet/ops/_geometry/_transformations/__init__.py +++ /dev/null @@ -1,60 +0,0 @@ -from ._apply_euler_angle import apply_euler_angle -from ._apply_quaternion import ( - apply_quaternion, -) -from ._apply_rotation_matrix import apply_rotation_matrix -from ._apply_rotation_vector import apply_rotation_vector -from ._compose_euler_angle import compose_euler_angle -from ._compose_quaternion import compose_quaternion -from ._compose_rotation_matrix import compose_rotation_matrix -from ._compose_rotation_vector import compose_rotation_vector -from ._euler_angle_identity import euler_angle_identity -from ._euler_angle_magnitude import euler_angle_magnitude -from ._euler_angle_mean import euler_angle_mean -from ._euler_angle_to_quaternion import ( - euler_angle_to_quaternion, -) -from ._euler_angle_to_rotation_matrix import euler_angle_to_rotation_matrix -from ._euler_angle_to_rotation_vector import euler_angle_to_rotation_vector -from ._invert_euler_angle import invert_euler_angle -from ._invert_quaternion import invert_quaternion -from ._invert_rotation_matrix import invert_rotation_matrix -from ._invert_rotation_vector import invert_rotation_vector -from ._quaternion_identity import quaternion_identity -from ._quaternion_magnitude import quaternion_magnitude -from ._quaternion_mean import quaternion_mean -from ._quaternion_slerp import quaternion_slerp -from ._quaternion_to_euler_angle import ( - quaternion_to_euler_angle, -) -from ._quaternion_to_rotation_matrix import ( - quaternion_to_rotation_matrix, -) -from ._quaternion_to_rotation_vector import ( - quaternion_to_rotation_vector, -) -from ._random_euler_angle import random_euler_angle -from ._random_quaternion import random_quaternion -from ._random_rotation_matrix import random_rotation_matrix -from ._random_rotation_vector import random_rotation_vector -from ._rotation_matrix_identity import rotation_matrix_identity -from ._rotation_matrix_magnitude import rotation_matrix_magnitude -from ._rotation_matrix_mean import rotation_matrix_mean -from ._rotation_matrix_to_euler_angle import rotation_matrix_to_euler_angle -from ._rotation_matrix_to_quaternion import ( - rotation_matrix_to_quaternion, -) -from ._rotation_matrix_to_rotation_vector import ( - rotation_matrix_to_rotation_vector, -) -from ._rotation_vector_identity import rotation_vector_identity -from ._rotation_vector_magnitude import rotation_vector_magnitude -from ._rotation_vector_mean import rotation_vector_mean -from ._rotation_vector_to_euler_angle import rotation_vector_to_euler_angle -from ._rotation_vector_to_quaternion import ( - rotation_vector_to_quaternion, -) -from ._rotation_vector_to_rotation_matrix import ( - rotation_vector_to_rotation_matrix, -) -from ._translation_identity import translation_identity diff --git a/src/beignet/ops/_geometry/_transformations/_apply_euler_angle.py b/src/beignet/ops/_geometry/_transformations/_apply_euler_angle.py deleted file mode 100644 index 3cb9f09079..0000000000 --- a/src/beignet/ops/_geometry/_transformations/_apply_euler_angle.py +++ /dev/null @@ -1,63 +0,0 @@ -from torch import Tensor - -from ._apply_rotation_matrix import apply_rotation_matrix -from ._euler_angle_to_rotation_matrix import euler_angle_to_rotation_matrix - - -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, - ) diff --git a/src/beignet/ops/_geometry/_transformations/_apply_quaternion.py b/src/beignet/ops/_geometry/_transformations/_apply_quaternion.py deleted file mode 100644 index 1410453b88..0000000000 --- a/src/beignet/ops/_geometry/_transformations/_apply_quaternion.py +++ /dev/null @@ -1,52 +0,0 @@ -from torch import Tensor - -from ._apply_rotation_matrix import apply_rotation_matrix -from ._quaternion_to_rotation_matrix import ( - quaternion_to_rotation_matrix, -) - - -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, - ) diff --git a/src/beignet/ops/_geometry/_transformations/_apply_rotation_matrix.py b/src/beignet/ops/_geometry/_transformations/_apply_rotation_matrix.py deleted file mode 100644 index fcac443401..0000000000 --- a/src/beignet/ops/_geometry/_transformations/_apply_rotation_matrix.py +++ /dev/null @@ -1,47 +0,0 @@ -import torch -from torch import Tensor - - -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 diff --git a/src/beignet/ops/_geometry/_transformations/_apply_rotation_vector.py b/src/beignet/ops/_geometry/_transformations/_apply_rotation_vector.py deleted file mode 100644 index 0682bd4ac6..0000000000 --- a/src/beignet/ops/_geometry/_transformations/_apply_rotation_vector.py +++ /dev/null @@ -1,63 +0,0 @@ -from torch import Tensor - -from ._apply_rotation_matrix import apply_rotation_matrix -from ._quaternion_to_rotation_matrix import ( - quaternion_to_rotation_matrix, -) -from ._rotation_vector_to_quaternion import ( - rotation_vector_to_quaternion, -) - - -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, - ) diff --git a/src/beignet/ops/_geometry/_transformations/_compose_euler_angle.py b/src/beignet/ops/_geometry/_transformations/_compose_euler_angle.py deleted file mode 100644 index 3427d724dc..0000000000 --- a/src/beignet/ops/_geometry/_transformations/_compose_euler_angle.py +++ /dev/null @@ -1,53 +0,0 @@ -from torch import Tensor - -from ._compose_quaternion import compose_quaternion -from ._euler_angle_to_quaternion import euler_angle_to_quaternion -from ._quaternion_to_euler_angle import quaternion_to_euler_angle - - -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, - ) diff --git a/src/beignet/ops/_geometry/_transformations/_compose_quaternion.py b/src/beignet/ops/_geometry/_transformations/_compose_quaternion.py deleted file mode 100644 index 35d0b30ae9..0000000000 --- a/src/beignet/ops/_geometry/_transformations/_compose_quaternion.py +++ /dev/null @@ -1,73 +0,0 @@ -import torch -from torch import Tensor - - -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 diff --git a/src/beignet/ops/_geometry/_transformations/_compose_rotation_matrix.py b/src/beignet/ops/_geometry/_transformations/_compose_rotation_matrix.py deleted file mode 100644 index 10b6ce1582..0000000000 --- a/src/beignet/ops/_geometry/_transformations/_compose_rotation_matrix.py +++ /dev/null @@ -1,33 +0,0 @@ -from torch import Tensor - -from ._compose_quaternion import compose_quaternion -from ._quaternion_to_rotation_matrix import quaternion_to_rotation_matrix -from ._rotation_matrix_to_quaternion import rotation_matrix_to_quaternion - - -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), - ), - ) diff --git a/src/beignet/ops/_geometry/_transformations/_compose_rotation_vector.py b/src/beignet/ops/_geometry/_transformations/_compose_rotation_vector.py deleted file mode 100644 index d15223e489..0000000000 --- a/src/beignet/ops/_geometry/_transformations/_compose_rotation_vector.py +++ /dev/null @@ -1,45 +0,0 @@ -from torch import Tensor - -from ._compose_quaternion import compose_quaternion -from ._quaternion_to_rotation_vector import quaternion_to_rotation_vector -from ._rotation_vector_to_quaternion import rotation_vector_to_quaternion - - -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, - ) diff --git a/src/beignet/ops/_geometry/_transformations/_euler_angle_identity.py b/src/beignet/ops/_geometry/_transformations/_euler_angle_identity.py deleted file mode 100644 index 40c716cf3a..0000000000 --- a/src/beignet/ops/_geometry/_transformations/_euler_angle_identity.py +++ /dev/null @@ -1,70 +0,0 @@ -import torch -from torch import Tensor - -from ._quaternion_identity import quaternion_identity -from ._quaternion_to_euler_angle import ( - quaternion_to_euler_angle, -) - - -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, - ) diff --git a/src/beignet/ops/_geometry/_transformations/_euler_angle_magnitude.py b/src/beignet/ops/_geometry/_transformations/_euler_angle_magnitude.py deleted file mode 100644 index 3429062d09..0000000000 --- a/src/beignet/ops/_geometry/_transformations/_euler_angle_magnitude.py +++ /dev/null @@ -1,41 +0,0 @@ -from torch import Tensor - -from ._euler_angle_to_quaternion import ( - euler_angle_to_quaternion, -) -from ._quaternion_magnitude import quaternion_magnitude - - -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, - ), - ) diff --git a/src/beignet/ops/_geometry/_transformations/_euler_angle_mean.py b/src/beignet/ops/_geometry/_transformations/_euler_angle_mean.py deleted file mode 100644 index 5e711958bc..0000000000 --- a/src/beignet/ops/_geometry/_transformations/_euler_angle_mean.py +++ /dev/null @@ -1,49 +0,0 @@ -from torch import Tensor - -from ._euler_angle_to_quaternion import euler_angle_to_quaternion -from ._quaternion_mean import quaternion_mean -from ._quaternion_to_euler_angle import quaternion_to_euler_angle - - -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, - ) diff --git a/src/beignet/ops/_geometry/_transformations/_euler_angle_to_quaternion.py b/src/beignet/ops/_geometry/_transformations/_euler_angle_to_quaternion.py deleted file mode 100644 index 7736d8171b..0000000000 --- a/src/beignet/ops/_geometry/_transformations/_euler_angle_to_quaternion.py +++ /dev/null @@ -1,170 +0,0 @@ -import re - -import torch -from torch import Tensor - - -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 diff --git a/src/beignet/ops/_geometry/_transformations/_euler_angle_to_rotation_matrix.py b/src/beignet/ops/_geometry/_transformations/_euler_angle_to_rotation_matrix.py deleted file mode 100644 index 2d1baf1c28..0000000000 --- a/src/beignet/ops/_geometry/_transformations/_euler_angle_to_rotation_matrix.py +++ /dev/null @@ -1,80 +0,0 @@ -import torch -from torch import Tensor - - -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 diff --git a/src/beignet/ops/_geometry/_transformations/_euler_angle_to_rotation_vector.py b/src/beignet/ops/_geometry/_transformations/_euler_angle_to_rotation_vector.py deleted file mode 100644 index 19dd27cc48..0000000000 --- a/src/beignet/ops/_geometry/_transformations/_euler_angle_to_rotation_vector.py +++ /dev/null @@ -1,253 +0,0 @@ -import re - -import torch -from torch import Tensor - - -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 diff --git a/src/beignet/ops/_geometry/_transformations/_invert_euler_angle.py b/src/beignet/ops/_geometry/_transformations/_invert_euler_angle.py deleted file mode 100644 index 9a7c3c6a6d..0000000000 --- a/src/beignet/ops/_geometry/_transformations/_invert_euler_angle.py +++ /dev/null @@ -1,48 +0,0 @@ -from torch import Tensor - -from ._euler_angle_to_quaternion import ( - euler_angle_to_quaternion, -) -from ._invert_quaternion import invert_quaternion -from ._quaternion_to_euler_angle import ( - quaternion_to_euler_angle, -) - - -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, - ) diff --git a/src/beignet/ops/_geometry/_transformations/_invert_quaternion.py b/src/beignet/ops/_geometry/_transformations/_invert_quaternion.py deleted file mode 100644 index 9762327f75..0000000000 --- a/src/beignet/ops/_geometry/_transformations/_invert_quaternion.py +++ /dev/null @@ -1,31 +0,0 @@ -from torch import Tensor - - -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 diff --git a/src/beignet/ops/_geometry/_transformations/_invert_rotation_matrix.py b/src/beignet/ops/_geometry/_transformations/_invert_rotation_matrix.py deleted file mode 100644 index 4ceba7d74a..0000000000 --- a/src/beignet/ops/_geometry/_transformations/_invert_rotation_matrix.py +++ /dev/null @@ -1,19 +0,0 @@ -import torch -from torch import Tensor - - -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) diff --git a/src/beignet/ops/_geometry/_transformations/_invert_rotation_vector.py b/src/beignet/ops/_geometry/_transformations/_invert_rotation_vector.py deleted file mode 100644 index c592cdbb91..0000000000 --- a/src/beignet/ops/_geometry/_transformations/_invert_rotation_vector.py +++ /dev/null @@ -1,20 +0,0 @@ -from torch import Tensor - - -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 diff --git a/src/beignet/ops/_geometry/_transformations/_quaternion_identity.py b/src/beignet/ops/_geometry/_transformations/_quaternion_identity.py deleted file mode 100644 index 9474cb9669..0000000000 --- a/src/beignet/ops/_geometry/_transformations/_quaternion_identity.py +++ /dev/null @@ -1,64 +0,0 @@ -import torch -from torch import Tensor - - -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 diff --git a/src/beignet/ops/_geometry/_transformations/_quaternion_magnitude.py b/src/beignet/ops/_geometry/_transformations/_quaternion_magnitude.py deleted file mode 100644 index 7d2179c094..0000000000 --- a/src/beignet/ops/_geometry/_transformations/_quaternion_magnitude.py +++ /dev/null @@ -1,37 +0,0 @@ -import torch -from torch import Tensor - - -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 diff --git a/src/beignet/ops/_geometry/_transformations/_quaternion_mean.py b/src/beignet/ops/_geometry/_transformations/_quaternion_mean.py deleted file mode 100644 index c6c0d369be..0000000000 --- a/src/beignet/ops/_geometry/_transformations/_quaternion_mean.py +++ /dev/null @@ -1,34 +0,0 @@ -import torch -from torch import Tensor - - -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 diff --git a/src/beignet/ops/_geometry/_transformations/_quaternion_slerp.py b/src/beignet/ops/_geometry/_transformations/_quaternion_slerp.py deleted file mode 100644 index 694052a637..0000000000 --- a/src/beignet/ops/_geometry/_transformations/_quaternion_slerp.py +++ /dev/null @@ -1,93 +0,0 @@ -import torch -import torch.testing -from torch import Tensor - - -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 diff --git a/src/beignet/ops/_geometry/_transformations/_quaternion_to_euler_angle.py b/src/beignet/ops/_geometry/_transformations/_quaternion_to_euler_angle.py deleted file mode 100644 index e66d7a6459..0000000000 --- a/src/beignet/ops/_geometry/_transformations/_quaternion_to_euler_angle.py +++ /dev/null @@ -1,143 +0,0 @@ -import math -import re - -import torch -from torch import Tensor - - -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 diff --git a/src/beignet/ops/_geometry/_transformations/_quaternion_to_rotation_matrix.py b/src/beignet/ops/_geometry/_transformations/_quaternion_to_rotation_matrix.py deleted file mode 100644 index 20d753af6b..0000000000 --- a/src/beignet/ops/_geometry/_transformations/_quaternion_to_rotation_matrix.py +++ /dev/null @@ -1,43 +0,0 @@ -import torch -from torch import Tensor - - -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 diff --git a/src/beignet/ops/_geometry/_transformations/_quaternion_to_rotation_vector.py b/src/beignet/ops/_geometry/_transformations/_quaternion_to_rotation_vector.py deleted file mode 100644 index 6827c672e8..0000000000 --- a/src/beignet/ops/_geometry/_transformations/_quaternion_to_rotation_vector.py +++ /dev/null @@ -1,57 +0,0 @@ -import torch -from torch import Tensor - - -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 diff --git a/src/beignet/ops/_geometry/_transformations/_random_euler_angle.py b/src/beignet/ops/_geometry/_transformations/_random_euler_angle.py deleted file mode 100644 index f41bea8995..0000000000 --- a/src/beignet/ops/_geometry/_transformations/_random_euler_angle.py +++ /dev/null @@ -1,91 +0,0 @@ -import torch -from torch import Generator, Tensor - -from ._quaternion_to_euler_angle import ( - quaternion_to_euler_angle, -) -from ._random_quaternion import random_quaternion - - -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, - ) diff --git a/src/beignet/ops/_geometry/_transformations/_random_quaternion.py b/src/beignet/ops/_geometry/_transformations/_random_quaternion.py deleted file mode 100644 index 468e4c3e8e..0000000000 --- a/src/beignet/ops/_geometry/_transformations/_random_quaternion.py +++ /dev/null @@ -1,95 +0,0 @@ -import torch -from torch import Generator, Tensor - - -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 diff --git a/src/beignet/ops/_geometry/_transformations/_random_rotation_matrix.py b/src/beignet/ops/_geometry/_transformations/_random_rotation_matrix.py deleted file mode 100644 index 8d9368a1c4..0000000000 --- a/src/beignet/ops/_geometry/_transformations/_random_rotation_matrix.py +++ /dev/null @@ -1,69 +0,0 @@ -import torch -from torch import Generator, Tensor - -from ._quaternion_to_rotation_matrix import ( - quaternion_to_rotation_matrix, -) -from ._random_quaternion import random_quaternion - - -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, - ), - ) diff --git a/src/beignet/ops/_geometry/_transformations/_random_rotation_vector.py b/src/beignet/ops/_geometry/_transformations/_random_rotation_vector.py deleted file mode 100644 index 1cfb578a42..0000000000 --- a/src/beignet/ops/_geometry/_transformations/_random_rotation_vector.py +++ /dev/null @@ -1,73 +0,0 @@ -import torch -from torch import Generator, Tensor - -from ._quaternion_to_rotation_vector import ( - quaternion_to_rotation_vector, -) -from ._random_quaternion import random_quaternion - - -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, - ) diff --git a/src/beignet/ops/_geometry/_transformations/_rotation_matrix_identity.py b/src/beignet/ops/_geometry/_transformations/_rotation_matrix_identity.py deleted file mode 100644 index 4e646a5d85..0000000000 --- a/src/beignet/ops/_geometry/_transformations/_rotation_matrix_identity.py +++ /dev/null @@ -1,58 +0,0 @@ -import torch -from torch import Tensor - -from ._quaternion_identity import quaternion_identity -from ._quaternion_to_rotation_matrix import ( - quaternion_to_rotation_matrix, -) - - -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, - ), - ) diff --git a/src/beignet/ops/_geometry/_transformations/_rotation_matrix_magnitude.py b/src/beignet/ops/_geometry/_transformations/_rotation_matrix_magnitude.py deleted file mode 100644 index 74c39721c7..0000000000 --- a/src/beignet/ops/_geometry/_transformations/_rotation_matrix_magnitude.py +++ /dev/null @@ -1,27 +0,0 @@ -from torch import Tensor - -from ._quaternion_magnitude import quaternion_magnitude -from ._rotation_matrix_to_quaternion import ( - rotation_matrix_to_quaternion, -) - - -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, - ), - ) diff --git a/src/beignet/ops/_geometry/_transformations/_rotation_matrix_mean.py b/src/beignet/ops/_geometry/_transformations/_rotation_matrix_mean.py deleted file mode 100644 index 0fb8bce5a5..0000000000 --- a/src/beignet/ops/_geometry/_transformations/_rotation_matrix_mean.py +++ /dev/null @@ -1,32 +0,0 @@ -from torch import Tensor - -from ._quaternion_mean import quaternion_mean -from ._quaternion_to_rotation_matrix import quaternion_to_rotation_matrix -from ._rotation_matrix_to_quaternion import rotation_matrix_to_quaternion - - -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, - ), - ) diff --git a/src/beignet/ops/_geometry/_transformations/_rotation_matrix_to_euler_angle.py b/src/beignet/ops/_geometry/_transformations/_rotation_matrix_to_euler_angle.py deleted file mode 100644 index cf6515a939..0000000000 --- a/src/beignet/ops/_geometry/_transformations/_rotation_matrix_to_euler_angle.py +++ /dev/null @@ -1,51 +0,0 @@ -from torch import Tensor - -from ._quaternion_to_euler_angle import ( - quaternion_to_euler_angle, -) -from ._rotation_matrix_to_quaternion import ( - rotation_matrix_to_quaternion, -) - - -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, - ) diff --git a/src/beignet/ops/_geometry/_transformations/_rotation_matrix_to_quaternion.py b/src/beignet/ops/_geometry/_transformations/_rotation_matrix_to_quaternion.py deleted file mode 100644 index c415a6f888..0000000000 --- a/src/beignet/ops/_geometry/_transformations/_rotation_matrix_to_quaternion.py +++ /dev/null @@ -1,88 +0,0 @@ -import torch -from torch import Tensor - - -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 diff --git a/src/beignet/ops/_geometry/_transformations/_rotation_matrix_to_rotation_vector.py b/src/beignet/ops/_geometry/_transformations/_rotation_matrix_to_rotation_vector.py deleted file mode 100644 index 75409a01b0..0000000000 --- a/src/beignet/ops/_geometry/_transformations/_rotation_matrix_to_rotation_vector.py +++ /dev/null @@ -1,37 +0,0 @@ -from torch import Tensor - -from ._quaternion_to_rotation_vector import ( - quaternion_to_rotation_vector, -) -from ._rotation_matrix_to_quaternion import ( - rotation_matrix_to_quaternion, -) - - -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, - ) diff --git a/src/beignet/ops/_geometry/_transformations/_rotation_vector_identity.py b/src/beignet/ops/_geometry/_transformations/_rotation_vector_identity.py deleted file mode 100644 index 29a0d0ad38..0000000000 --- a/src/beignet/ops/_geometry/_transformations/_rotation_vector_identity.py +++ /dev/null @@ -1,64 +0,0 @@ -import torch -from torch import Tensor - -from ._quaternion_identity import quaternion_identity -from ._quaternion_to_rotation_vector import ( - quaternion_to_rotation_vector, -) - - -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, - ) diff --git a/src/beignet/ops/_geometry/_transformations/_rotation_vector_magnitude.py b/src/beignet/ops/_geometry/_transformations/_rotation_vector_magnitude.py deleted file mode 100644 index ceb1725235..0000000000 --- a/src/beignet/ops/_geometry/_transformations/_rotation_vector_magnitude.py +++ /dev/null @@ -1,34 +0,0 @@ -from torch import Tensor - -from ._quaternion_magnitude import quaternion_magnitude -from ._rotation_vector_to_quaternion import ( - rotation_vector_to_quaternion, -) - - -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, - ), - ) diff --git a/src/beignet/ops/_geometry/_transformations/_rotation_vector_mean.py b/src/beignet/ops/_geometry/_transformations/_rotation_vector_mean.py deleted file mode 100644 index 8fb8c2a968..0000000000 --- a/src/beignet/ops/_geometry/_transformations/_rotation_vector_mean.py +++ /dev/null @@ -1,42 +0,0 @@ -from torch import Tensor - -from ._quaternion_mean import quaternion_mean -from ._quaternion_to_rotation_vector import quaternion_to_rotation_vector -from ._rotation_vector_to_quaternion import rotation_vector_to_quaternion - - -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, - ) diff --git a/src/beignet/ops/_geometry/_transformations/_rotation_vector_to_euler_angle.py b/src/beignet/ops/_geometry/_transformations/_rotation_vector_to_euler_angle.py deleted file mode 100644 index 8ae5503d5c..0000000000 --- a/src/beignet/ops/_geometry/_transformations/_rotation_vector_to_euler_angle.py +++ /dev/null @@ -1,48 +0,0 @@ -from torch import Tensor - -from ._quaternion_to_euler_angle import ( - quaternion_to_euler_angle, -) -from ._rotation_vector_to_quaternion import ( - rotation_vector_to_quaternion, -) - - -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, - ) diff --git a/src/beignet/ops/_geometry/_transformations/_rotation_vector_to_quaternion.py b/src/beignet/ops/_geometry/_transformations/_rotation_vector_to_quaternion.py deleted file mode 100644 index 92bd81b65a..0000000000 --- a/src/beignet/ops/_geometry/_transformations/_rotation_vector_to_quaternion.py +++ /dev/null @@ -1,71 +0,0 @@ -import torch -from torch import Tensor - - -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 diff --git a/src/beignet/ops/_geometry/_transformations/_rotation_vector_to_rotation_matrix.py b/src/beignet/ops/_geometry/_transformations/_rotation_vector_to_rotation_matrix.py deleted file mode 100644 index 9259f8b233..0000000000 --- a/src/beignet/ops/_geometry/_transformations/_rotation_vector_to_rotation_matrix.py +++ /dev/null @@ -1,37 +0,0 @@ -from torch import Tensor - -from ._quaternion_to_rotation_matrix import ( - quaternion_to_rotation_matrix, -) -from ._rotation_vector_to_quaternion import ( - rotation_vector_to_quaternion, -) - - -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, - ), - ) diff --git a/src/beignet/ops/_geometry/_transformations/_translation_identity.py b/src/beignet/ops/_geometry/_transformations/_translation_identity.py deleted file mode 100644 index 1fa2b6966a..0000000000 --- a/src/beignet/ops/_geometry/_transformations/_translation_identity.py +++ /dev/null @@ -1,51 +0,0 @@ -import torch -from torch import Tensor - - -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, - ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__apply_euler_angle.py b/tests/beignet/ops/_geometry/_transformations/test__apply_euler_angle.py deleted file mode 100644 index 86aa0a1296..0000000000 --- a/tests/beignet/ops/_geometry/_transformations/test__apply_euler_angle.py +++ /dev/null @@ -1,94 +0,0 @@ -import beignet.ops -import hypothesis.extra.numpy -import hypothesis.strategies -import numpy -import torch.testing -from scipy.spatial.transform import Rotation - - -@hypothesis.strategies.composite -def _strategy(function): - size = function( - hypothesis.strategies.integers( - min_value=1, - max_value=8, - ), - ) - - input = function( - hypothesis.extra.numpy.arrays( - numpy.float64, - (size, 3), - elements={ - "allow_infinity": False, - "min_value": numpy.finfo(numpy.float32).min, - "max_value": numpy.finfo(numpy.float32).max, - }, - ), - ) - - rotation = Rotation.random( - size, - ) - - axes = function( - hypothesis.strategies.sampled_from( - [ - "xyz", - "xzy", - "yxz", - "yzx", - "zxy", - "zyx", - "XYZ", - "XZY", - "YXZ", - "YZX", - "ZXY", - "ZYX", - ] - ), - ) - - degrees = function( - hypothesis.strategies.booleans(), - ) - - inverse = function( - hypothesis.strategies.booleans(), - ) - - return ( - { - "input": torch.from_numpy( - input, - ), - "rotation": torch.from_numpy( - rotation.as_euler( - axes, - degrees, - ), - ), - "axes": axes, - "degrees": degrees, - "inverse": inverse, - }, - torch.from_numpy( - rotation.apply( - input, - inverse, - ), - ), - ) - - -@hypothesis.given(_strategy()) -def test_apply_euler_angle(data): - parameters, expected = data - - torch.testing.assert_close( - beignet.ops.apply_euler_angle( - **parameters, - ), - expected, - ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__apply_quaternion.py b/tests/beignet/ops/_geometry/_transformations/test__apply_quaternion.py deleted file mode 100644 index 83a874f815..0000000000 --- a/tests/beignet/ops/_geometry/_transformations/test__apply_quaternion.py +++ /dev/null @@ -1,53 +0,0 @@ -import beignet.ops -import hypothesis.extra.numpy -import hypothesis.strategies -import numpy -import torch.testing -from scipy.spatial.transform import Rotation - - -@hypothesis.strategies.composite -def _strategy(function): - size = function( - hypothesis.strategies.integers( - min_value=1, - max_value=8, - ), - ) - - input = function( - hypothesis.extra.numpy.arrays( - numpy.float64, - (size, 3), - elements={ - "allow_infinity": False, - "min_value": numpy.finfo(numpy.float32).min, - "max_value": numpy.finfo(numpy.float32).max, - }, - ), - ) - - rotation = Rotation.random(size) - - canonical = function(hypothesis.strategies.booleans()) - - inverse = function(hypothesis.strategies.booleans()) - - return ( - { - "input": torch.from_numpy(input), - "rotation": torch.from_numpy(rotation.as_quat(canonical)), - "inverse": inverse, - }, - torch.from_numpy(rotation.apply(input, inverse)), - ) - - -@hypothesis.given(_strategy()) -def test_apply_quaternion(data): - parameters, expected = data - - torch.testing.assert_close( - beignet.ops.apply_quaternion(**parameters), - expected, - ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__apply_rotation_matrix.py b/tests/beignet/ops/_geometry/_transformations/test__apply_rotation_matrix.py deleted file mode 100644 index 4ce23b05ac..0000000000 --- a/tests/beignet/ops/_geometry/_transformations/test__apply_rotation_matrix.py +++ /dev/null @@ -1,65 +0,0 @@ -import beignet.ops -import hypothesis.extra.numpy -import hypothesis.strategies -import numpy -import torch.testing -from scipy.spatial.transform import Rotation - - -@hypothesis.strategies.composite -def _strategy(function): - size = function( - hypothesis.strategies.integers( - min_value=1, - max_value=8, - ), - ) - - input = function( - hypothesis.extra.numpy.arrays( - numpy.float64, - (size, 3), - elements={ - "allow_infinity": False, - "min_value": numpy.finfo(numpy.float32).min, - "max_value": numpy.finfo(numpy.float32).max, - }, - ), - ) - - rotation = Rotation.random(size) - - inverse = function(hypothesis.strategies.booleans()) - - return ( - { - "input": torch.from_numpy( - input, - ), - "rotation": torch.from_numpy( - rotation.as_matrix(), - ), - "inverse": inverse, - }, - torch.from_numpy( - rotation.apply( - input, - inverse, - ), - ), - ) - - -@hypothesis.given(_strategy()) -def test_apply_rotation_matrix(data): - parameters, expected = data - - torch.testing.assert_close( - beignet.ops.apply_rotation_matrix( - **parameters, - ), - expected, - equal_nan=True, - atol=1e-06, - rtol=1e-06, - ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__apply_rotation_vector.py b/tests/beignet/ops/_geometry/_transformations/test__apply_rotation_vector.py deleted file mode 100644 index 33a5aa31ec..0000000000 --- a/tests/beignet/ops/_geometry/_transformations/test__apply_rotation_vector.py +++ /dev/null @@ -1,54 +0,0 @@ -import beignet.ops -import hypothesis.extra.numpy -import hypothesis.strategies -import numpy -import torch.testing -from scipy.spatial.transform import Rotation - - -@hypothesis.strategies.composite -def _strategy(function): - size = function( - hypothesis.strategies.integers( - min_value=1, - max_value=8, - ), - ) - - input = function( - hypothesis.extra.numpy.arrays( - numpy.float64, - (size, 3), - elements={ - "allow_infinity": False, - "min_value": numpy.finfo(numpy.float32).min, - "max_value": numpy.finfo(numpy.float32).max, - }, - ), - ) - - rotation = Rotation.random(size) - - degrees = function(hypothesis.strategies.booleans()) - - inverse = function(hypothesis.strategies.booleans()) - - return ( - { - "input": torch.from_numpy(input), - "rotation": torch.from_numpy(rotation.as_rotvec(degrees)), - "degrees": degrees, - "inverse": inverse, - }, - torch.from_numpy(rotation.apply(input, inverse)), - ) - - -@hypothesis.given(_strategy()) -def test_apply_rotation_vector(data): - parameters, expected = data - - torch.testing.assert_close( - beignet.ops.apply_rotation_vector(**parameters), - expected, - ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__compose_euler_angle.py b/tests/beignet/ops/_geometry/_transformations/test__compose_euler_angle.py deleted file mode 100644 index 814e397bdc..0000000000 --- a/tests/beignet/ops/_geometry/_transformations/test__compose_euler_angle.py +++ /dev/null @@ -1,60 +0,0 @@ -import operator - -import beignet.ops -import hypothesis.strategies -import torch.testing -from scipy.spatial.transform import Rotation - - -@hypothesis.strategies.composite -def _strategy(function): - size = function( - hypothesis.strategies.integers( - min_value=16, - max_value=32, - ), - ) - - input = Rotation.random(size) - other = Rotation.random(size) - - axes = function( - hypothesis.strategies.sampled_from( - [ - "xyz", - "xzy", - "yxz", - "yzx", - "zxy", - "zyx", - "XYZ", - "XZY", - "YXZ", - "YZX", - "ZXY", - "ZYX", - ] - ), - ) - - degrees = function(hypothesis.strategies.booleans()) - - return ( - { - "input": torch.from_numpy(input.as_euler(axes, degrees)), - "other": torch.from_numpy(other.as_euler(axes, degrees)), - "axes": axes, - "degrees": degrees, - }, - torch.from_numpy(operator.mul(input, other).as_euler(axes, degrees)), - ) - - -@hypothesis.given(_strategy()) -def test_compose_euler_angle(data): - parameters, expected = data - - torch.testing.assert_close( - beignet.ops.compose_euler_angle(**parameters), - expected, - ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__compose_quaternion.py b/tests/beignet/ops/_geometry/_transformations/test__compose_quaternion.py deleted file mode 100644 index a0f51f686b..0000000000 --- a/tests/beignet/ops/_geometry/_transformations/test__compose_quaternion.py +++ /dev/null @@ -1,40 +0,0 @@ -import operator - -import beignet.ops -import hypothesis.strategies -import torch.testing -from scipy.spatial.transform import Rotation - - -@hypothesis.strategies.composite -def _strategy(function): - size = function( - hypothesis.strategies.integers( - min_value=16, - max_value=32, - ), - ) - - input = Rotation.random(size) - other = Rotation.random(size) - - canonical = function(hypothesis.strategies.booleans()) - - return ( - { - "input": torch.from_numpy(input.as_quat(canonical)), - "other": torch.from_numpy(other.as_quat(canonical)), - "canonical": canonical, - }, - torch.abs(torch.from_numpy(operator.mul(input, other).as_quat(canonical))), - ) - - -@hypothesis.given(_strategy()) -def test_compose_quaternion(data): - parameters, expected = data - - torch.testing.assert_close( - torch.abs(beignet.ops.compose_quaternion(**parameters)), - expected, - ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__compose_rotation_matrix.py b/tests/beignet/ops/_geometry/_transformations/test__compose_rotation_matrix.py deleted file mode 100644 index a6e042d524..0000000000 --- a/tests/beignet/ops/_geometry/_transformations/test__compose_rotation_matrix.py +++ /dev/null @@ -1,37 +0,0 @@ -import operator - -import beignet.ops -import hypothesis.strategies -import torch.testing -from scipy.spatial.transform import Rotation - - -@hypothesis.strategies.composite -def _strategy(function): - size = function( - hypothesis.strategies.integers( - min_value=16, - max_value=32, - ), - ) - - input = Rotation.random(size) - other = Rotation.random(size) - - return ( - { - "input": torch.from_numpy(input.as_matrix()), - "other": torch.from_numpy(other.as_matrix()), - }, - torch.from_numpy(operator.mul(input, other).as_matrix()), - ) - - -@hypothesis.given(_strategy()) -def test_compose_rotation_matrix(data): - parameters, expected = data - - torch.testing.assert_close( - beignet.ops.compose_rotation_matrix(**parameters), - expected, - ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__compose_rotation_vector.py b/tests/beignet/ops/_geometry/_transformations/test__compose_rotation_vector.py deleted file mode 100644 index 2a6f3e09ae..0000000000 --- a/tests/beignet/ops/_geometry/_transformations/test__compose_rotation_vector.py +++ /dev/null @@ -1,40 +0,0 @@ -import operator - -import beignet.ops -import hypothesis.strategies -import torch.testing -from scipy.spatial.transform import Rotation - - -@hypothesis.strategies.composite -def _strategy(function): - size = function( - hypothesis.strategies.integers( - min_value=16, - max_value=32, - ), - ) - - input = Rotation.random(size) - other = Rotation.random(size) - - degrees = function(hypothesis.strategies.booleans()) - - return ( - { - "input": torch.from_numpy(input.as_rotvec(degrees)), - "other": torch.from_numpy(other.as_rotvec(degrees)), - "degrees": degrees, - }, - torch.from_numpy(operator.mul(input, other).as_rotvec(degrees)), - ) - - -@hypothesis.given(_strategy()) -def test_compose_rotation_vector(data): - parameters, expected = data - - torch.testing.assert_close( - beignet.ops.compose_rotation_vector(**parameters), - expected, - ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__euler_angle_identity.py b/tests/beignet/ops/_geometry/_transformations/test__euler_angle_identity.py deleted file mode 100644 index f9706d7bd8..0000000000 --- a/tests/beignet/ops/_geometry/_transformations/test__euler_angle_identity.py +++ /dev/null @@ -1,11 +0,0 @@ -import hypothesis.strategies - - -@hypothesis.strategies.composite -def strategy(f): - return - - -@hypothesis.given(strategy()) -def test_euler_angle_identity(data): - assert True diff --git a/tests/beignet/ops/_geometry/_transformations/test__euler_angle_magnitude.py b/tests/beignet/ops/_geometry/_transformations/test__euler_angle_magnitude.py deleted file mode 100644 index 169376b4c5..0000000000 --- a/tests/beignet/ops/_geometry/_transformations/test__euler_angle_magnitude.py +++ /dev/null @@ -1,56 +0,0 @@ -import beignet.ops -import hypothesis.strategies -import torch.testing -from scipy.spatial.transform import Rotation - - -@hypothesis.strategies.composite -def _strategy(function): - axes = function( - hypothesis.strategies.sampled_from( - [ - "xyz", - "xzy", - "yxz", - "yzx", - "zxy", - "zyx", - "XYZ", - "XZY", - "YXZ", - "YZX", - "ZXY", - "ZYX", - ] - ), - ) - - degrees = function(hypothesis.strategies.booleans()) - - rotations = Rotation.random( - function( - hypothesis.strategies.integers( - min_value=1, - max_value=8, - ), - ), - ) - - return ( - { - "input": torch.from_numpy(rotations.as_euler(axes, degrees)), - "axes": axes, - "degrees": degrees, - }, - torch.from_numpy(rotations.magnitude()), - ) - - -@hypothesis.given(_strategy()) -def test_euler_angle_magnitude(data): - parameters, expected = data - - torch.testing.assert_close( - beignet.ops.euler_angle_magnitude(**parameters), - expected, - ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__euler_angle_mean.py b/tests/beignet/ops/_geometry/_transformations/test__euler_angle_mean.py deleted file mode 100644 index 31a568d598..0000000000 --- a/tests/beignet/ops/_geometry/_transformations/test__euler_angle_mean.py +++ /dev/null @@ -1,61 +0,0 @@ -import beignet.ops -import hypothesis.strategies -import torch.testing -from scipy.spatial.transform import Rotation - - -@hypothesis.strategies.composite -def _strategy(function): - size = function( - hypothesis.strategies.integers( - min_value=16, - max_value=32, - ), - ) - - input = Rotation.random(size) - - axes = function( - hypothesis.strategies.sampled_from( - [ - "xyz", - "xzy", - "yxz", - "yzx", - "zxy", - "zyx", - "XYZ", - "XZY", - "YXZ", - "YZX", - "ZXY", - "ZYX", - ] - ), - ) - - degrees = function(hypothesis.strategies.booleans()) - - return ( - { - "input": torch.from_numpy(input.as_euler(axes, degrees)), - "axes": axes, - "degrees": degrees, - }, - torch.unsqueeze( - torch.from_numpy( - input.mean().as_euler(axes, degrees), - ), - dim=0, - ), - ) - - -@hypothesis.given(_strategy()) -def test_euler_angle_mean(data): - parameters, expected = data - - torch.testing.assert_close( - beignet.ops.euler_angle_mean(**parameters), - expected, - ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__euler_angle_to_quaternion.py b/tests/beignet/ops/_geometry/_transformations/test__euler_angle_to_quaternion.py deleted file mode 100644 index 1043a994c2..0000000000 --- a/tests/beignet/ops/_geometry/_transformations/test__euler_angle_to_quaternion.py +++ /dev/null @@ -1,75 +0,0 @@ -import beignet.ops -import hypothesis.extra.numpy -import hypothesis.strategies -import torch -from scipy.spatial.transform import Rotation - - -@hypothesis.strategies.composite -def _strategy(function): - rotation = Rotation.random( - function( - hypothesis.strategies.integers( - min_value=16, - max_value=32, - ), - ), - ) - - axes = function( - hypothesis.strategies.sampled_from( - [ - "xyz", - "xzy", - "yxz", - "yzx", - "zxy", - "zyx", - "XYZ", - "XZY", - "YXZ", - "YZX", - "ZXY", - "ZYX", - ] - ), - ) - - degrees = function(hypothesis.strategies.booleans()) - - canonical = function(hypothesis.strategies.booleans()) - - return ( - { - "input": torch.from_numpy( - rotation.as_euler( - axes, - degrees, - ), - ), - "axes": axes, - "degrees": degrees, - "canonical": canonical, - }, - torch.abs( - torch.from_numpy( - rotation.as_quat( - canonical, - ), - ), - ), - ) - - -@hypothesis.given(_strategy()) -def test_euler_angle_to_quaternion(data): - parameters, expected = data - - torch.testing.assert_close( - torch.abs( - beignet.ops.euler_angle_to_quaternion( - **parameters, - ), - ), - expected, - ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__euler_angle_to_rotation_matrix.py b/tests/beignet/ops/_geometry/_transformations/test__euler_angle_to_rotation_matrix.py deleted file mode 100644 index 4e63942c86..0000000000 --- a/tests/beignet/ops/_geometry/_transformations/test__euler_angle_to_rotation_matrix.py +++ /dev/null @@ -1,65 +0,0 @@ -import beignet.ops -import hypothesis.strategies -import torch.testing -from scipy.spatial.transform import Rotation - - -@hypothesis.strategies.composite -def _strategy(function): - rotation = Rotation.random( - function( - hypothesis.strategies.integers( - min_value=16, - max_value=32, - ), - ), - ) - - axes = function( - hypothesis.strategies.sampled_from( - [ - "xyz", - "xzy", - "yxz", - "yzx", - "zxy", - "zyx", - "XYZ", - "XZY", - "YXZ", - "YZX", - "ZXY", - "ZYX", - ] - ), - ) - - degrees = function(hypothesis.strategies.booleans()) - - return ( - { - "input": torch.from_numpy( - rotation.as_euler( - axes, - degrees, - ), - ), - "axes": axes, - "degrees": degrees, - }, - torch.from_numpy( - rotation.as_matrix(), - ), - ) - - -@hypothesis.given(_strategy()) -def test_euler_angle_to_rotation_matrix(data): - parameters, expected = data - - torch.testing.assert_close( - beignet.ops.euler_angle_to_rotation_matrix( - **parameters, - ), - expected, - ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__euler_angle_to_rotation_vector.py b/tests/beignet/ops/_geometry/_transformations/test__euler_angle_to_rotation_vector.py deleted file mode 100644 index 20f2adea53..0000000000 --- a/tests/beignet/ops/_geometry/_transformations/test__euler_angle_to_rotation_vector.py +++ /dev/null @@ -1,63 +0,0 @@ -import beignet.ops -import hypothesis.strategies -import torch -from scipy.spatial.transform import Rotation - - -@hypothesis.strategies.composite -def _strategy(function): - rotation = Rotation.random( - function( - hypothesis.strategies.integers( - min_value=16, - max_value=32, - ), - ), - ) - - axes = function( - hypothesis.strategies.sampled_from( - [ - "xyz", - "xzy", - "yxz", - "yzx", - "zxy", - "zyx", - "XYZ", - "XZY", - "YXZ", - "YZX", - "ZXY", - "ZYX", - ] - ), - ) - - degrees = function(hypothesis.strategies.booleans()) - - return ( - { - "input": torch.from_numpy( - rotation.as_euler( - axes, - degrees, - ), - ), - "axes": axes, - "degrees": degrees, - }, - torch.from_numpy(rotation.as_rotvec(degrees)), - ) - - -@hypothesis.given(_strategy()) -def test_euler_angle_to_rotation_vector(data): - parameters, expected = data - - torch.testing.assert_close( - beignet.ops.euler_angle_to_rotation_vector( - **parameters, - ), - expected, - ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__invert_euler_angle.py b/tests/beignet/ops/_geometry/_transformations/test__invert_euler_angle.py deleted file mode 100644 index d6505e2b31..0000000000 --- a/tests/beignet/ops/_geometry/_transformations/test__invert_euler_angle.py +++ /dev/null @@ -1,56 +0,0 @@ -import beignet.ops -import hypothesis.strategies -import torch.testing -from scipy.spatial.transform import Rotation - - -@hypothesis.strategies.composite -def _strategy(function): - axes = function( - hypothesis.strategies.sampled_from( - [ - "xyz", - "xzy", - "yxz", - "yzx", - "zxy", - "zyx", - "XYZ", - "XZY", - "YXZ", - "YZX", - "ZXY", - "ZYX", - ] - ), - ) - - degrees = function(hypothesis.strategies.booleans()) - - rotations = Rotation.random( - function( - hypothesis.strategies.integers( - min_value=1, - max_value=8, - ), - ), - ) - - return ( - { - "input": torch.from_numpy(rotations.as_euler(axes, degrees)), - "axes": axes, - "degrees": degrees, - }, - torch.from_numpy(rotations.inv().as_euler(axes, degrees)), - ) - - -@hypothesis.given(_strategy()) -def test_invert_euler_angle(data): - parameters, expected = data - - torch.testing.assert_close( - beignet.ops.invert_euler_angle(**parameters), - expected, - ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__invert_quaternion.py b/tests/beignet/ops/_geometry/_transformations/test__invert_quaternion.py deleted file mode 100644 index 78cc7f5195..0000000000 --- a/tests/beignet/ops/_geometry/_transformations/test__invert_quaternion.py +++ /dev/null @@ -1,36 +0,0 @@ -import beignet.ops -import hypothesis.strategies -import torch.testing -from scipy.spatial.transform import Rotation - - -@hypothesis.strategies.composite -def _strategy(function): - canonical = function(hypothesis.strategies.booleans()) - - rotations = Rotation.random( - function( - hypothesis.strategies.integers( - min_value=1, - max_value=8, - ), - ), - ) - - return ( - { - "input": torch.from_numpy(rotations.as_quat(canonical)), - "canonical": canonical, - }, - torch.from_numpy(rotations.inv().as_quat(canonical)), - ) - - -@hypothesis.given(_strategy()) -def test_invert_quaternion(data): - parameters, expected = data - - torch.testing.assert_close( - beignet.ops.invert_quaternion(**parameters), - expected, - ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__invert_rotation_matrix.py b/tests/beignet/ops/_geometry/_transformations/test__invert_rotation_matrix.py deleted file mode 100644 index 9267f65c22..0000000000 --- a/tests/beignet/ops/_geometry/_transformations/test__invert_rotation_matrix.py +++ /dev/null @@ -1,33 +0,0 @@ -import beignet.ops -import hypothesis.strategies -import torch.testing -from scipy.spatial.transform import Rotation - - -@hypothesis.strategies.composite -def _strategy(function): - rotations = Rotation.random( - function( - hypothesis.strategies.integers( - min_value=1, - max_value=8, - ), - ), - ) - - return ( - { - "input": torch.from_numpy(rotations.as_matrix()), - }, - torch.from_numpy(rotations.inv().as_matrix()), - ) - - -@hypothesis.given(_strategy()) -def test_invert_rotation_matrix(data): - parameters, expected = data - - torch.testing.assert_close( - beignet.ops.invert_rotation_matrix(**parameters), - expected, - ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__invert_rotation_vector.py b/tests/beignet/ops/_geometry/_transformations/test__invert_rotation_vector.py deleted file mode 100644 index a215243901..0000000000 --- a/tests/beignet/ops/_geometry/_transformations/test__invert_rotation_vector.py +++ /dev/null @@ -1,35 +0,0 @@ -import beignet.ops -import hypothesis.strategies -import torch.testing -from scipy.spatial.transform import Rotation - - -@hypothesis.strategies.composite -def _strategy(function): - degrees = function(hypothesis.strategies.booleans()) - - rotations = Rotation.random( - function( - hypothesis.strategies.integers( - min_value=1, - max_value=8, - ), - ), - ) - - return ( - { - "input": torch.from_numpy(rotations.as_rotvec(degrees)), - }, - torch.from_numpy(rotations.inv().as_rotvec(degrees)), - ) - - -@hypothesis.given(_strategy()) -def test_invert_rotation_vector(data): - parameters, expected = data - - torch.testing.assert_close( - beignet.ops.invert_rotation_vector(**parameters), - expected, - ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__quaternion_identity.py b/tests/beignet/ops/_geometry/_transformations/test__quaternion_identity.py deleted file mode 100644 index f7f69c6f77..0000000000 --- a/tests/beignet/ops/_geometry/_transformations/test__quaternion_identity.py +++ /dev/null @@ -1,37 +0,0 @@ -import beignet.ops -import hypothesis.strategies -import torch -from scipy.spatial.transform import Rotation - - -@hypothesis.strategies.composite -def _strategy(function): - size = function( - hypothesis.strategies.integers( - min_value=1, - max_value=8, - ), - ) - - rotation = Rotation.identity(size) - - canonical = function(hypothesis.strategies.booleans()) - - return ( - { - "size": size, - "canonical": canonical, - "dtype": torch.float64, - }, - torch.from_numpy(rotation.as_quat(canonical)), - ) - - -@hypothesis.given(_strategy()) -def test_quaternion_identity(data): - parameters, expected = data - - torch.testing.assert_close( - beignet.ops.quaternion_identity(**parameters), - expected, - ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__quaternion_magnitude.py b/tests/beignet/ops/_geometry/_transformations/test__quaternion_magnitude.py deleted file mode 100644 index 1bfe4e8a24..0000000000 --- a/tests/beignet/ops/_geometry/_transformations/test__quaternion_magnitude.py +++ /dev/null @@ -1,36 +0,0 @@ -import beignet.ops -import hypothesis.strategies -import torch.testing -from scipy.spatial.transform import Rotation - - -@hypothesis.strategies.composite -def _strategy(function): - canonical = function(hypothesis.strategies.booleans()) - - rotations = Rotation.random( - function( - hypothesis.strategies.integers( - min_value=1, - max_value=8, - ), - ), - ) - - return ( - { - "input": torch.from_numpy(rotations.as_quat(canonical)), - "canonical": canonical, - }, - torch.from_numpy(rotations.magnitude()), - ) - - -@hypothesis.given(_strategy()) -def test_quaternion_magnitude(data): - parameters, expected = data - - torch.testing.assert_close( - beignet.ops.quaternion_magnitude(**parameters), - expected, - ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__quaternion_mean.py b/tests/beignet/ops/_geometry/_transformations/test__quaternion_mean.py deleted file mode 100644 index 01d3b1baac..0000000000 --- a/tests/beignet/ops/_geometry/_transformations/test__quaternion_mean.py +++ /dev/null @@ -1,50 +0,0 @@ -import beignet.ops -import hypothesis.strategies -import torch.testing -from scipy.spatial.transform import Rotation - - -@hypothesis.strategies.composite -def _strategy(function): - rotation = Rotation.random( - function( - hypothesis.strategies.integers( - min_value=1, - max_value=8, - ), - ), - ) - - return ( - { - "input": torch.from_numpy( - rotation.as_quat( - canonical=False, - ), - ), - }, - torch.unsqueeze( - torch.abs( - torch.from_numpy( - rotation.mean().as_quat( - canonical=False, - ), - ), - ), - dim=0, - ), - ) - - -@hypothesis.given(_strategy()) -def test_quaternion_mean(data): - parameters, expected = data - - torch.testing.assert_close( - torch.abs( - beignet.ops.quaternion_mean( - **parameters, - ), - ), - expected, - ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__quaternion_to_euler_angle.py b/tests/beignet/ops/_geometry/_transformations/test__quaternion_to_euler_angle.py deleted file mode 100644 index 9f2b6129e4..0000000000 --- a/tests/beignet/ops/_geometry/_transformations/test__quaternion_to_euler_angle.py +++ /dev/null @@ -1,67 +0,0 @@ -import beignet.ops -import hypothesis.strategies -import torch -from scipy.spatial.transform import Rotation - - -@hypothesis.strategies.composite -def _strategy(function): - rotation = Rotation.random( - function( - hypothesis.strategies.integers( - min_value=16, - max_value=32, - ), - ), - ) - - axes = function( - hypothesis.strategies.sampled_from( - [ - "xyz", - "xzy", - "yxz", - "yzx", - "zxy", - "zyx", - "XYZ", - "XZY", - "YXZ", - "YZX", - "ZXY", - "ZYX", - ] - ), - ) - - degrees = function(hypothesis.strategies.booleans()) - - return ( - { - "input": torch.from_numpy( - rotation.as_quat( - canonical=False, - ), - ), - "axes": axes, - "degrees": degrees, - }, - torch.from_numpy( - rotation.as_euler( - axes, - degrees, - ), - ), - ) - - -@hypothesis.given(_strategy()) -def test_quaternion_to_euler_angle(data): - parameters, expected = data - - torch.testing.assert_close( - beignet.ops.quaternion_to_euler_angle( - **parameters, - ), - expected, - ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__quaternion_to_rotation_matrix.py b/tests/beignet/ops/_geometry/_transformations/test__quaternion_to_rotation_matrix.py deleted file mode 100644 index ebea9a70ed..0000000000 --- a/tests/beignet/ops/_geometry/_transformations/test__quaternion_to_rotation_matrix.py +++ /dev/null @@ -1,41 +0,0 @@ -import beignet.ops -import hypothesis.strategies -import torch -from scipy.spatial.transform import Rotation - - -@hypothesis.strategies.composite -def _strategy(function): - rotation = Rotation.random( - function( - hypothesis.strategies.integers( - min_value=16, - max_value=32, - ), - ), - ) - - return ( - { - "input": torch.from_numpy( - rotation.as_quat( - canonical=False, - ), - ), - }, - torch.from_numpy( - rotation.as_matrix(), - ), - ) - - -@hypothesis.given(_strategy()) -def test_quaternion_to_rotation_matrix(data): - parameters, expected = data - - torch.testing.assert_close( - beignet.ops.quaternion_to_rotation_matrix( - **parameters, - ), - expected, - ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__quaternion_to_rotation_vector.py b/tests/beignet/ops/_geometry/_transformations/test__quaternion_to_rotation_vector.py deleted file mode 100644 index 5c69a9e1b3..0000000000 --- a/tests/beignet/ops/_geometry/_transformations/test__quaternion_to_rotation_vector.py +++ /dev/null @@ -1,46 +0,0 @@ -import beignet.ops -import hypothesis.strategies -import torch -from scipy.spatial.transform import Rotation - - -@hypothesis.strategies.composite -def _strategy(function): - rotation = Rotation.random( - function( - hypothesis.strategies.integers( - min_value=16, - max_value=32, - ), - ), - ) - - degrees = function(hypothesis.strategies.booleans()) - - return ( - { - "input": torch.from_numpy( - rotation.as_quat( - canonical=False, - ), - ), - "degrees": degrees, - }, - torch.from_numpy( - rotation.as_rotvec( - degrees, - ), - ), - ) - - -@hypothesis.given(_strategy()) -def test_quaternion_to_rotation_vector(data): - parameters, expected = data - - torch.testing.assert_close( - beignet.ops.quaternion_to_rotation_vector( - **parameters, - ), - expected, - ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__random_euler_angle.py b/tests/beignet/ops/_geometry/_transformations/test__random_euler_angle.py deleted file mode 100644 index ca0ef5fb2c..0000000000 --- a/tests/beignet/ops/_geometry/_transformations/test__random_euler_angle.py +++ /dev/null @@ -1,51 +0,0 @@ -import beignet.ops -import hypothesis.strategies - - -@hypothesis.strategies.composite -def _strategy(function): - size = function( - hypothesis.strategies.integers( - min_value=1, - max_value=8, - ), - ) - - axes = function( - hypothesis.strategies.sampled_from( - [ - "xyz", - "xzy", - "yxz", - "yzx", - "zxy", - "zyx", - "XYZ", - "XZY", - "YXZ", - "YZX", - "ZXY", - "ZYX", - ] - ), - ) - - degrees = function(hypothesis.strategies.booleans()) - - return ( - { - "size": size, - "axes": axes, - "degrees": degrees, - }, - None, - ) - - -@hypothesis.given(_strategy()) -def test_random_euler_angle(data): - parameters, _ = data - - assert beignet.ops.random_euler_angle( - **parameters, - ).shape == (parameters["size"], 3) diff --git a/tests/beignet/ops/_geometry/_transformations/test__random_quaternion.py b/tests/beignet/ops/_geometry/_transformations/test__random_quaternion.py deleted file mode 100644 index 938e79339c..0000000000 --- a/tests/beignet/ops/_geometry/_transformations/test__random_quaternion.py +++ /dev/null @@ -1,31 +0,0 @@ -import beignet.ops -import hypothesis.strategies - - -@hypothesis.strategies.composite -def _strategy(function): - size = function( - hypothesis.strategies.integers( - min_value=1, - max_value=8, - ), - ) - - canonical = function(hypothesis.strategies.booleans()) - - return ( - { - "size": size, - "canonical": canonical, - }, - None, - ) - - -@hypothesis.given(_strategy()) -def test_random_quaternion(data): - parameters, _ = data - - assert beignet.ops.random_quaternion( - **parameters, - ).shape == (parameters["size"], 4) diff --git a/tests/beignet/ops/_geometry/_transformations/test__random_rotation_matrix.py b/tests/beignet/ops/_geometry/_transformations/test__random_rotation_matrix.py deleted file mode 100644 index 7e007b2b2f..0000000000 --- a/tests/beignet/ops/_geometry/_transformations/test__random_rotation_matrix.py +++ /dev/null @@ -1,28 +0,0 @@ -import beignet.ops -import hypothesis.strategies - - -@hypothesis.strategies.composite -def _strategy(function): - size = function( - hypothesis.strategies.integers( - min_value=1, - max_value=8, - ), - ) - - return ( - { - "size": size, - }, - None, - ) - - -@hypothesis.given(_strategy()) -def test_random_rotation_matrix(data): - parameters, _ = data - - assert beignet.ops.random_rotation_matrix( - **parameters, - ).shape == (parameters["size"], 3, 3) diff --git a/tests/beignet/ops/_geometry/_transformations/test__random_rotation_vector.py b/tests/beignet/ops/_geometry/_transformations/test__random_rotation_vector.py deleted file mode 100644 index c214441eb9..0000000000 --- a/tests/beignet/ops/_geometry/_transformations/test__random_rotation_vector.py +++ /dev/null @@ -1,31 +0,0 @@ -import beignet.ops -import hypothesis.strategies - - -@hypothesis.strategies.composite -def _strategy(function): - size = function( - hypothesis.strategies.integers( - min_value=1, - max_value=8, - ), - ) - - degrees = function(hypothesis.strategies.booleans()) - - return ( - { - "size": size, - "degrees": degrees, - }, - None, - ) - - -@hypothesis.given(_strategy()) -def test_random_rotation_vector(data): - parameters, _ = data - - assert beignet.ops.random_rotation_vector( - **parameters, - ).shape == (parameters["size"], 3) diff --git a/tests/beignet/ops/_geometry/_transformations/test__rotation_matrix_identity.py b/tests/beignet/ops/_geometry/_transformations/test__rotation_matrix_identity.py deleted file mode 100644 index 13d163f692..0000000000 --- a/tests/beignet/ops/_geometry/_transformations/test__rotation_matrix_identity.py +++ /dev/null @@ -1,34 +0,0 @@ -import beignet.ops -import hypothesis.strategies -import torch -from scipy.spatial.transform import Rotation - - -@hypothesis.strategies.composite -def _strategy(function): - size = function( - hypothesis.strategies.integers( - min_value=1, - max_value=8, - ), - ) - - rotation = Rotation.identity(size) - - return ( - { - "size": size, - "dtype": torch.float64, - }, - torch.from_numpy(rotation.as_matrix()), - ) - - -@hypothesis.given(_strategy()) -def test_rotation_matrix_identity(data): - parameters, expected = data - - torch.testing.assert_close( - beignet.ops.rotation_matrix_identity(**parameters), - expected, - ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__rotation_matrix_magnitude.py b/tests/beignet/ops/_geometry/_transformations/test__rotation_matrix_magnitude.py deleted file mode 100644 index 85fb6d94d9..0000000000 --- a/tests/beignet/ops/_geometry/_transformations/test__rotation_matrix_magnitude.py +++ /dev/null @@ -1,33 +0,0 @@ -import beignet.ops -import hypothesis.strategies -import torch.testing -from scipy.spatial.transform import Rotation - - -@hypothesis.strategies.composite -def _strategy(function): - rotations = Rotation.random( - function( - hypothesis.strategies.integers( - min_value=1, - max_value=8, - ), - ), - ) - - return ( - { - "input": torch.from_numpy(rotations.as_matrix()), - }, - torch.from_numpy(rotations.magnitude()), - ) - - -@hypothesis.given(_strategy()) -def test_rotation_matrix_magnitude(data): - parameters, expected = data - - torch.testing.assert_close( - beignet.ops.rotation_matrix_magnitude(**parameters), - expected, - ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__rotation_matrix_mean.py b/tests/beignet/ops/_geometry/_transformations/test__rotation_matrix_mean.py deleted file mode 100644 index 22af4a1bbf..0000000000 --- a/tests/beignet/ops/_geometry/_transformations/test__rotation_matrix_mean.py +++ /dev/null @@ -1,33 +0,0 @@ -import beignet.ops -import hypothesis.strategies -import torch.testing -from scipy.spatial.transform import Rotation - - -@hypothesis.strategies.composite -def _strategy(function): - size = function( - hypothesis.strategies.integers( - min_value=16, - max_value=32, - ), - ) - - input = Rotation.random(size) - - return ( - { - "input": torch.from_numpy(input.as_matrix()), - }, - torch.unsqueeze(torch.from_numpy(input.mean().as_matrix()), dim=0), - ) - - -@hypothesis.given(_strategy()) -def test_rotation_matrix_mean(data): - parameters, expected = data - - torch.testing.assert_close( - beignet.ops.rotation_matrix_mean(**parameters), - expected, - ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__rotation_matrix_to_euler_angle.py b/tests/beignet/ops/_geometry/_transformations/test__rotation_matrix_to_euler_angle.py deleted file mode 100644 index b143e9aa4f..0000000000 --- a/tests/beignet/ops/_geometry/_transformations/test__rotation_matrix_to_euler_angle.py +++ /dev/null @@ -1,65 +0,0 @@ -import beignet.ops -import hypothesis.strategies -import torch -from scipy.spatial.transform import Rotation - - -@hypothesis.strategies.composite -def _strategy(function): - rotation = Rotation.random( - function( - hypothesis.strategies.integers( - min_value=16, - max_value=32, - ), - ), - ) - - axes = function( - hypothesis.strategies.sampled_from( - [ - "xyz", - "xzy", - "yxz", - "yzx", - "zxy", - "zyx", - "XYZ", - "XZY", - "YXZ", - "YZX", - "ZXY", - "ZYX", - ] - ), - ) - - degrees = function(hypothesis.strategies.booleans()) - - return ( - { - "input": torch.from_numpy( - rotation.as_matrix(), - ), - "axes": axes, - "degrees": degrees, - }, - torch.from_numpy( - rotation.as_euler( - axes, - degrees, - ), - ), - ) - - -@hypothesis.given(_strategy()) -def test_rotation_matrix_to_euler_angle(data): - parameters, expected = data - - torch.testing.assert_close( - beignet.ops.rotation_matrix_to_euler_angle( - **parameters, - ), - expected, - ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__rotation_matrix_to_quaternion.py b/tests/beignet/ops/_geometry/_transformations/test__rotation_matrix_to_quaternion.py deleted file mode 100644 index fde6a951ff..0000000000 --- a/tests/beignet/ops/_geometry/_transformations/test__rotation_matrix_to_quaternion.py +++ /dev/null @@ -1,49 +0,0 @@ -import beignet.ops -import hypothesis.extra.numpy -import hypothesis.strategies -import torch -from scipy.spatial.transform import Rotation - - -@hypothesis.strategies.composite -def _strategy(function): - rotation = Rotation.random( - function( - hypothesis.strategies.integers( - min_value=16, - max_value=32, - ), - ), - ) - - canonical = function(hypothesis.strategies.booleans()) - - return ( - { - "input": torch.from_numpy( - rotation.as_matrix(), - ), - "canonical": canonical, - }, - torch.abs( - torch.from_numpy( - rotation.as_quat( - canonical, - ), - ), - ), - ) - - -@hypothesis.given(_strategy()) -def test_rotation_matrix_to_quaternion(data): - parameters, expected = data - - torch.testing.assert_close( - torch.abs( - beignet.ops.rotation_matrix_to_quaternion( - **parameters, - ), - ), - expected, - ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__rotation_matrix_to_rotation_vector.py b/tests/beignet/ops/_geometry/_transformations/test__rotation_matrix_to_rotation_vector.py deleted file mode 100644 index 491690a13a..0000000000 --- a/tests/beignet/ops/_geometry/_transformations/test__rotation_matrix_to_rotation_vector.py +++ /dev/null @@ -1,45 +0,0 @@ -import beignet.ops -import hypothesis.extra.numpy -import hypothesis.strategies -import torch -from scipy.spatial.transform import Rotation - - -@hypothesis.strategies.composite -def _strategy(function): - rotation = Rotation.random( - function( - hypothesis.strategies.integers( - min_value=16, - max_value=32, - ), - ), - ) - - degrees = function(hypothesis.strategies.booleans()) - - return ( - { - "input": torch.from_numpy( - rotation.as_matrix(), - ), - "degrees": degrees, - }, - torch.from_numpy( - rotation.as_rotvec( - degrees, - ), - ), - ) - - -@hypothesis.given(_strategy()) -def test_rotation_matrix_to_rotation_vector(data): - parameters, expected = data - - torch.testing.assert_close( - beignet.ops.rotation_matrix_to_rotation_vector( - **parameters, - ), - expected, - ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__rotation_vector_identity.py b/tests/beignet/ops/_geometry/_transformations/test__rotation_vector_identity.py deleted file mode 100644 index d84b97d9fa..0000000000 --- a/tests/beignet/ops/_geometry/_transformations/test__rotation_vector_identity.py +++ /dev/null @@ -1,36 +0,0 @@ -import beignet.ops -import hypothesis.strategies -import torch -from scipy.spatial.transform import Rotation - - -@hypothesis.strategies.composite -def _strategy(function): - size = function( - hypothesis.strategies.integers( - min_value=1, - max_value=8, - ), - ) - - rotation = Rotation.identity(size) - - degrees = function(hypothesis.strategies.booleans()) - - return ( - { - "size": size, - "dtype": torch.float64, - }, - torch.from_numpy(rotation.as_rotvec(degrees)), - ) - - -@hypothesis.given(_strategy()) -def test_rotation_vector_identity(data): - parameters, expected = data - - torch.testing.assert_close( - beignet.ops.rotation_vector_identity(**parameters), - expected, - ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__rotation_vector_magnitude.py b/tests/beignet/ops/_geometry/_transformations/test__rotation_vector_magnitude.py deleted file mode 100644 index a065bbed5f..0000000000 --- a/tests/beignet/ops/_geometry/_transformations/test__rotation_vector_magnitude.py +++ /dev/null @@ -1,36 +0,0 @@ -import beignet.ops -import hypothesis.strategies -import torch.testing -from scipy.spatial.transform import Rotation - - -@hypothesis.strategies.composite -def _strategy(function): - degrees = function(hypothesis.strategies.booleans()) - - rotations = Rotation.random( - function( - hypothesis.strategies.integers( - min_value=1, - max_value=8, - ), - ), - ) - - return ( - { - "input": torch.from_numpy(rotations.as_rotvec(degrees)), - "degrees": degrees, - }, - torch.from_numpy(rotations.magnitude()), - ) - - -@hypothesis.given(_strategy()) -def test_rotation_vector_magnitude(data): - parameters, expected = data - - torch.testing.assert_close( - beignet.ops.rotation_vector_magnitude(**parameters), - expected, - ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__rotation_vector_mean.py b/tests/beignet/ops/_geometry/_transformations/test__rotation_vector_mean.py deleted file mode 100644 index 6ae68d159f..0000000000 --- a/tests/beignet/ops/_geometry/_transformations/test__rotation_vector_mean.py +++ /dev/null @@ -1,39 +0,0 @@ -import beignet.ops -import hypothesis.strategies -import torch.testing -from scipy.spatial.transform import Rotation - - -@hypothesis.strategies.composite -def _strategy(function): - size = function( - hypothesis.strategies.integers( - min_value=16, - max_value=32, - ), - ) - - input = Rotation.random(size) - - degrees = function(hypothesis.strategies.booleans()) - - return ( - { - "input": torch.from_numpy(input.as_rotvec(degrees)), - "degrees": degrees, - }, - torch.unsqueeze( - torch.from_numpy(input.mean().as_rotvec(degrees)), - dim=0, - ), - ) - - -@hypothesis.given(_strategy()) -def test_rotation_vector_mean(data): - parameters, expected = data - - torch.testing.assert_close( - beignet.ops.rotation_vector_mean(**parameters), - expected, - ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__rotation_vector_to_euler_angle.py b/tests/beignet/ops/_geometry/_transformations/test__rotation_vector_to_euler_angle.py deleted file mode 100644 index f49ab3ed1b..0000000000 --- a/tests/beignet/ops/_geometry/_transformations/test__rotation_vector_to_euler_angle.py +++ /dev/null @@ -1,67 +0,0 @@ -import beignet.ops -import hypothesis.strategies -import torch -from scipy.spatial.transform import Rotation - - -@hypothesis.strategies.composite -def _strategy(function): - rotation = Rotation.random( - function( - hypothesis.strategies.integers( - min_value=16, - max_value=32, - ), - ), - ) - - axes = function( - hypothesis.strategies.sampled_from( - [ - "xyz", - "xzy", - "yxz", - "yzx", - "zxy", - "zyx", - "XYZ", - "XZY", - "YXZ", - "YZX", - "ZXY", - "ZYX", - ] - ), - ) - - degrees = function(hypothesis.strategies.booleans()) - - return ( - { - "input": torch.from_numpy( - rotation.as_rotvec( - degrees, - ), - ), - "axes": axes, - "degrees": degrees, - }, - torch.from_numpy( - rotation.as_euler( - axes, - degrees, - ), - ), - ) - - -@hypothesis.given(_strategy()) -def test_rotation_vector_to_euler_angle(data): - parameters, expected = data - - torch.testing.assert_close( - beignet.ops.rotation_vector_to_euler_angle( - **parameters, - ), - expected, - ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__rotation_vector_to_quaternion.py b/tests/beignet/ops/_geometry/_transformations/test__rotation_vector_to_quaternion.py deleted file mode 100644 index 9017271dbc..0000000000 --- a/tests/beignet/ops/_geometry/_transformations/test__rotation_vector_to_quaternion.py +++ /dev/null @@ -1,54 +0,0 @@ -import beignet.ops -import hypothesis.extra.numpy -import hypothesis.strategies -import torch -from scipy.spatial.transform import Rotation - - -@hypothesis.strategies.composite -def _strategy(function): - rotation = Rotation.random( - function( - hypothesis.strategies.integers( - min_value=16, - max_value=32, - ), - ), - ) - - degrees = function(hypothesis.strategies.booleans()) - - canonical = function(hypothesis.strategies.booleans()) - - return ( - { - "input": torch.from_numpy( - rotation.as_rotvec( - degrees, - ), - ), - "degrees": degrees, - "canonical": canonical, - }, - torch.abs( - torch.from_numpy( - rotation.as_quat( - canonical, - ), - ), - ), - ) - - -@hypothesis.given(_strategy()) -def test_rotation_vector_to_quaternion(data): - parameters, expected = data - - torch.testing.assert_close( - torch.abs( - beignet.ops.rotation_vector_to_quaternion( - **parameters, - ), - ), - expected, - ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__rotation_vector_to_rotation_matrix.py b/tests/beignet/ops/_geometry/_transformations/test__rotation_vector_to_rotation_matrix.py deleted file mode 100644 index 0c8e699e2a..0000000000 --- a/tests/beignet/ops/_geometry/_transformations/test__rotation_vector_to_rotation_matrix.py +++ /dev/null @@ -1,42 +0,0 @@ -import beignet.ops -import hypothesis.strategies -import torch -from scipy.spatial.transform import Rotation - - -@hypothesis.strategies.composite -def _strategy(function): - rotation = Rotation.random( - function( - hypothesis.strategies.integers( - min_value=16, - max_value=32, - ), - ), - ) - - degrees = function(hypothesis.strategies.booleans()) - - return ( - { - "input": torch.from_numpy( - rotation.as_rotvec(degrees), - ), - "degrees": degrees, - }, - torch.from_numpy( - rotation.as_matrix(), - ), - ) - - -@hypothesis.given(_strategy()) -def test_rotation_vector_to_rotation_matrix(data): - parameters, expected = data - - torch.testing.assert_close( - beignet.ops.rotation_vector_to_rotation_matrix( - **parameters, - ), - expected, - ) diff --git a/tests/beignet/ops/_geometry/_transformations/test__slerp.py b/tests/beignet/ops/_geometry/_transformations/test__slerp.py deleted file mode 100644 index 5b09726995..0000000000 --- a/tests/beignet/ops/_geometry/_transformations/test__slerp.py +++ /dev/null @@ -1,151 +0,0 @@ -import beignet.ops -import hypothesis.strategies -import numpy -import torch -from scipy.spatial.transform import Rotation, Slerp - - -def test_slerp(): - # t = 0 - torch.testing.assert_close( - beignet.ops.quaternion_slerp( - torch.tensor([+0.00000]), - torch.tensor([+0.00000, +1.00000]), - torch.tensor( - [ - [+1.00000, +0.00000, +0.00000, +0.00000], - [+0.00000, +1.00000, +0.00000, +0.00000], - ] - ), - ), - torch.tensor([[+1.00000, +0.00000, +0.00000, +0.00000]]), - ) - - # t = 1 - torch.testing.assert_close( - beignet.ops.quaternion_slerp( - torch.tensor([+1.00000]), - torch.tensor([+0.00000, +1.00000]), - torch.tensor( - [ - [+1.00000, +0.00000, +0.00000, +0.00000], - [+0.00000, +1.00000, +0.00000, +0.00000], - ] - ), - ), - torch.tensor([[+0.00000, +1.00000, +0.00000, +0.00000]]), - ) - - # SMALL (ACUTE) ANGLE BETWEEN QUATERNIONS - torch.testing.assert_close( - beignet.ops.quaternion_slerp( - torch.tensor([+0.50000]), - torch.tensor([+0.00000, +1.00000]), - torch.tensor( - [ - [+1.00000, +0.00000, +0.00000, +0.00000], - [+0.70710, +0.70710, +0.00000, +0.00000], - ], - ), - ), - torch.reshape( - torch.tensor([+0.92388, +0.38268, +0.00000, +0.00000]), - [1, -1], - ), - ) - - # LARGE (OBTUSE) ANGLE BETWEEN QUATERNIONS - torch.testing.assert_close( - beignet.ops.quaternion_slerp( - torch.tensor([+0.50000]), - torch.tensor([+0.00000, +1.00000]), - torch.tensor( - [ - [+1.00000, +0.00000, +0.00000, +0.00000], - [-1.00000, +0.00000, +0.00000, +0.00000], - ] - ), - ), - torch.reshape( - torch.tensor([+1.00000, +0.00000, +0.00000, +0.00000]), - [1, -1], - ), - ) - - -@hypothesis.strategies.composite -def slerp_parameters(f): - n = f( - hypothesis.strategies.integers( - min_value=2, - max_value=8, - ), - ) - - times = numpy.sort( - f( - hypothesis.strategies.lists( - hypothesis.strategies.floats( - allow_infinity=False, - allow_nan=False, - ), - min_size=n, - max_size=n, - unique=True, - ), - ), - ) - - min_value = numpy.min(times) - max_value = numpy.max(times) - - input = numpy.sort( - f( - hypothesis.strategies.lists( - hypothesis.strategies.floats( - min_value=min_value, - max_value=max_value, - ), - min_size=1, - max_size=8, - unique=True, - ), - ), - ) - - rotations = f( - hypothesis.strategies.lists( - hypothesis.strategies.lists( - hypothesis.strategies.floats( - numpy.finfo(numpy.float32).eps, - 1.0, - ), - min_size=4, - max_size=4, - ), - min_size=n, - max_size=n, - ), - ) - - rotations = Rotation.from_quat(rotations) - - return [ - [ - torch.from_numpy(input), - torch.from_numpy(times), - torch.from_numpy(rotations.as_quat(canonical=True)), - ], - torch.from_numpy( - Slerp(times, rotations)(input).as_quat(canonical=True), - ), - ] - - -@hypothesis.given(slerp_parameters()) -def test_slerp_properties(data): - parameters, expected_rotations = data - - torch.testing.assert_close( - beignet.ops.quaternion_slerp(*parameters), expected_rotations - ) From 4ef55de5f62f697b912a7c878ee4a66c13282412 Mon Sep 17 00:00:00 2001 From: Allen Goodman Date: Mon, 13 May 2024 11:26:13 -0400 Subject: [PATCH 03/14] cleanup --- docs/beignet.ops.md | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100644 docs/beignet.ops.md diff --git a/docs/beignet.ops.md b/docs/beignet.ops.md deleted file mode 100644 index f660c46747..0000000000 --- a/docs/beignet.ops.md +++ /dev/null @@ -1,11 +0,0 @@ -# beignet.ops - -## Geometry - -### Transformations - -#### Rotations - -#### Translations - -## Interpolation From 1f1d2832649717d59c6448156ce4e9b3200deea1 Mon Sep 17 00:00:00 2001 From: Allen Goodman Date: Mon, 13 May 2024 11:29:54 -0400 Subject: [PATCH 04/14] cleanup --- pyproject.toml | 2 +- src/beignet/__init__.py | 6 +++++- src/beignet/{operators => }/_needleman_wunsch.py | 0 src/beignet/{operators => }/_smith_waterman.py | 0 src/beignet/operators/__init__.py | 7 ------- tests/beignet/{operators => }/test__needleman_wunsch.py | 0 tests/beignet/{operators => }/test__smith_waterman.py | 0 7 files changed, 6 insertions(+), 9 deletions(-) rename src/beignet/{operators => }/_needleman_wunsch.py (100%) rename src/beignet/{operators => }/_smith_waterman.py (100%) delete mode 100644 src/beignet/operators/__init__.py rename tests/beignet/{operators => }/test__needleman_wunsch.py (100%) rename tests/beignet/{operators => }/test__smith_waterman.py (100%) diff --git a/pyproject.toml b/pyproject.toml index b14277f13d..65bcc2339d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -31,7 +31,7 @@ exclude = [ "./src/beignet/constants/_substitution_matrices.py", ] -[tool.ruff] +[tool.ruff.lint] select = [ "B", # FLAKE8-BUGBEAR "E", # PYCODESTYLE ERRORS diff --git a/src/beignet/__init__.py b/src/beignet/__init__.py index f91d4adc64..76a8dfc20f 100644 --- a/src/beignet/__init__.py +++ b/src/beignet/__init__.py @@ -28,6 +28,7 @@ from ._invert_quaternion import invert_quaternion from ._invert_rotation_matrix import invert_rotation_matrix from ._invert_rotation_vector import invert_rotation_vector +from ._needleman_wunsch import needleman_wunsch from ._quaternion_identity import quaternion_identity from ._quaternion_magnitude import quaternion_magnitude from ._quaternion_mean import quaternion_mean @@ -65,6 +66,7 @@ from ._rotation_vector_to_rotation_matrix import ( rotation_vector_to_rotation_matrix, ) +from ._smith_waterman import smith_waterman from ._translation_identity import translation_identity __all__ = [ @@ -86,9 +88,11 @@ "invert_quaternion", "invert_rotation_matrix", "invert_rotation_vector", + "needleman_wunsch", "quaternion_identity", "quaternion_magnitude", "quaternion_mean", + "quaternion_slerp", "quaternion_to_euler_angle", "quaternion_to_rotation_matrix", "quaternion_to_rotation_vector", @@ -108,6 +112,6 @@ "rotation_vector_to_euler_angle", "rotation_vector_to_quaternion", "rotation_vector_to_rotation_matrix", - "quaternion_slerp", + "smith_waterman", "translation_identity", ] diff --git a/src/beignet/operators/_needleman_wunsch.py b/src/beignet/_needleman_wunsch.py similarity index 100% rename from src/beignet/operators/_needleman_wunsch.py rename to src/beignet/_needleman_wunsch.py diff --git a/src/beignet/operators/_smith_waterman.py b/src/beignet/_smith_waterman.py similarity index 100% rename from src/beignet/operators/_smith_waterman.py rename to src/beignet/_smith_waterman.py diff --git a/src/beignet/operators/__init__.py b/src/beignet/operators/__init__.py deleted file mode 100644 index e281919d3c..0000000000 --- a/src/beignet/operators/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -from ._needleman_wunsch import needleman_wunsch -from ._smith_waterman import smith_waterman - -__all__ = [ - "needleman_wunsch", - "smith_waterman", -] diff --git a/tests/beignet/operators/test__needleman_wunsch.py b/tests/beignet/test__needleman_wunsch.py similarity index 100% rename from tests/beignet/operators/test__needleman_wunsch.py rename to tests/beignet/test__needleman_wunsch.py diff --git a/tests/beignet/operators/test__smith_waterman.py b/tests/beignet/test__smith_waterman.py similarity index 100% rename from tests/beignet/operators/test__smith_waterman.py rename to tests/beignet/test__smith_waterman.py From 5c8ef4b9b9d73a6c75a0107f09a6056f305872a1 Mon Sep 17 00:00:00 2001 From: Allen Goodman Date: Mon, 13 May 2024 11:31:47 -0400 Subject: [PATCH 05/14] docs --- docs/index.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/index.md b/docs/index.md index 53f1199f37..6d6ad0a8c4 100644 --- a/docs/index.md +++ b/docs/index.md @@ -18,6 +18,7 @@ ::: beignet.invert_quaternion ::: beignet.invert_rotation_matrix ::: beignet.invert_rotation_vector +::: beignet.needleman_wunsch ::: beignet.quaternion_identity ::: beignet.quaternion_magnitude ::: beignet.quaternion_mean @@ -41,4 +42,5 @@ ::: beignet.rotation_vector_to_euler_angle ::: beignet.rotation_vector_to_quaternion ::: beignet.rotation_vector_to_rotation_matrix +::: beignet.smith_waterman ::: beignet.translation_identity From aac59888972f471a48427b0541368ba6df84a6bc Mon Sep 17 00:00:00 2001 From: Allen Goodman Date: Mon, 13 May 2024 11:33:20 -0400 Subject: [PATCH 06/14] cleanup --- src/beignet/datasets/__init__.py | 1 + src/beignet/datasets/_msa_dataset.py | 24 +++++++++++++++--------- 2 files changed, 16 insertions(+), 9 deletions(-) create mode 100644 src/beignet/datasets/__init__.py diff --git a/src/beignet/datasets/__init__.py b/src/beignet/datasets/__init__.py new file mode 100644 index 0000000000..b3cb555401 --- /dev/null +++ b/src/beignet/datasets/__init__.py @@ -0,0 +1 @@ +from ._msa_dataset import MSADataset diff --git a/src/beignet/datasets/_msa_dataset.py b/src/beignet/datasets/_msa_dataset.py index f367f0c6fa..f5481cac47 100644 --- a/src/beignet/datasets/_msa_dataset.py +++ b/src/beignet/datasets/_msa_dataset.py @@ -1,12 +1,16 @@ from pathlib import Path from typing import Callable -from torch import Tensor -from torch.utils.data import Dataset - import numpy import pooch import torch +from torch import Tensor +from torch.utils.data import Dataset + + +def make_similarity_matrices(*args): + return + class MSADataset(Dataset): def __init__( @@ -24,7 +28,7 @@ def __init__( if download: pooch.retrieve( - f"https://files.ipd.uw.edu/krypton/data_unalign.npz", + "https://files.ipd.uw.edu/krypton/data_unalign.npz", fname=f"{name}.npz", known_hash="9cc22e381619b66fc353c079221fd02450705d4e3ee23e4e23a052b6e70a95ec", path=root / name, @@ -41,7 +45,7 @@ def __init__( for subset in self.all_data.files: data = self.all_data[subset].tolist() - # pad sequences + # pad sequences sequences = torch.nested.to_padded_tensor( torch.nested.nested_tensor(data["ms"]), 0.0, @@ -59,7 +63,7 @@ def __init__( sizes = torch.tensor([len(seq) for seq in sequences]) all_sizes.append(sizes) - # pad alignments + # pad alignments alignments = torch.nested.to_padded_tensor( torch.nested.nested_tensor(data["aln"]), 0.0, @@ -72,10 +76,12 @@ def __init__( ], )[alignments] - _, alignments = alignments[0], alignments[1:] # ignore first alignment + _, alignments = alignments[0], alignments[1:] # ignore first alignment all_alignments.append(alignments) - matrices = make_similarity_matrices(sequences, reference_sequence) # TODO (Edith): make matrices + matrices = make_similarity_matrices( + sequences, reference_sequence + ) # TODO (Edith): make matrices all_matrices.append(matrices) self.sequences = torch.stack(all_sequences, dim=1) @@ -101,4 +107,4 @@ def __getitem__(self, index: int) -> tuple[Tensor, Tensor]: if self.target_transform: target = self.target_transform(target) - return inputs, target \ No newline at end of file + return inputs, target From 223e3015eb3a1530feb33d9360f90a6317f29a0c Mon Sep 17 00:00:00 2001 From: Allen Goodman Date: Mon, 13 May 2024 11:35:51 -0400 Subject: [PATCH 07/14] pooch --- pyproject.toml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 65bcc2339d..ec6e4fc301 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,8 +7,13 @@ requires = [ ] [project] -authors = [{ email = "allen.goodman@icloud.com", name = "Allen Goodman" }] -dependencies = ["torch"] +authors = [ + { email = "allen.goodman@icloud.com", name = "Allen Goodman" }, +] +dependencies = [ + "pooch", + "torch", +] dynamic = ["version"] license = { file = "LICENSE" } name = "beignet" From 1020275120390dae8b767104e6f6a0f602ead14e Mon Sep 17 00:00:00 2001 From: Allen Goodman Date: Wed, 22 May 2024 11:07:11 -0400 Subject: [PATCH 08/14] NeedlemanWunschMSA --- src/beignet/lightning/_msa_lightning_module.py | 4 ++-- src/beignet/nn/__init__.py | 2 +- src/beignet/nn/{_msa.py => _needleman_wunsch_msa.py} | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) rename src/beignet/nn/{_msa.py => _needleman_wunsch_msa.py} (92%) diff --git a/src/beignet/lightning/_msa_lightning_module.py b/src/beignet/lightning/_msa_lightning_module.py index 20c64760b8..73e8602867 100644 --- a/src/beignet/lightning/_msa_lightning_module.py +++ b/src/beignet/lightning/_msa_lightning_module.py @@ -1,6 +1,6 @@ from lightning import LightningModule -from beignet.nn import MSA +from beignet.nn import NeedlemanWunschMSA class MSALightningModule(LightningModule): @@ -15,7 +15,7 @@ def __init__( ): super().__init__() - self.module = MSA( + self.module = NeedlemanWunschMSA( in_channels, out_channels, kernel_size, diff --git a/src/beignet/nn/__init__.py b/src/beignet/nn/__init__.py index d56ceb7aee..8c96a3bd73 100644 --- a/src/beignet/nn/__init__.py +++ b/src/beignet/nn/__init__.py @@ -1 +1 @@ -from ._msa import MSA +from ._needleman_wunsch_msa import NeedlemanWunschMSA diff --git a/src/beignet/nn/_msa.py b/src/beignet/nn/_needleman_wunsch_msa.py similarity index 92% rename from src/beignet/nn/_msa.py rename to src/beignet/nn/_needleman_wunsch_msa.py index 92d6b7eeac..39f4526ff8 100644 --- a/src/beignet/nn/_msa.py +++ b/src/beignet/nn/_needleman_wunsch_msa.py @@ -2,10 +2,10 @@ from torch import Tensor from torch.nn import Conv1d, Module -import beignet.operators +import beignet -class MSA(Module): +class NeedlemanWunschMSA(Module): def __init__( self, in_channels: int, @@ -35,7 +35,7 @@ def forward(self, inputs: (Tensor, Tensor)) -> Tensor: embedding = embedding @ embedding[0].T - output = beignet.operators.needleman_wunsch( + output = beignet.needleman_wunsch( embedding, shapes, gap_penalty=self.gap_penalty, From 7d062f36ef704a8bb0944e97b23511473db163cf Mon Sep 17 00:00:00 2001 From: Allen Goodman Date: Wed, 22 May 2024 11:08:25 -0400 Subject: [PATCH 09/14] SmithWatermanMSA --- src/beignet/nn/__init__.py | 1 + src/beignet/nn/_smith_waterman_msa.py | 56 +++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 src/beignet/nn/_smith_waterman_msa.py diff --git a/src/beignet/nn/__init__.py b/src/beignet/nn/__init__.py index 8c96a3bd73..2e96d98fb5 100644 --- a/src/beignet/nn/__init__.py +++ b/src/beignet/nn/__init__.py @@ -1 +1,2 @@ from ._needleman_wunsch_msa import NeedlemanWunschMSA +from ._smith_waterman_msa import SmithWatermanMSA diff --git a/src/beignet/nn/_smith_waterman_msa.py b/src/beignet/nn/_smith_waterman_msa.py new file mode 100644 index 0000000000..b1262b4d29 --- /dev/null +++ b/src/beignet/nn/_smith_waterman_msa.py @@ -0,0 +1,56 @@ +import torch +from torch import Tensor +from torch.nn import Conv1d, Module + +import beignet + + +class SmithWatermanMSA(Module): + def __init__( + self, + in_channels: int, + out_channels: int = 512, + kernel_size: int = 18, + *, + gap_penalty: float = 0.0, + temperature: float = 1.0, + ): + super().__init__() + + self.gap_penalty = gap_penalty + + self.temperature = temperature + + self.embedding = Conv1d( + in_channels, + out_channels, + kernel_size, + padding="same", + ) + + def forward(self, inputs: (Tensor, Tensor)) -> Tensor: + matrices, shapes = inputs + + embedding = self.embedding(matrices) + + embedding = embedding @ embedding[0].T + + output = beignet.smith_waterman( + embedding, + shapes, + gap_penalty=self.gap_penalty, + temperature=self.temperature, + ) + + return torch.einsum( + "ja, nij -> nia", + torch.mean( + torch.einsum( + "nia, nij -> nja", + matrices, + output, + ), + dim=0, + ), + output, + ) From 6e0887c325ad5c0aebe3ba2d87b816b2bb69e7d0 Mon Sep 17 00:00:00 2001 From: Edith Lee Date: Fri, 31 May 2024 12:16:35 -0700 Subject: [PATCH 10/14] rename to smurf dataset, add better for-loop for reading in all in memory --- src/beignet/datasets/__init__.py | 2 +- src/beignet/datasets/_msa_dataset.py | 110 ----- src/beignet/datasets/_smurf_dataset.py | 107 +++++ .../datasets/_smurf_dataset_constants.py | 392 ++++++++++++++++++ 4 files changed, 500 insertions(+), 111 deletions(-) delete mode 100644 src/beignet/datasets/_msa_dataset.py create mode 100644 src/beignet/datasets/_smurf_dataset.py create mode 100644 src/beignet/datasets/_smurf_dataset_constants.py diff --git a/src/beignet/datasets/__init__.py b/src/beignet/datasets/__init__.py index b3cb555401..64765ebe84 100644 --- a/src/beignet/datasets/__init__.py +++ b/src/beignet/datasets/__init__.py @@ -1 +1 @@ -from ._msa_dataset import MSADataset +from ._smurf_dataset import SMURFDataset diff --git a/src/beignet/datasets/_msa_dataset.py b/src/beignet/datasets/_msa_dataset.py deleted file mode 100644 index f5481cac47..0000000000 --- a/src/beignet/datasets/_msa_dataset.py +++ /dev/null @@ -1,110 +0,0 @@ -from pathlib import Path -from typing import Callable - -import numpy -import pooch -import torch -from torch import Tensor -from torch.utils.data import Dataset - - -def make_similarity_matrices(*args): - return - - -class MSADataset(Dataset): - def __init__( - self, - root: str | Path, - *, - download: bool = False, - transform: Callable | None = None, - target_transform: Callable | None = None, - ): - if isinstance(root, str): - root = Path(root) - - name = self.__class__.__name__ - - if download: - pooch.retrieve( - "https://files.ipd.uw.edu/krypton/data_unalign.npz", - fname=f"{name}.npz", - known_hash="9cc22e381619b66fc353c079221fd02450705d4e3ee23e4e23a052b6e70a95ec", - path=root / name, - ) - - self.all_data = numpy.load(root / name / f"{name}.npz", allow_pickle=True) - - all_sequences = [] - all_alignments = [] - all_sizes = [] - all_matrices = [] - - # process each subset - for subset in self.all_data.files: - data = self.all_data[subset].tolist() - - # pad sequences - sequences = torch.nested.to_padded_tensor( - torch.nested.nested_tensor(data["ms"]), - 0.0, - ) - sequences = torch.concatenate( - [ - torch.eye(torch.max(sequences) + 1), - torch.zeros([1, torch.max(sequences) + 1]), - ], - )[sequences] - - reference_sequence, sequences = sequences[0].unsqueeze(0), sequences[1:] - all_sequences.append(sequences) - - sizes = torch.tensor([len(seq) for seq in sequences]) - all_sizes.append(sizes) - - # pad alignments - alignments = torch.nested.to_padded_tensor( - torch.nested.nested_tensor(data["aln"]), - 0.0, - ) - - alignments = torch.concatenate( - [ - torch.eye(torch.max(alignments) + 1), - torch.zeros([1, torch.max(alignments) + 1]), - ], - )[alignments] - - _, alignments = alignments[0], alignments[1:] # ignore first alignment - all_alignments.append(alignments) - - matrices = make_similarity_matrices( - sequences, reference_sequence - ) # TODO (Edith): make matrices - all_matrices.append(matrices) - - self.sequences = torch.stack(all_sequences, dim=1) - self.alignments = torch.stack(all_alignments, dim=1) - self.sizes = torch.stack(all_sizes, dim=1) - self.matrices = torch.stack(all_matrices, dim=1) - - self.transform = transform - - self.target_transform = target_transform - - def __len__(self): - return self.sequences.size(0) - - def __getitem__(self, index: int) -> tuple[Tensor, Tensor]: - inputs = self.matrices[index], self.sizes[index] - - if self.transform: - inputs = self.transform(*inputs) - - target = self.alignments[index] - - if self.target_transform: - target = self.target_transform(target) - - return inputs, target diff --git a/src/beignet/datasets/_smurf_dataset.py b/src/beignet/datasets/_smurf_dataset.py new file mode 100644 index 0000000000..2ace5329be --- /dev/null +++ b/src/beignet/datasets/_smurf_dataset.py @@ -0,0 +1,107 @@ +from pathlib import Path +from typing import Callable + +import numpy +import pooch +import torch +from torch import Tensor +from torch.utils.data import Dataset + +from ._smurf_dataset_constants import FAMILIES_TEST, FAMILIES_TRAIN, NUM_SEQUENCES_TEST, NUM_SEQUENCES_TRAIN + +class SMURFDataset(Dataset): + def __init__( + self, + root: str | Path, + *, + download: bool = False, + train: bool = True, + transform: Callable | None = None, + target_transform: Callable | None = None, + ): + if isinstance(root, str): + root = Path(root) + + name = self.__class__.__name__ + + if download: + pooch.retrieve( + "https://files.ipd.uw.edu/krypton/data_unalign.npz", + fname=f"{name}.npz", + known_hash="9cc22e381619b66fc353c079221fd02450705d4e3ee23e4e23a052b6e70a95ec", + path=root / name, + ) + + self.all_data = numpy.load(root / name / f"{name}.npz", + allow_pickle=True, mmap_mode="r" + ) + + if train: + families = FAMILIES_TRAIN + num_sequences = NUM_SEQUENCES_TRAIN + else: + families = FAMILIES_TEST + num_sequences = NUM_SEQUENCES_TEST + + self.all_sequences = torch.zeros([num_sequences, 583]) + self.all_references = torch.zeros([num_sequences, 583]) + self.all_alignments = torch.zeros([num_sequences, 583]) + self.all_sizes = torch.zeros([num_sequences, 1]) + + idx = 0 + + for family in families: + data = self.all_data[family].tolist() + + # sequences + sequences = torch.nested.to_padded_tensor( + torch.nested.nested_tensor(data["ms"]), + 0.0 + ) + reference_sequence, sequences = sequences[0], sequences[1:] + + chunk = torch.zeros([sequences.shape[0], 583]) + chunk[:, :sequences.shape[1]] = sequences + self.all_sequences[idx:idx+sequences.shape[0], :] = chunk + + chunk = torch.zeros([sequences.shape[0], 583]) + chunk[:, :sequences.shape[1]] = reference_sequence.repeat( + (sequences.shape[0], 1) + ) + self.all_references[idx:idx+sequences.shape[0], :] = chunk + + # alignments + alignments = torch.nested.to_padded_tensor( + torch.nested.nested_tensor(data["aln"]), + 0.0 + ) + _, alignments = alignments[0], alignments[1:] # discard the first alignment + + chunk = torch.zeros([alignments.shape[0], 583]) + chunk[:, :sequences.shape[1]] = alignments + self.all_alignments[idx:idx+sequences.shape[0], :] = chunk + + # sizes + self.all_sizes[idx:idx+sequences.shape[0], :] = torch.tensor([len(seq) for seq in sequences]).unsqueeze(1) # noqa: E501 + + idx += sequences.shape[0] + + self.transform = transform + + self.target_transform = target_transform + + def __len__(self): + return self.all_sequences.size(0) + + def __getitem__(self, index: int) -> tuple[Tensor, Tensor]: + inputs = self.all_sequences[index], self.all_references[index], self.all_sizes[index] # noqa: E501 + + if self.transform: + inputs = self.transform(*inputs) + + target = self.all_alignments[index] + + if self.target_transform: + target = self.target_transform(target) + + return inputs, target diff --git a/src/beignet/datasets/_smurf_dataset_constants.py b/src/beignet/datasets/_smurf_dataset_constants.py new file mode 100644 index 0000000000..914974a702 --- /dev/null +++ b/src/beignet/datasets/_smurf_dataset_constants.py @@ -0,0 +1,392 @@ +FAMILIES_TEST = [ + '3F6GA', + '1F86A', + '3F9XA', + '2P3WA', + '3FDXA', + '5FH7A', + '2FIUA', + '1FM0D', + '1FM0E', + '3KZPA', + '3FPNB', + '4FVGA', + '1FXLA', + '4G0XA', + '3G13A', + '1G2RA', + '3G2EA', + '3NO0A', + '4G4KA', + '1G6XA', + '3G9KF', + '1GCIA', + '3U2UA', + '4GJZA', + '2GMYA', + '1GPRA', + '3GPKA', + '1N62C', + '4GWBA', + '3H0NA', + '3LYHA', + '4HYLA', + '3H5JA', + '3H7OA', + '4H8EA', + '1H99A', + '2HA8A', + '2HBAA', + '2HBWA', + '2HC8A', + '4XPCA', + '3HMCA', + '5HMLA', + '3HRLA', + '3HY3A', + '2HZQA', + '2JFRA', + '5I32A', + '2I6HA', + '3IBZA', + '2ICUA', + '1IIBA', + '2IIHA', + '5IJAA', + '3IP0A', + '2NWRA', + '1IQ4A', + '2IQYA', + '3IS6A', + '3ISRA', + '3IT4A', + '3IT4B', + '3ITQA', + '5ITQA', + '3IUGA', + '2IXDA', + '3OCMA', + '2IZ6A', + '3PVEA', + '1JKEA', + '1JL1A', + '2JLIA', + '3JXGA', + '1K4IA', + '4LFLA', + '2OMLA', + '3K8UA', + '1M93B', + '1MPGA', + '3KEWA', + '1KHYA', + '1KNMA', + '2NUHA', + '3L00A', + '3L51A', + '3L60A', + '1LFPA', + '3LF9A', + '1LOPA', + '3LQBA', + '4LQ4A', + '4LWRA', + '1LYQA', + '4M0NA', + '3M7AA', + '4ME3A', + '2MHRA', + '3MHXA', + '3MMHA', + '4MU3A', + '1MVLA', + '3MVUA', + '1X1OA', + '4NBXA', + '3NFDA', + '3NO4A', + '2NRKA', + '2NRRA', + '1NS5A', + '4NTKA', + '3NUAA', + '1NZ0A', + '2O70A', + '2OFKA', + '2OLMA', + '2OMKA', + '4ONMA', + '3PN3A', + '1WDJA', + '2OYAA', + '1OZ9A', + '1TQ5A', + '2PFRA', + '4PGRA', + '2PLIA', + '3PO8A', + '3POJA', + '4PUIA', + '3PYWA', + '3Q46A', + '3Q64A', + '2Q7SA', + '4QDNA', + '2QF4A', + '1QG8A', + '2QIFA', + '2QIPA', + '2VTCA', + '2QQ4A', + '1R5LA', + '1YB0A', + '1RSSA', + '1RV9A', + '4RWUA', + '1S7IA', + '1SEIA', + '1SJ1A', + '1SUMB', + '1TIFA', + '1TIGA', + '1TQGA', + '3UBYA', + '1UCDA', + '4UC1A', + '1UEBA', + '1UI0A', + '1USMA', + '1V6TA', + '2VE8A', + '1VGJA', + '1VMHA', + '2VXNA', + '1VZYA', + '4WK7A', + '1W2WA', + '1W2WB', + '2W6KA', + '4W9ZA', + '4WEEA', + '1WJXA', + '1WNYA', + '2WNPF', + '4WPKA', + '2WQKA', + '1X9UA', + '3WSGA', + '1WUBA', + '1WURA', + '2X8XX', + '4X84A', + '4X9JA', + '2XOVA', + '2XTYA', + '1Y6ZA', + '2Y71A', + '1YARH', + '1YD0A', + '2YN5A', + '1Z0WA', + '4YQDA', + '1ZAVA', + '3ZJAA', + '2ZPTX' +] + +NUM_SEQUENCES_TEST = 719_168 + +FAMILIES_TRAIN = [ + '3A0YA', + '4ACIA', + '3AH7A', + '5A62A', + '2A4VA', + '1A3AA', + '3A35A', + '5A35A', + '3GM5A', + '2A67A', + '3A6SA', + '1NNHA', + '4A7UA', + '4A7WA', + '5ECCA', + '5A89A', + '5C0PA', + '2ABWA', + '2A9SA', + '4JS8A', + '3AABA', + '3AAYA', + '4C5KA', + '4ABLA', + '3ACXA', + '1AE9A', + '4AFFA', + '4AFHA', + '3AGYA', + '1M2KA', + '4AIVA', + '4AIWA', + '1AKOA', + '3AK8A', + '3AKBA', + '3ALUA', + '2AMHA', + '2AN1A', + '2ANRA', + '2ANXA', + '4WTPA', + '2APJA', + '2FBNA', + '4APXB', + '2AQ6A', + '1ATZA', + '4ATEA', + '4AVRA', + '3AWUA', + '4AY0A', + '2B0AA', + '1EUWA', + '4LSCA', + '5B3PA', + '2B5GA', + '2HQSC', + '3B8BA', + '4B8EA', + '2B94A', + '1BD8A', + '3BEDA', + '3BEMA', + '3SY1A', + '2BFWA', + '5C1EA', + '4BH5A', + '2C2IA', + '2BK8A', + '2BKMA', + '2BKXA', + '4LXQA', + '3BM7A', + '2BOUA', + '3BP3A', + '3BPKA', + '5C90A', + '3KG9A', + '3BR8A', + '3BT5A', + '1BUOA', + '2BV5A', + '3BWUD', + '3BWUF', + '1I4JA', + '1BXYA', + '1BYRA', + '3BY8A', + '5BY4A', + '2BZ1A', + '4N0KA', + '3C1QA', + '4C24A', + '3C37A', + '3C4BA', + '2C5QA', + '4C6AA', + '4C6SA', + '2C71A', + '2C8MA', + '2C92A', + '1K7KA', + '5CAJA', + '3CCDA', + '3CCGA', + '5CEGB', + '1WPNA', + '1CFBA', + '1CHDA', + '2GGCA', + '3CH0A', + '3LULA', + '3MN2A', + '4EWFA', + '3NREA', + '3CI3A', + '4NNOA', + '3CNVA', + '2EGZA', + '1COJA', + '1COZA', + '3CQ1A', + '5CQXA', + '1KQPA', + '1CTFA', + '1CUKA', + '2CVEA', + '1CXQA', + '3LF5A', + '3CXKA', + '5CX7A', + '3CZXA', + '1D0QA', + '3D01A', + '3D03A', + '4D05A', + '4D74A', + '4DBFA', + '2D4XA', + '3LTJA', + '4DAMA', + '3DBOB', + '3DD6A', + '1H72C', + '4DE9A', + '1DFUP', + '3DFGA', + '1DJ0A', + '2DQWA', + '3FDJA', + '2DTJA', + '4DT4A', + '4DUNA', + '2DXAA', + '4XTVA', + '2DYIA', + '2DYJA', + '2E0NA', + '2E11A', + '1K7JA', + '4E3YA', + '3UF6A', + '1E58A', + '2E5YA', + '2GUIA', + '2EBJA', + '3EERA', + '4HOIA', + '2EGVA', + '3OHEA', + '3EJKA', + '1EKEA', + '1EKJA', + '4ONWA', + '4EOJB', + '4EQPA', + '3ERBA', + '3ERSX', + '2G2CA', + '4ES1A', + '2EW0A', + '4K08A', + '3F0DA', + '4F01A', + '2F1FA', + '2F23A', + '5F3MA', + '3F42A', + '2F5GA', + '3F5VA', + '4F55A' +] + +NUM_SEQUENCES_TRAIN = 950_762 \ No newline at end of file From 4aaff604866a1e0552174e577c8e9154bfb4d9c9 Mon Sep 17 00:00:00 2001 From: Edith Lee Date: Fri, 31 May 2024 12:18:51 -0700 Subject: [PATCH 11/14] ruff --- src/beignet/datasets/_smurf_dataset.py | 44 +- .../datasets/_smurf_dataset_constants.py | 768 +++++++++--------- 2 files changed, 411 insertions(+), 401 deletions(-) diff --git a/src/beignet/datasets/_smurf_dataset.py b/src/beignet/datasets/_smurf_dataset.py index 2ace5329be..a875b98c02 100644 --- a/src/beignet/datasets/_smurf_dataset.py +++ b/src/beignet/datasets/_smurf_dataset.py @@ -7,7 +7,13 @@ from torch import Tensor from torch.utils.data import Dataset -from ._smurf_dataset_constants import FAMILIES_TEST, FAMILIES_TRAIN, NUM_SEQUENCES_TEST, NUM_SEQUENCES_TRAIN +from ._smurf_dataset_constants import ( + FAMILIES_TEST, + FAMILIES_TRAIN, + NUM_SEQUENCES_TEST, + NUM_SEQUENCES_TRAIN, +) + class SMURFDataset(Dataset): def __init__( @@ -32,9 +38,9 @@ def __init__( path=root / name, ) - self.all_data = numpy.load(root / name / f"{name}.npz", - allow_pickle=True, mmap_mode="r" - ) + self.all_data = numpy.load( + root / name / f"{name}.npz", allow_pickle=True, mmap_mode="r" + ) if train: families = FAMILIES_TRAIN @@ -55,34 +61,34 @@ def __init__( # sequences sequences = torch.nested.to_padded_tensor( - torch.nested.nested_tensor(data["ms"]), - 0.0 + torch.nested.nested_tensor(data["ms"]), 0.0 ) reference_sequence, sequences = sequences[0], sequences[1:] chunk = torch.zeros([sequences.shape[0], 583]) - chunk[:, :sequences.shape[1]] = sequences - self.all_sequences[idx:idx+sequences.shape[0], :] = chunk + chunk[:, : sequences.shape[1]] = sequences + self.all_sequences[idx : idx + sequences.shape[0], :] = chunk chunk = torch.zeros([sequences.shape[0], 583]) - chunk[:, :sequences.shape[1]] = reference_sequence.repeat( + chunk[:, : sequences.shape[1]] = reference_sequence.repeat( (sequences.shape[0], 1) ) - self.all_references[idx:idx+sequences.shape[0], :] = chunk + self.all_references[idx : idx + sequences.shape[0], :] = chunk # alignments alignments = torch.nested.to_padded_tensor( - torch.nested.nested_tensor(data["aln"]), - 0.0 + torch.nested.nested_tensor(data["aln"]), 0.0 ) - _, alignments = alignments[0], alignments[1:] # discard the first alignment + _, alignments = alignments[0], alignments[1:] # discard the first alignment chunk = torch.zeros([alignments.shape[0], 583]) - chunk[:, :sequences.shape[1]] = alignments - self.all_alignments[idx:idx+sequences.shape[0], :] = chunk + chunk[:, : sequences.shape[1]] = alignments + self.all_alignments[idx : idx + sequences.shape[0], :] = chunk # sizes - self.all_sizes[idx:idx+sequences.shape[0], :] = torch.tensor([len(seq) for seq in sequences]).unsqueeze(1) # noqa: E501 + self.all_sizes[idx : idx + sequences.shape[0], :] = torch.tensor( + [len(seq) for seq in sequences] + ).unsqueeze(1) # noqa: E501 idx += sequences.shape[0] @@ -94,7 +100,11 @@ def __len__(self): return self.all_sequences.size(0) def __getitem__(self, index: int) -> tuple[Tensor, Tensor]: - inputs = self.all_sequences[index], self.all_references[index], self.all_sizes[index] # noqa: E501 + inputs = ( + self.all_sequences[index], + self.all_references[index], + self.all_sizes[index], + ) # noqa: E501 if self.transform: inputs = self.transform(*inputs) diff --git a/src/beignet/datasets/_smurf_dataset_constants.py b/src/beignet/datasets/_smurf_dataset_constants.py index 914974a702..eea165de02 100644 --- a/src/beignet/datasets/_smurf_dataset_constants.py +++ b/src/beignet/datasets/_smurf_dataset_constants.py @@ -1,392 +1,392 @@ FAMILIES_TEST = [ - '3F6GA', - '1F86A', - '3F9XA', - '2P3WA', - '3FDXA', - '5FH7A', - '2FIUA', - '1FM0D', - '1FM0E', - '3KZPA', - '3FPNB', - '4FVGA', - '1FXLA', - '4G0XA', - '3G13A', - '1G2RA', - '3G2EA', - '3NO0A', - '4G4KA', - '1G6XA', - '3G9KF', - '1GCIA', - '3U2UA', - '4GJZA', - '2GMYA', - '1GPRA', - '3GPKA', - '1N62C', - '4GWBA', - '3H0NA', - '3LYHA', - '4HYLA', - '3H5JA', - '3H7OA', - '4H8EA', - '1H99A', - '2HA8A', - '2HBAA', - '2HBWA', - '2HC8A', - '4XPCA', - '3HMCA', - '5HMLA', - '3HRLA', - '3HY3A', - '2HZQA', - '2JFRA', - '5I32A', - '2I6HA', - '3IBZA', - '2ICUA', - '1IIBA', - '2IIHA', - '5IJAA', - '3IP0A', - '2NWRA', - '1IQ4A', - '2IQYA', - '3IS6A', - '3ISRA', - '3IT4A', - '3IT4B', - '3ITQA', - '5ITQA', - '3IUGA', - '2IXDA', - '3OCMA', - '2IZ6A', - '3PVEA', - '1JKEA', - '1JL1A', - '2JLIA', - '3JXGA', - '1K4IA', - '4LFLA', - '2OMLA', - '3K8UA', - '1M93B', - '1MPGA', - '3KEWA', - '1KHYA', - '1KNMA', - '2NUHA', - '3L00A', - '3L51A', - '3L60A', - '1LFPA', - '3LF9A', - '1LOPA', - '3LQBA', - '4LQ4A', - '4LWRA', - '1LYQA', - '4M0NA', - '3M7AA', - '4ME3A', - '2MHRA', - '3MHXA', - '3MMHA', - '4MU3A', - '1MVLA', - '3MVUA', - '1X1OA', - '4NBXA', - '3NFDA', - '3NO4A', - '2NRKA', - '2NRRA', - '1NS5A', - '4NTKA', - '3NUAA', - '1NZ0A', - '2O70A', - '2OFKA', - '2OLMA', - '2OMKA', - '4ONMA', - '3PN3A', - '1WDJA', - '2OYAA', - '1OZ9A', - '1TQ5A', - '2PFRA', - '4PGRA', - '2PLIA', - '3PO8A', - '3POJA', - '4PUIA', - '3PYWA', - '3Q46A', - '3Q64A', - '2Q7SA', - '4QDNA', - '2QF4A', - '1QG8A', - '2QIFA', - '2QIPA', - '2VTCA', - '2QQ4A', - '1R5LA', - '1YB0A', - '1RSSA', - '1RV9A', - '4RWUA', - '1S7IA', - '1SEIA', - '1SJ1A', - '1SUMB', - '1TIFA', - '1TIGA', - '1TQGA', - '3UBYA', - '1UCDA', - '4UC1A', - '1UEBA', - '1UI0A', - '1USMA', - '1V6TA', - '2VE8A', - '1VGJA', - '1VMHA', - '2VXNA', - '1VZYA', - '4WK7A', - '1W2WA', - '1W2WB', - '2W6KA', - '4W9ZA', - '4WEEA', - '1WJXA', - '1WNYA', - '2WNPF', - '4WPKA', - '2WQKA', - '1X9UA', - '3WSGA', - '1WUBA', - '1WURA', - '2X8XX', - '4X84A', - '4X9JA', - '2XOVA', - '2XTYA', - '1Y6ZA', - '2Y71A', - '1YARH', - '1YD0A', - '2YN5A', - '1Z0WA', - '4YQDA', - '1ZAVA', - '3ZJAA', - '2ZPTX' + "3F6GA", + "1F86A", + "3F9XA", + "2P3WA", + "3FDXA", + "5FH7A", + "2FIUA", + "1FM0D", + "1FM0E", + "3KZPA", + "3FPNB", + "4FVGA", + "1FXLA", + "4G0XA", + "3G13A", + "1G2RA", + "3G2EA", + "3NO0A", + "4G4KA", + "1G6XA", + "3G9KF", + "1GCIA", + "3U2UA", + "4GJZA", + "2GMYA", + "1GPRA", + "3GPKA", + "1N62C", + "4GWBA", + "3H0NA", + "3LYHA", + "4HYLA", + "3H5JA", + "3H7OA", + "4H8EA", + "1H99A", + "2HA8A", + "2HBAA", + "2HBWA", + "2HC8A", + "4XPCA", + "3HMCA", + "5HMLA", + "3HRLA", + "3HY3A", + "2HZQA", + "2JFRA", + "5I32A", + "2I6HA", + "3IBZA", + "2ICUA", + "1IIBA", + "2IIHA", + "5IJAA", + "3IP0A", + "2NWRA", + "1IQ4A", + "2IQYA", + "3IS6A", + "3ISRA", + "3IT4A", + "3IT4B", + "3ITQA", + "5ITQA", + "3IUGA", + "2IXDA", + "3OCMA", + "2IZ6A", + "3PVEA", + "1JKEA", + "1JL1A", + "2JLIA", + "3JXGA", + "1K4IA", + "4LFLA", + "2OMLA", + "3K8UA", + "1M93B", + "1MPGA", + "3KEWA", + "1KHYA", + "1KNMA", + "2NUHA", + "3L00A", + "3L51A", + "3L60A", + "1LFPA", + "3LF9A", + "1LOPA", + "3LQBA", + "4LQ4A", + "4LWRA", + "1LYQA", + "4M0NA", + "3M7AA", + "4ME3A", + "2MHRA", + "3MHXA", + "3MMHA", + "4MU3A", + "1MVLA", + "3MVUA", + "1X1OA", + "4NBXA", + "3NFDA", + "3NO4A", + "2NRKA", + "2NRRA", + "1NS5A", + "4NTKA", + "3NUAA", + "1NZ0A", + "2O70A", + "2OFKA", + "2OLMA", + "2OMKA", + "4ONMA", + "3PN3A", + "1WDJA", + "2OYAA", + "1OZ9A", + "1TQ5A", + "2PFRA", + "4PGRA", + "2PLIA", + "3PO8A", + "3POJA", + "4PUIA", + "3PYWA", + "3Q46A", + "3Q64A", + "2Q7SA", + "4QDNA", + "2QF4A", + "1QG8A", + "2QIFA", + "2QIPA", + "2VTCA", + "2QQ4A", + "1R5LA", + "1YB0A", + "1RSSA", + "1RV9A", + "4RWUA", + "1S7IA", + "1SEIA", + "1SJ1A", + "1SUMB", + "1TIFA", + "1TIGA", + "1TQGA", + "3UBYA", + "1UCDA", + "4UC1A", + "1UEBA", + "1UI0A", + "1USMA", + "1V6TA", + "2VE8A", + "1VGJA", + "1VMHA", + "2VXNA", + "1VZYA", + "4WK7A", + "1W2WA", + "1W2WB", + "2W6KA", + "4W9ZA", + "4WEEA", + "1WJXA", + "1WNYA", + "2WNPF", + "4WPKA", + "2WQKA", + "1X9UA", + "3WSGA", + "1WUBA", + "1WURA", + "2X8XX", + "4X84A", + "4X9JA", + "2XOVA", + "2XTYA", + "1Y6ZA", + "2Y71A", + "1YARH", + "1YD0A", + "2YN5A", + "1Z0WA", + "4YQDA", + "1ZAVA", + "3ZJAA", + "2ZPTX", ] NUM_SEQUENCES_TEST = 719_168 FAMILIES_TRAIN = [ - '3A0YA', - '4ACIA', - '3AH7A', - '5A62A', - '2A4VA', - '1A3AA', - '3A35A', - '5A35A', - '3GM5A', - '2A67A', - '3A6SA', - '1NNHA', - '4A7UA', - '4A7WA', - '5ECCA', - '5A89A', - '5C0PA', - '2ABWA', - '2A9SA', - '4JS8A', - '3AABA', - '3AAYA', - '4C5KA', - '4ABLA', - '3ACXA', - '1AE9A', - '4AFFA', - '4AFHA', - '3AGYA', - '1M2KA', - '4AIVA', - '4AIWA', - '1AKOA', - '3AK8A', - '3AKBA', - '3ALUA', - '2AMHA', - '2AN1A', - '2ANRA', - '2ANXA', - '4WTPA', - '2APJA', - '2FBNA', - '4APXB', - '2AQ6A', - '1ATZA', - '4ATEA', - '4AVRA', - '3AWUA', - '4AY0A', - '2B0AA', - '1EUWA', - '4LSCA', - '5B3PA', - '2B5GA', - '2HQSC', - '3B8BA', - '4B8EA', - '2B94A', - '1BD8A', - '3BEDA', - '3BEMA', - '3SY1A', - '2BFWA', - '5C1EA', - '4BH5A', - '2C2IA', - '2BK8A', - '2BKMA', - '2BKXA', - '4LXQA', - '3BM7A', - '2BOUA', - '3BP3A', - '3BPKA', - '5C90A', - '3KG9A', - '3BR8A', - '3BT5A', - '1BUOA', - '2BV5A', - '3BWUD', - '3BWUF', - '1I4JA', - '1BXYA', - '1BYRA', - '3BY8A', - '5BY4A', - '2BZ1A', - '4N0KA', - '3C1QA', - '4C24A', - '3C37A', - '3C4BA', - '2C5QA', - '4C6AA', - '4C6SA', - '2C71A', - '2C8MA', - '2C92A', - '1K7KA', - '5CAJA', - '3CCDA', - '3CCGA', - '5CEGB', - '1WPNA', - '1CFBA', - '1CHDA', - '2GGCA', - '3CH0A', - '3LULA', - '3MN2A', - '4EWFA', - '3NREA', - '3CI3A', - '4NNOA', - '3CNVA', - '2EGZA', - '1COJA', - '1COZA', - '3CQ1A', - '5CQXA', - '1KQPA', - '1CTFA', - '1CUKA', - '2CVEA', - '1CXQA', - '3LF5A', - '3CXKA', - '5CX7A', - '3CZXA', - '1D0QA', - '3D01A', - '3D03A', - '4D05A', - '4D74A', - '4DBFA', - '2D4XA', - '3LTJA', - '4DAMA', - '3DBOB', - '3DD6A', - '1H72C', - '4DE9A', - '1DFUP', - '3DFGA', - '1DJ0A', - '2DQWA', - '3FDJA', - '2DTJA', - '4DT4A', - '4DUNA', - '2DXAA', - '4XTVA', - '2DYIA', - '2DYJA', - '2E0NA', - '2E11A', - '1K7JA', - '4E3YA', - '3UF6A', - '1E58A', - '2E5YA', - '2GUIA', - '2EBJA', - '3EERA', - '4HOIA', - '2EGVA', - '3OHEA', - '3EJKA', - '1EKEA', - '1EKJA', - '4ONWA', - '4EOJB', - '4EQPA', - '3ERBA', - '3ERSX', - '2G2CA', - '4ES1A', - '2EW0A', - '4K08A', - '3F0DA', - '4F01A', - '2F1FA', - '2F23A', - '5F3MA', - '3F42A', - '2F5GA', - '3F5VA', - '4F55A' + "3A0YA", + "4ACIA", + "3AH7A", + "5A62A", + "2A4VA", + "1A3AA", + "3A35A", + "5A35A", + "3GM5A", + "2A67A", + "3A6SA", + "1NNHA", + "4A7UA", + "4A7WA", + "5ECCA", + "5A89A", + "5C0PA", + "2ABWA", + "2A9SA", + "4JS8A", + "3AABA", + "3AAYA", + "4C5KA", + "4ABLA", + "3ACXA", + "1AE9A", + "4AFFA", + "4AFHA", + "3AGYA", + "1M2KA", + "4AIVA", + "4AIWA", + "1AKOA", + "3AK8A", + "3AKBA", + "3ALUA", + "2AMHA", + "2AN1A", + "2ANRA", + "2ANXA", + "4WTPA", + "2APJA", + "2FBNA", + "4APXB", + "2AQ6A", + "1ATZA", + "4ATEA", + "4AVRA", + "3AWUA", + "4AY0A", + "2B0AA", + "1EUWA", + "4LSCA", + "5B3PA", + "2B5GA", + "2HQSC", + "3B8BA", + "4B8EA", + "2B94A", + "1BD8A", + "3BEDA", + "3BEMA", + "3SY1A", + "2BFWA", + "5C1EA", + "4BH5A", + "2C2IA", + "2BK8A", + "2BKMA", + "2BKXA", + "4LXQA", + "3BM7A", + "2BOUA", + "3BP3A", + "3BPKA", + "5C90A", + "3KG9A", + "3BR8A", + "3BT5A", + "1BUOA", + "2BV5A", + "3BWUD", + "3BWUF", + "1I4JA", + "1BXYA", + "1BYRA", + "3BY8A", + "5BY4A", + "2BZ1A", + "4N0KA", + "3C1QA", + "4C24A", + "3C37A", + "3C4BA", + "2C5QA", + "4C6AA", + "4C6SA", + "2C71A", + "2C8MA", + "2C92A", + "1K7KA", + "5CAJA", + "3CCDA", + "3CCGA", + "5CEGB", + "1WPNA", + "1CFBA", + "1CHDA", + "2GGCA", + "3CH0A", + "3LULA", + "3MN2A", + "4EWFA", + "3NREA", + "3CI3A", + "4NNOA", + "3CNVA", + "2EGZA", + "1COJA", + "1COZA", + "3CQ1A", + "5CQXA", + "1KQPA", + "1CTFA", + "1CUKA", + "2CVEA", + "1CXQA", + "3LF5A", + "3CXKA", + "5CX7A", + "3CZXA", + "1D0QA", + "3D01A", + "3D03A", + "4D05A", + "4D74A", + "4DBFA", + "2D4XA", + "3LTJA", + "4DAMA", + "3DBOB", + "3DD6A", + "1H72C", + "4DE9A", + "1DFUP", + "3DFGA", + "1DJ0A", + "2DQWA", + "3FDJA", + "2DTJA", + "4DT4A", + "4DUNA", + "2DXAA", + "4XTVA", + "2DYIA", + "2DYJA", + "2E0NA", + "2E11A", + "1K7JA", + "4E3YA", + "3UF6A", + "1E58A", + "2E5YA", + "2GUIA", + "2EBJA", + "3EERA", + "4HOIA", + "2EGVA", + "3OHEA", + "3EJKA", + "1EKEA", + "1EKJA", + "4ONWA", + "4EOJB", + "4EQPA", + "3ERBA", + "3ERSX", + "2G2CA", + "4ES1A", + "2EW0A", + "4K08A", + "3F0DA", + "4F01A", + "2F1FA", + "2F23A", + "5F3MA", + "3F42A", + "2F5GA", + "3F5VA", + "4F55A", ] -NUM_SEQUENCES_TRAIN = 950_762 \ No newline at end of file +NUM_SEQUENCES_TRAIN = 950_762 From b584a427944a13a77e431e4b221d781992ca7e16 Mon Sep 17 00:00:00 2001 From: Edith Lee Date: Fri, 31 May 2024 12:19:22 -0700 Subject: [PATCH 12/14] delete comments --- src/beignet/datasets/_smurf_dataset.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/beignet/datasets/_smurf_dataset.py b/src/beignet/datasets/_smurf_dataset.py index a875b98c02..e9cebcb073 100644 --- a/src/beignet/datasets/_smurf_dataset.py +++ b/src/beignet/datasets/_smurf_dataset.py @@ -88,7 +88,7 @@ def __init__( # sizes self.all_sizes[idx : idx + sequences.shape[0], :] = torch.tensor( [len(seq) for seq in sequences] - ).unsqueeze(1) # noqa: E501 + ).unsqueeze(1) idx += sequences.shape[0] @@ -104,7 +104,7 @@ def __getitem__(self, index: int) -> tuple[Tensor, Tensor]: self.all_sequences[index], self.all_references[index], self.all_sizes[index], - ) # noqa: E501 + ) if self.transform: inputs = self.transform(*inputs) From 3e6f1235c720261ec82dce538fec075abf8b9e65 Mon Sep 17 00:00:00 2001 From: Edith Lee Date: Fri, 31 May 2024 12:21:08 -0700 Subject: [PATCH 13/14] ruff again --- src/beignet/datasets/_smurf_dataset.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/beignet/datasets/_smurf_dataset.py b/src/beignet/datasets/_smurf_dataset.py index e9cebcb073..b937b55572 100644 --- a/src/beignet/datasets/_smurf_dataset.py +++ b/src/beignet/datasets/_smurf_dataset.py @@ -104,7 +104,7 @@ def __getitem__(self, index: int) -> tuple[Tensor, Tensor]: self.all_sequences[index], self.all_references[index], self.all_sizes[index], - ) + ) if self.transform: inputs = self.transform(*inputs) From 9896ba06f8f828ff10bc3215bf2dbc96992e8b1b Mon Sep 17 00:00:00 2001 From: Edith Lee Date: Mon, 3 Jun 2024 16:57:09 -0700 Subject: [PATCH 14/14] add one-hot --- src/beignet/_smith_waterman.py | 6 +++-- src/beignet/datasets/_smurf_dataset.py | 33 ++++++++++++++++++++------ 2 files changed, 30 insertions(+), 9 deletions(-) diff --git a/src/beignet/_smith_waterman.py b/src/beignet/_smith_waterman.py index 63041583e1..071604d9f3 100644 --- a/src/beignet/_smith_waterman.py +++ b/src/beignet/_smith_waterman.py @@ -1,6 +1,8 @@ # @title `smith_waterman` +from typing import Sequence + import torch import torch.func from torch import Tensor @@ -8,7 +10,7 @@ def smith_waterman( input: Tensor, - lengths: (int, int), + lengths: Sequence[int], gap_penalty: float = 0.0, temperature: float = 1.0, ) -> Tensor: @@ -41,7 +43,7 @@ def smith_waterman( def fn( input: Tensor, - lengths: (int, int), + lengths: Sequence[int], ) -> Tensor: if input.is_complex() or input.is_floating_point(): initial_value = torch.finfo(input.dtype).min diff --git a/src/beignet/datasets/_smurf_dataset.py b/src/beignet/datasets/_smurf_dataset.py index b937b55572..3becfd3d04 100644 --- a/src/beignet/datasets/_smurf_dataset.py +++ b/src/beignet/datasets/_smurf_dataset.py @@ -52,7 +52,7 @@ def __init__( self.all_sequences = torch.zeros([num_sequences, 583]) self.all_references = torch.zeros([num_sequences, 583]) self.all_alignments = torch.zeros([num_sequences, 583]) - self.all_sizes = torch.zeros([num_sequences, 1]) + self.all_sizes = torch.zeros([num_sequences]) idx = 0 @@ -63,18 +63,25 @@ def __init__( sequences = torch.nested.to_padded_tensor( torch.nested.nested_tensor(data["ms"]), 0.0 ) - reference_sequence, sequences = sequences[0], sequences[1:] + + reference_sequence, sequences = sequences[0].squeeze(0), sequences[1:] chunk = torch.zeros([sequences.shape[0], 583]) chunk[:, : sequences.shape[1]] = sequences self.all_sequences[idx : idx + sequences.shape[0], :] = chunk + # reference sequences chunk = torch.zeros([sequences.shape[0], 583]) chunk[:, : sequences.shape[1]] = reference_sequence.repeat( (sequences.shape[0], 1) ) self.all_references[idx : idx + sequences.shape[0], :] = chunk + # sizes + self.all_sizes[idx : idx + sequences.shape[0]] = torch.tensor( + [len(seq) for seq in sequences] + ) + # alignments alignments = torch.nested.to_padded_tensor( torch.nested.nested_tensor(data["aln"]), 0.0 @@ -85,13 +92,25 @@ def __init__( chunk[:, : sequences.shape[1]] = alignments self.all_alignments[idx : idx + sequences.shape[0], :] = chunk - # sizes - self.all_sizes[idx : idx + sequences.shape[0], :] = torch.tensor( - [len(seq) for seq in sequences] - ).unsqueeze(1) - idx += sequences.shape[0] + # one-hot sequences and reference sequences + max_token = torch.max(self.all_sequences.int()).item() + + self.all_sequences = torch.concatenate( + [ + torch.eye(max_token + 1), + torch.zeros([1, max_token + 1]), + ], + )[self.all_sequences.int()] + + self.all_references = torch.concatenate( + [ + torch.eye(max_token + 1), + torch.zeros([1, max_token + 1]), + ], + )[self.all_references.int()] + self.transform = transform self.target_transform = target_transform