Execution backends
Choose Rust CPU, NumPy, or a GPU array backend, and understand sliced execution and timing.
On this page
Choosing a backend
arctn_contract and ArcTNExecutionPlan.execute default to backend="native", the Rust CPU executor. Specify the appropriate backend for NumPy or a GPU array library. ArcTN neither switches automatically based on hardware nor falls back to another backend after a failure.
The backend determines which library performs each array operation. For example, the same path can run through the Rust CPU implementation or NumPy; existing CuPy device arrays can run through CuPy. Backend selection does not change the chosen contraction path.
| backend | Execution mechanism | Array location |
|---|---|---|
native |
Rust matrixmultiply CPU kernels |
Inputs are prepared as C-contiguous NumPy arrays before being passed to Rust |
numpy |
opt_einsum calls NumPy | CPU |
cupy, torch, jax, etc. |
opt_einsum calls the specified array library | Retains the device of the input device arrays; prepare inputs according to the selected library |
Executing slices
For unsliced execution, the native backend follows the supplied SSA path; external backends prepare and evaluate a fixed opt_einsum contraction expression.
Sliced execution uses the same slicing set and per-slice path, but the two backend types schedule work differently:
- Native backend: Rust groups slices through Rayon, then combines results in a fixed group order.
- External backend: Python sequentially enumerates slicing-index value combinations, evaluates the same expression for each slice, and adds results using the selected array library. Intermediate tensors are not reused between slices.
Execution through Quimb / Cotengra
arctn_tree returns a Cotengra ContractionTree containing the path and slicing indices; it does not contract arrays itself. When the tree is subsequently contracted, Cotengra/autoray selects array operations and executes slices.
For an existing Quimb TensorNetwork, pass optimize=ArcTNOptimizer(...). Quimb obtains the tree through ArcTNOptimizer.search(); see the Quimb frontend example. This execution route differs from selecting a backend directly in arctn_contract.
Synchronization, timing, and dependencies
In an arctn_contract report, native and NumPy execution are treated as synchronous: numerical computation is complete when the call returns. execution_wall_s includes expression preparation and the backend call, but excludes input preparation; execution_total_host_wall_s also includes execution_input_prepare_wall_s.
GPU libraries may only submit work during the call, with device computation finishing later. ArcTN does not insert device synchronization, so other external backends report execution_wall_s as None instead of treating the shorter host-call duration as full computation time. Unsliced plan.execute(return_info=True) returns timing fields from the compiled object.
| Field | Scope |
|---|---|
| execution_setup_wall_s | Expression compilation and preparation of input-array slicing indices |
| execution_dispatch_wall_s | From the start of the backend call to its return on the host |
| execution_wall_s | Setup plus dispatch for native/NumPy; excludes input preparation in arctn_contract |
| execution_timing_scope | Indicates synchronous host timing or unverified external-backend completion |
from arctn import arctn_contract
value, info = arctn_contract(
inputs, output, size_dict, arrays,
backend="cupy", return_info=True,
)
# For an asynchronous device backend, use synchronization or event timing from the corresponding library
Install external-execution dependencies with arctn[execution]. Install CuPy, PyTorch, JAX, and their CUDA/runtime versions for your target hardware yourself; ArcTN does not select compatible distributions of these libraries.