Working with ProxyArray#

Isaac Lab data classes return ProxyArray — a lightweight, warp-first wrapper that provides zero-copy access to simulation data as either a warp.array or a torch.Tensor.

Note

ProxyArray is inspired by the ProxyArray class from mujocolab/mjlab (BSD-3-Clause). The design adapts the same dual-accessor pattern to Isaac Lab’s warp-based data pipeline.

Quick Start#

Every property on asset and sensor data classes (e.g., robot.data.joint_pos, sensor.data.net_forces_w) returns a ProxyArray:

robot = env.scene["robot"]

# Explicit torch access (preferred)
joint_positions = robot.data.joint_pos.torch        # torch.Tensor, cached zero-copy view
gravity_proj = robot.data.projected_gravity_b.torch  # torch.Tensor

# Explicit warp access (for kernel interop)
wp_array = robot.data.joint_pos.warp                # warp.array, the original buffer

# Pass directly to warp kernels — no unwrapping needed
wp.launch(my_kernel, inputs=[robot.data.joint_pos], ...)  # works via __cuda_array_interface__

The .torch and .warp Accessors#

  • .torch returns a cached, zero-copy torch.Tensor view of the underlying warp array (via warp.to_torch()). The tensor is created on first access and reused on subsequent calls. Since it is a zero-copy view, writes to the tensor are visible through the warp array and vice versa.

  • .warp returns the original warp.array. Use this when you need to pass data to warp kernels explicitly or access warp-specific attributes (ptr, strides, etc.).

Deprecation Bridge#

To ease migration, ProxyArray includes a deprecation bridge that allows existing code to treat it as a torch.Tensor temporarily:

# These still work but emit a one-time DeprecationWarning:
result = torch.sum(robot.data.joint_pos)           # via __torch_function__
value = robot.data.joint_pos[0, 3]                 # via __getitem__
result = robot.data.joint_pos + 1.0                # via __add__
legacy = wp.to_torch(robot.data.joint_pos)         # temporary shim

# Preferred (no warning):
result = torch.sum(robot.data.joint_pos.torch)
value = robot.data.joint_pos.torch[0, 3]
result = robot.data.joint_pos.torch + 1.0
tensor = robot.data.joint_pos.torch

The wp.to_torch() compatibility path is a temporary shim for code that was migrated before ProxyArray exposed explicit accessors. It returns the same zero-copy tensor as .torch and emits a one-time DeprecationWarning. The shim and the other deprecation bridges will be removed in a future release. Migrate to explicit .torch access now.

Migrating from Isaac Lab 2.x#

In Isaac Lab 2.x, data properties returned torch.Tensor directly. In 3.0, they return ProxyArray. Append .torch to get the tensor:

# BEFORE (Isaac Lab 2.x) — properties returned torch.Tensor directly
joint_pos = robot.data.joint_pos
first_contact = sensor.compute_first_contact(dt)

# AFTER (Isaac Lab 3.0) — properties return ProxyArray
joint_pos = robot.data.joint_pos.torch
first_contact = sensor.compute_first_contact(dt).torch

Note

Passing a ProxyArray to wp.to_torch() is temporarily supported by a compatibility shim and returns the same cached zero-copy tensor as .torch. This path emits a one-time DeprecationWarning and will be removed in a future release. Use .torch in new code.

Backend Differences#

While the ProxyArray interface is identical across backends, the underlying data refresh model differs:

PhysX (pull-to-refresh):

Properties pull fresh data from the PhysX tensor API on first access per simulation step, then cache the result. The underlying GPU buffers are stable and pre-allocated — the ProxyArray wrapper is created once and reused safely across steps.

Newton (auto-refresh with wrapper replacement):

The simulation automatically refreshes GPU buffers each step. On full simulation resets, buffers may be re-created. The Newton backend creates new ProxyArray wrappers for the new warp arrays, invalidating any previously cached torch tensors.

In both cases, .torch always returns a view of the current simulation state for the current step.

Warning

Do not cache .torch results across simulation resets. After a reset (especially on Newton), previously obtained tensors may point to stale or freed GPU memory. Always re-access the property after a reset.

API Reference#

class isaaclab.utils.warp.ProxyArray[source]

Warp-first array wrapper providing cached zero-copy .torch and .warp accessors.

This class wraps a warp.array and provides:

  • A .warp property that returns the original warp array (for kernel interop).

  • A .torch property that returns a cached, zero-copy torch.Tensor view (via warp.to_torch()).

  • Convenience properties (shape, dtype, device) delegated to the warp array.

  • A deprecation bridge for common torch functions, indexing, and arithmetic/comparison operators while emitting a one-time DeprecationWarning. Tensor instance methods such as clone() are not forwarded; use explicit .torch access for those.

Example:

import warp as wp
from isaaclab.utils.warp.proxy_array import ProxyArray

arr = wp.zeros(100, dtype=wp.vec3f, device="cuda:0")
ta = ProxyArray(arr)

# Explicit access (preferred)
ta.warp  # -> wp.array, shape (100,), dtype vec3f
ta.torch  # -> torch.Tensor, shape (100, 3)

# Deprecation bridge (warns once, then silent)
result = ta + 1.0  # works, emits DeprecationWarning

Methods:

__init__(wp_array)

Initialize the ProxyArray wrapper.

Attributes:

warp

The underlying warp array.

torch

A cached, zero-copy torch.Tensor view of the warp array.

shape

Shape of the underlying warp array.

dtype

Warp dtype of the underlying array.

device

Device string of the underlying warp array.

__init__(wp_array: warp.array) None[source]

Initialize the ProxyArray wrapper.

The instance is immutable after construction: the wrapped wp.array cannot be reassigned. If the underlying simulation memory is re-allocated, construct a new ProxyArray instead of mutating an existing one.

Parameters:

wp_array – The warp array to wrap.

Raises:

TypeError – If wp_array is not a warp.array.

property warp: warp.array

The underlying warp array.

property torch: torch.Tensor

A cached, zero-copy torch.Tensor view of the warp array.

The tensor is created on first access via warp.to_torch() and cached for subsequent calls. Since this is a zero-copy view, modifications to the tensor are visible through the warp array and vice versa.

When the underlying warp array has dtype wp.quatf and the WARN_ON_TORCH_QUATF_ACCESS environment variable is set to "1", each read emits a UserWarning pointing at the call site. This is a runtime aid for migrating Isaac Lab 2.x code (which used the (w, x, y, z) quaternion convention) to Isaac Lab 3.x’s (x, y, z, w) convention.

property shape: tuple[int, ...]

Shape of the underlying warp array.

property dtype

Warp dtype of the underlying array.

property device: str

Device string of the underlying warp array.