Skip to content

fix(agent): back Policies with a hashable tuple#416

Open
gauraaansh wants to merge 1 commit into
infer-actively:mainfrom
gauraaansh:fix/policies-hashable-static
Open

fix(agent): back Policies with a hashable tuple#416
gauraaansh wants to merge 1 commit into
infer-actively:mainfrom
gauraaansh:fix/policies-hashable-static

Conversation

@gauraaansh

@gauraaansh gauraaansh commented Jul 5, 2026

Copy link
Copy Markdown

Fixes #346

Agent.policies is marked static=True (#345) to support vmap/scan over a batched Agent (#227), since policies has no batch dimension. But Policies.policy_arr is a real jnp.ndarray, so the static partition ends up identity-based instead of value-based, and every fresh Agent construction is a cache miss under eqx.filter_jit.

This backs Policies with a hashable tuple instead, exposing policy_arr as a property that materializes a JAX array on access. Agent.policies stays static, but the static partition is now hashable by value.

Constructing an Agent inside an active jax.jit trace broke the first version of this, since a traced array can't be converted to a concrete tuple mid-trace. Traced this to construct_policies() converting to JAX arrays earlier than necessary. Added pure-Python tuple builders that defer the JAX conversion to the property/return boundary.

Testing

  • Recompiles across repeated agent construction drop from 3 to 1
  • vmap/scan/slicing over a batched Agent still work (Agent policies field in equinox module has no batch_dim #227)
  • New construction path verified bit-for-bit equivalent to the old output, and faster
  • No memory regression observed under repeated Agent construction (CPU and GPU) or in a compiled workload mirroring the planning loop's access pattern (CPU). At larger policy-table sizes, the tuple implementation showed lower peak memory usage than the current implementation during repeated construction.
  • Full test suite: 283 passed, 1 skipped, 1 pre-existing unrelated failure

Agent.policies is marked static=True to support vmap/scan over batched
Agents (infer-actively#227), but Policies currently stores policy_arr as a jnp.ndarray.
As described in infer-actively#346, constructing equivalent Agents repeatedly causes
eqx.filter_jit to miss its compilation cache.

Store policies internally as a hashable nested tuple instead, exposing
policy_arr via a property that materializes a JAX array on access. This
preserves the static Agent.policies partition while allowing equivalent
policy tables to hash by value.

Constructing an Agent inside an active jax.jit trace required an
additional change, since traced arrays cannot be converted back to
concrete Python values. To avoid this, add pure-Python tuple builders
for policy construction, and only convert to a JAX array at the
property/return boundary.

Fixes infer-actively#346
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.

Static JAX arrays in Equinox static=True fields can break eqx.filter_jit / cause recompilation errors

1 participant