Skip to content

Add test coverage for gnm_common#25

Open
manumishra12 wants to merge 1 commit into
google:mainfrom
manumishra12:pr3/gnm-common-tests
Open

Add test coverage for gnm_common#25
manumishra12 wants to merge 1 commit into
google:mainfrom
manumishra12:pr3/gnm-common-tests

Conversation

@manumishra12

Copy link
Copy Markdown
Contributor

Adds gnm_common_test.py. gnm_common.py holds the backend-agnostic math
shared by all four GNM backends but had no dedicated test (it was only
exercised indirectly through the per-backend tests).

The new suite (25 tests) covers:

  • Array helpers: take, eye, reshape_with_batch_dims,
    zeros_with_batch_dims.
  • axis_angle_to_rotation_matrix: zero -> identity, rotation about each
    principal axis leaves that axis invariant, the 90 degrees-about-z reference
    matrix, orthonormality and unit determinant on random inputs, and batch-shape
    preservation.
  • joint_transforms_world: rest pose places joints at their bind positions,
    a global translation shifts the chain, and a root rotation propagates to the
    child joint.
  • linear_blend_skinning: rest pose is the identity, a global translation
    translates the vertices, and batch shapes are preserved.
  • vertex_positions_bind_pose / joint_positions_bind_pose: None
    parameters return the template, and identity/expression bases are applied
    correctly.
  • compute_pose_correctives: None inputs and zero rotations produce zero
    correctives, and batch shapes are preserved.

Follows the existing absltest style used across the package. All tests pass
locally with the NumPy backend.

@manumishra12
manumishra12 force-pushed the pr3/gnm-common-tests branch from 655792d to 6996da4 Compare July 18, 2026 10:27
Comment thread gnm/shape/gnm_common_test.py Outdated
class ArrayHelpersTest(parameterized.TestCase):
"""Tests for the backend-agnostic array helpers."""

def test_take_selects_along_axis(self) -> None:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove the return type annotation from all the test_* functions. This is to stay consistent with our internal codebase.

from gnm.shape import gnm_common


class ArrayHelpersTest(parameterized.TestCase):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For all the tests, please use the parameterized to generate a given test for all the backends supported by xnp (NumPy, jax, TF, pytorch).

For the functions which take xnp as an input argument, you can iterate over the backends directly (take, eye), for the other functions you can iterate over input arrays built by the individual backends from which the current xnp is extracted at runtime within the functions under test (reshape_with_batch_dims, zeros_with_batch_dims).

This will help the tests catch any potential bugs specific to a given backend.

np.testing.assert_array_equal(zeros, np.zeros((4, 4, 4)))


class AxisAngleToRotationMatrixTest(parameterized.TestCase):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As in the comment about ArrayHelperTest, please use the parameterized to iterate as well over the supported backends. Fo the actual asserts, for simplicity one could always convert the values to np.ndarray.

self.assertEqual(matrices.shape, (2, 4, 3, 3))


class JointTransformsWorldTest(parameterized.TestCase):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As in the comment about ArrayHelperTest, please use the parameterized to iterate as well over the supported backends. Fo the actual asserts, for simplicity one could always convert the values to np.ndarray.

)


class LinearBlendSkinningTest(parameterized.TestCase):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As in the comment about ArrayHelperTest, please use the parameterized to iterate as well over the supported backends. Fo the actual asserts, for simplicity one could always convert the values to np.ndarray.

self.assertEqual(posed.shape, (4, 3, 3))


class BindPoseTest(parameterized.TestCase):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As in the comment about ArrayHelperTest, please use the parameterized to iterate as well over the supported backends. Fo the actual asserts, for simplicity one could always convert the values to np.ndarray.

)


class PoseCorrectivesTest(parameterized.TestCase):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As in the comment about ArrayHelperTest, please use the parameterized to iterate as well over the supported backends. Fo the actual asserts, for simplicity one could always convert the values to np.ndarray.

@bednarikjan

Copy link
Copy Markdown
Collaborator

@manumishra12 Thanks for the PR! Besides the comments above, please see also the output of the linter CI.

Adds gnm_common_test.py covering the backend-agnostic math shared by every GNM
backend: array helpers (take, eye, reshape_with_batch_dims,
zeros_with_batch_dims), axis_angle_to_rotation_matrix (identity, per-axis
invariance, known rotations, orthonormality/determinant, batch shapes),
joint_transforms_world forward kinematics, linear_blend_skinning (rest pose,
translation, batching), the bind-pose helpers, and compute_pose_correctives.

Every test is parameterized over all supported xnp backends (NumPy, JAX,
TensorFlow, PyTorch) so backend-specific regressions are caught. For the
functions that accept an xnp argument (take, eye) the backend module is passed
through directly; for the rest the inputs are built with each backend so the
module is resolved at runtime inside the function under test. Assertions
convert results to np.ndarray for simplicity. Follows the existing absltest
style used across the package.
@manumishra12
manumishra12 force-pushed the pr3/gnm-common-tests branch from 6996da4 to 8f23dbc Compare July 23, 2026 17:53
@manumishra12

Copy link
Copy Markdown
Contributor Author

Thanks for the review! I've pushed an update addressing all the comments:

  • Return type annotations removed — dropped the -> None annotations from every test_* function (and from the two setUp methods) to stay consistent with the internal codebase.

  • Parameterized over all backends — every test now runs against all four xnp backends via a shared _XNP_BACKENDS list decorated with @parameterized.named_parameters:

    _XNP_BACKENDS = (
        ('numpy', np),
        ('jax', enp.lazy.jnp),
        ('tensorflow', enp.lazy.tnp),
        ('pytorch', enp.lazy.torch),
    )

    For the functions that take an xnp argument (take, eye) the backend module is passed through directly. For the rest, the inputs are built with each backend so the current xnp is extracted at runtime inside the function under test. Assertions convert the results to np.ndarray for simplicity. This gives 23 test methods x 4 backends = 92 test cases.

  • Linter — fixed the line-too-long failure; pylint gnm/ is now clean.

All 92 tests pass locally against NumPy, JAX, TensorFlow, and PyTorch. Let me know if you'd like any further changes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants