Source code for puxle.core.puzzle_state

from __future__ import annotations

from typing import Any, Type, TypeVar

from xtructure import FieldDescriptor, Xtructurable, xtructure_dataclass

T = TypeVar("T")

FieldDescriptor = FieldDescriptor


[docs] class PuzzleState(Xtructurable): """ Marker base-class for PuXle states. Notes: - PuXle state/solve-config classes are typically created via `@state_dataclass`. - In-memory bitpacking is handled by xtructure (FieldDescriptor.packed_tensor / aggregate bitpack), not by overriding this base class. """ pass
[docs] def state_dataclass(cls: Type[T] | None = None, **kwargs: Any): """ Decorator used to define a JAX-compatible xtructure dataclass for PuXle state objects. Default behavior: - Enables xtructure bitpacking helpers via `bitpack="auto"` when supported. - Preserves backwards compatibility by providing identity `.packed` / `.unpacked` properties for non-bitpacked states. """ def wrap(target_cls: Type[T]) -> Type[T]: # Prefer enabling xtructure's built-in bitpacking helpers by default. call_kwargs = dict(kwargs) call_kwargs.setdefault("bitpack", "auto") try: dc_cls = xtructure_dataclass(target_cls, **call_kwargs) except TypeError: # Backwards-compatible fallback if the installed xtructure doesn't accept `bitpack=`. call_kwargs.pop("bitpack", None) dc_cls = xtructure_dataclass(target_cls, **call_kwargs) if not hasattr(dc_cls, "packed") and not hasattr(dc_cls, "unpacked"): # Backwards compatibility: treat state as already packed/unpacked. def packed(self) -> Any: return self setattr(dc_cls, "packed", property(packed)) def unpacked(self) -> Any: return self setattr(dc_cls, "unpacked", property(unpacked)) elif hasattr(dc_cls, "packed") ^ hasattr(dc_cls, "unpacked"): # Packing and unpacking must be implemented together. raise ValueError( "State class must implement both packing and unpacking (or neither)." ) return dc_cls if cls is None: return wrap return wrap(cls)