Optimizing paths with Heavy

Call Heavy, read contraction paths, objective values, and timings, and save the resulting plan.

On this page

First prepare the example network structure, dimensions, and numerical arrays from Tensor-network input in Quick start.

Running Heavy and keeping its report

After installing the full wheel containing Light / Heavy, reuse the network in Quick start, or supply your own inputs, output, and size_dict.

Save the network definition and the call below as heavy_example.py, and set the thread count when launching it:

bash
RAYON_NUM_THREADS=24 python heavy_example.py

Obtaining the result

arctn_schedule optimizes the contraction order without executing numerical arrays. Its report is a Python dictionary containing the path, metrics, and optional slicing information.

python
from arctn import arctn_schedule

report = arctn_schedule(
    inputs, output, size_dict,
    preset="heavy", seed=17,
    use_ssa=True,
)

path = report["path"]
print(report["log10_flops"])
print(report["log2_read_write"])
print(report["planner_objective_score_log2"])

Heavy uses a larger search budget to seek better paths. It is still heuristic: it returns the best completed candidate from the current run, with no guarantee of local or global optimality or of outperforming Light every time.

Reading the result

The default objective is F+64RF+64R. When comparing searches on the same network with the same weights, read planner_objective_score_log2; FLOPs alone do not capture this weighted objective.

Path and objective fields

Field Meaning
path, path_format Final path and encoding; defaults to linear-v1, while the example uses ssa-v1
planner_objective Optimization objective name
flops_weight, read_write_weight Objective weights for this call
planner_objective_score_log2 Base-2 logarithm of the final objective, including all slices when sliced
log10_flops, log2_read_write Work and read/write volume of the final path on the unsliced network, in base-10 and base-2 logarithms respectively
log2_max_size Base-2 logarithm of the largest binary contraction result element count on the unsliced path
log2_max_contraction_size Base-2 logarithm of the largest sum of logical input and result elements in one unsliced-path step
log2_total_size, log2_peak_size Base-2 logarithms of total writes and peak live elements on the unsliced path
wall_s Search time in seconds recorded by the Light / Heavy compiled library; excludes subsequent array execution

Integers in path are tensor IDs interpreted according to path_format; integers in sliced_legs are internal index IDs. See Contraction trees and paths for the two path formats.

Path metrics are computed from network structure and dimensions, not measured execution time or process memory. See Path metrics and optimization objective for the formulas.

Slicing fields

The example does not set target_size. To limit per-slice intermediates, configure slicing as in Controlling intermediates, then read these fields:

Field Meaning
sliced_legs Internal integer IDs of sliced indices
log2_n_slices Base-2 logarithm of the slice count
sliced_log10_flops_total Base-10 logarithm of total FLOPs across all slices
sliced_log2_max_size Base-2 logarithm of the largest binary contraction result element count per slice
planner_log2_read_write Base-2 logarithm of total read/write volume across all slices
target_size Requested maximum result element count per slice
memory_constraint_metric Definition of the size constraint
max_intermediate_log2_elements_per_slice Base-2 logarithm of the final largest result element count per slice

sliced_legs lists which indices are sliced; its length is not the slice count. One index of dimension 4, for example, produces 4 slices and log2_n_slices equal to 2.

Without target_size, sliced_legs is empty, log2_n_slices is 0, some sliced_* fields are absent, and max_intermediate_log2_elements_per_slice is None. Even with target_size, slicing may not be needed; bool(report["sliced_legs"]) indicates whether any indices were actually selected.

Check the size constraint using the per-slice size, not the unsliced log2_max_size. Compare total work with sliced_log10_flops_total and planner_log2_read_write; planner_objective_score_log2 already includes the objective across all slices using the current weights.

Setting threads and reading timings

The example calls Heavy once. RAYON_NUM_THREADS=24 gives 3 independent search starts sharing 24 worker threads; no outer seed loop is needed. seed=17 sets the base seed, and the library derives the others. This setting does not reserve 24 physical cores. See Recommended thread configurations for 8, 16, and 32 threads.

Read the search time:

python
print("Search time (seconds):", report["wall_s"])

Internal candidate lists, stage records, and independent-start reports are not public return fields. To time the entire Python call, use time.perf_counter() around it; that covers a different interval from the search time recorded by the compiled library.

Saving the contraction plan

Given report, use ArcTNExecutionPlan.from_schedule to save the network, SSA path, and slicing information without searching again:

python
from arctn import ArcTNExecutionPlan

plan = ArcTNExecutionPlan.from_schedule(
    report, inputs=inputs, output=output, size_dict=size_dict,
)
plan.save("plan.json")

Subsequent execution and reuse

See Saving and reusing paths for loading files, executing contractions, and updating arrays. To pass paths to other tools, see Path representations and persistence.