#mjx Make pytree registration optional.

This is a noop for MJX itself, but is useful for custom types extending MJX types.
This CL also ensures unused kwargs in `__init_subclass__` are passed to the parent class.

PiperOrigin-RevId: 728215373
Change-Id: I362d3fb8d4b7d679a3a00d96866d46a52d711369
This commit is contained in:
Google DeepMind
2025-02-18 08:12:02 -08:00
committed by Copybara-Service
parent 36142cddee
commit 982330d15a
+7 -9
View File
@@ -34,7 +34,7 @@ def _jax_in_args(typ) -> bool:
return False return False
def dataclass(clz: _T) -> _T: def dataclass(clz: _T, register_as_pytree: bool) -> _T:
"""Wraps a dataclass with metadata for which fields are pytrees. """Wraps a dataclass with metadata for which fields are pytrees.
This is based off flax.struct.dataclass, but instead of using field This is based off flax.struct.dataclass, but instead of using field
@@ -48,6 +48,9 @@ def dataclass(clz: _T) -> _T:
the resulting dataclass, registered with Jax the resulting dataclass, registered with Jax
""" """
data_clz = dataclasses.dataclass(frozen=True)(clz) data_clz = dataclasses.dataclass(frozen=True)(clz)
data_clz.replace = dataclasses.replace
if register_as_pytree:
meta_fields, data_fields = [], [] meta_fields, data_fields = [], []
for field in dataclasses.fields(data_clz): for field in dataclasses.fields(data_clz):
if _jax_in_args(field.type): if _jax_in_args(field.type):
@@ -55,12 +58,6 @@ def dataclass(clz: _T) -> _T:
else: else:
meta_fields.append(field) meta_fields.append(field)
def replace(self, **updates):
"""Returns a new object replacing the specified fields with new values."""
return dataclasses.replace(self, **updates)
data_clz.replace = replace
def iterate_clz_with_keys(x): def iterate_clz_with_keys(x):
def to_meta(field, obj): def to_meta(field, obj):
val = getattr(obj, field.name) val = getattr(obj, field.name)
@@ -109,8 +106,9 @@ class PyTreeNode:
This base class additionally avoids type checking errors when using PyType. This base class additionally avoids type checking errors when using PyType.
""" """
def __init_subclass__(cls): def __init_subclass__(cls, register_as_pytree: bool = True, **kwargs):
dataclass(cls) super().__init_subclass__(**kwargs)
dataclass(cls, register_as_pytree=register_as_pytree)
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
# stub for pytype # stub for pytype