Skip to content

Index

AODClusterTargetGenerator dataclass

AODClusterTargetGenerator()

Bases: TargetGeneratorABC


              flowchart TD
              bloqade.lanes.heuristics.physical.AODClusterTargetGenerator[AODClusterTargetGenerator]
              bloqade.lanes.heuristics.physical.target_generator.TargetGeneratorABC[TargetGeneratorABC]

                              bloqade.lanes.heuristics.physical.target_generator.TargetGeneratorABC --> bloqade.lanes.heuristics.physical.AODClusterTargetGenerator
                


              click bloqade.lanes.heuristics.physical.AODClusterTargetGenerator href "" "bloqade.lanes.heuristics.physical.AODClusterTargetGenerator"
              click bloqade.lanes.heuristics.physical.target_generator.TargetGeneratorABC href "" "bloqade.lanes.heuristics.physical.target_generator.TargetGeneratorABC"
            

Choose CZ directions to maximise AOD-shot packing.

For each CZ pair, enumerate both direction candidates (control-moves or target-moves) and classify each by the (move_type, zone_id, bus_id, direction) signature of its first path hop — the same signature the downstream move scheduler uses to batch lanes into one AOD shot. Directions are then assigned greedily: the signature appearing in the most candidate first-hops is filled first, then the next largest, and so on. When no further clustering gain is possible (largest remaining bucket has a single unresolved pair), remaining pairs default to control-direction for parity with :class:DefaultTargetGenerator.

Rationale: CongAware rewards same-direction lane reuse per edge via a Dijkstra weight. That is a local proxy for shot-sharing; the scheduler actually batches by the 4-tuple above, not by individual lane reuse. Choosing CZ directions that align first-hops on shared signatures produces targets the scheduler can pack more tightly.

CongestionAwareTargetGenerator dataclass

CongestionAwareTargetGenerator(
    direction_factor: float = 0.5,
    shared_site_factor: float = 1.1,
)

Bases: TargetGeneratorABC


              flowchart TD
              bloqade.lanes.heuristics.physical.CongestionAwareTargetGenerator[CongestionAwareTargetGenerator]
              bloqade.lanes.heuristics.physical.target_generator.TargetGeneratorABC[TargetGeneratorABC]

                              bloqade.lanes.heuristics.physical.target_generator.TargetGeneratorABC --> bloqade.lanes.heuristics.physical.CongestionAwareTargetGenerator
                


              click bloqade.lanes.heuristics.physical.CongestionAwareTargetGenerator href "" "bloqade.lanes.heuristics.physical.CongestionAwareTargetGenerator"
              click bloqade.lanes.heuristics.physical.target_generator.TargetGeneratorABC href "" "bloqade.lanes.heuristics.physical.target_generator.TargetGeneratorABC"
            

Joint, longest-first, congestion-aware target generator.

For each CZ pair, picks whether to move the control or the target based on schedule-time cost computed against a working placement that reflects all prior pairs' committed moves and a running directional congestion record.

Per-lane weighting composes two orthogonal multiplicative factors (see :func:_make_weight_fn):

  • direction_factor ** (N - M) — signed net of same-direction (N) minus opposite-direction (M) prior commits on the lane. With direction_factor < 1, net-positive traffic rewards AOD-parallel reuse and net-negative traffic penalises contention; balanced traffic (N == M) is neutral.
  • shared_site_factor — applied whenever an endpoint of the candidate lane is a site a prior committed path already traversed. Applies independently of direction_factor; the two signals compose multiplicatively.

Dijkstra requires non-negative edge weights. direction_factor must be strictly positive (the negative exponent is otherwise undefined); shared_site_factor must be >= 0. Defaults reflect the canonical tuning; empirical retuning is a follow-up.

DefaultTargetGenerator dataclass

DefaultTargetGenerator()

Bases: TargetGeneratorABC


              flowchart TD
              bloqade.lanes.heuristics.physical.DefaultTargetGenerator[DefaultTargetGenerator]
              bloqade.lanes.heuristics.physical.target_generator.TargetGeneratorABC[TargetGeneratorABC]

                              bloqade.lanes.heuristics.physical.target_generator.TargetGeneratorABC --> bloqade.lanes.heuristics.physical.DefaultTargetGenerator
                


              click bloqade.lanes.heuristics.physical.DefaultTargetGenerator href "" "bloqade.lanes.heuristics.physical.DefaultTargetGenerator"
              click bloqade.lanes.heuristics.physical.target_generator.TargetGeneratorABC href "" "bloqade.lanes.heuristics.physical.target_generator.TargetGeneratorABC"
            

Default rule: control qubit moves to the CZ partner of the target's location.

NoHomePlacementStrategy dataclass

NoHomePlacementStrategy(
    arch_spec: ArchSpec,
    strategy: SearchStrategy = (
        lambda: SearchStrategy.IDS
    )(),
    max_expansions: int | None = 100,
    restarts: int = 20,
    deadlock_policy: DeadlockPolicy = (
        lambda: DeadlockPolicy.MOVE_BLOCKERS
    )(),
    top_c: int | None = None,
    gamma: float = 0.85,
    lambda_lookahead: float = 0.5,
    k_candidates: int = 8,
    top_bus_signatures: int = 6,
    bus_reward_rho: int = 1,
)

Bases: NoReturnStrategyBase


              flowchart TD
              bloqade.lanes.heuristics.physical.NoHomePlacementStrategy[NoHomePlacementStrategy]
              bloqade.lanes.heuristics.physical._no_return_base.NoReturnStrategyBase[NoReturnStrategyBase]
              bloqade.lanes.analysis.placement.strategy.PlacementStrategyABC[PlacementStrategyABC]

                              bloqade.lanes.heuristics.physical._no_return_base.NoReturnStrategyBase --> bloqade.lanes.heuristics.physical.NoHomePlacementStrategy
                                bloqade.lanes.analysis.placement.strategy.PlacementStrategyABC --> bloqade.lanes.heuristics.physical._no_return_base.NoReturnStrategyBase
                



              click bloqade.lanes.heuristics.physical.NoHomePlacementStrategy href "" "bloqade.lanes.heuristics.physical.NoHomePlacementStrategy"
              click bloqade.lanes.heuristics.physical._no_return_base.NoReturnStrategyBase href "" "bloqade.lanes.heuristics.physical._no_return_base.NoReturnStrategyBase"
              click bloqade.lanes.analysis.placement.strategy.PlacementStrategyABC href "" "bloqade.lanes.analysis.placement.strategy.PlacementStrategyABC"
            

Two-phase placement: return assignment + entangling routing.

Parameters

arch_spec: Architecture specification. strategy: Inner search strategy as a :class:SearchStrategy enum used for the two routing phases. Default 🇵🇾attr:SearchStrategy.IDS. max_expansions: Maximum node expansions per solve call (shared across phases). restarts: Number of parallel restarts with perturbed scoring inside each routing solve (return phase + entangling phase). The two-phase Hungarian assignments themselves are deterministic; diversity comes from the candidate-home-layout fan-out. Default 20. deadlock_policy: :class:DeadlockPolicy enum value controlling how the heuristic generator handles deadlocks during routing. Default 🇵🇾attr:DeadlockPolicy.MOVE_BLOCKERS. gamma: Discount factor for future CZ layer weights in the return assignment (default 0.85). lambda_lookahead: Blend weight for future proximity penalty in the return assignment (default 0.5). k_candidates: Maximum candidate holes per returner for cost-matrix pruning (default 8). top_bus_signatures: Number of bus-reward variant assignments to generate (default 6). Each variant rewards edges sharing a high-coverage lane signature, biasing the assignment toward layouts with parallel routing. bus_reward_rho: Per-edge hop-count discount applied to edges using a top signature when building bus-reward variant cost matrices (default 1).

Notes

Unlike :class:NoReturnPlacementStrategy and :class:RecedingHorizonNoReturnPlacementStrategy, this strategy does not pass top_c to SolveOptions (it inherits the base default None), matching the historical behaviour of the two-phase solve_nohome entry point.

NoReturnPlacementStrategy dataclass

NoReturnPlacementStrategy(
    arch_spec: ArchSpec,
    strategy: SearchStrategy = (
        lambda: SearchStrategy.IDS
    )(),
    max_expansions: int | None = 100,
    restarts: int = 20,
    deadlock_policy: DeadlockPolicy = (
        lambda: DeadlockPolicy.MOVE_BLOCKERS
    )(),
    top_c: int | None = 3,
    congestion_weight: float = 0.0,
    occupancy_penalty: float = 1.0,
    hungarian_horizon: int | None = 4,
)

Bases: NoReturnStrategyBase


              flowchart TD
              bloqade.lanes.heuristics.physical.NoReturnPlacementStrategy[NoReturnPlacementStrategy]
              bloqade.lanes.heuristics.physical._no_return_base.NoReturnStrategyBase[NoReturnStrategyBase]
              bloqade.lanes.analysis.placement.strategy.PlacementStrategyABC[PlacementStrategyABC]

                              bloqade.lanes.heuristics.physical._no_return_base.NoReturnStrategyBase --> bloqade.lanes.heuristics.physical.NoReturnPlacementStrategy
                                bloqade.lanes.analysis.placement.strategy.PlacementStrategyABC --> bloqade.lanes.heuristics.physical._no_return_base.NoReturnStrategyBase
                



              click bloqade.lanes.heuristics.physical.NoReturnPlacementStrategy href "" "bloqade.lanes.heuristics.physical.NoReturnPlacementStrategy"
              click bloqade.lanes.heuristics.physical._no_return_base.NoReturnStrategyBase href "" "bloqade.lanes.heuristics.physical._no_return_base.NoReturnStrategyBase"
              click bloqade.lanes.analysis.placement.strategy.PlacementStrategyABC href "" "bloqade.lanes.analysis.placement.strategy.PlacementStrategyABC"
            

No-return placement via the loose-goal entangling constraint solver.

Calls :pymethod:MoveSolver.solve_entangling once per CZ layer to find both the entangling placement and the routing simultaneously. Each layer's output layout is passed as the next layer's input, saving the cost of palindrome return moves.

Parameters

arch_spec: Architecture specification. strategy: Inner search strategy as a :class:SearchStrategy enum (e.g. 🇵🇾attr:SearchStrategy.IDS (default), 🇵🇾attr:SearchStrategy.ASTAR, 🇵🇾attr:SearchStrategy.ENTROPY). max_expansions: Maximum node expansions per solve call. restarts: Number of parallel restarts with perturbed scoring. Each restart gets a different seed for the greedy CZ-pair-to-slot assignment, producing diverse target layouts; pick_best keeps the lowest- cost result. Default 20. deadlock_policy: :class:DeadlockPolicy enum value (default 🇵🇾attr:DeadlockPolicy.MOVE_BLOCKERS). top_c: Per-qubit move-candidate pruning cap inside HeuristicGenerator. None keeps all scored bus options. Default 3 matches the previously-hardcoded behaviour. Larger values broaden the search but slow per-node expansion. congestion_weight: Penalty weight for the entangling Hungarian assignment to spread CZ pairs across word pairs. 0.0 (default) uses standard min-sum assignment; positive values reduce routing serialization at high occupancy at some cost in total atom moves. occupancy_penalty: Per-slot-half penalty (in lane-hop units) added to the Hungarian cost for slots currently held by spectator atoms (atoms not in any CZ pair of the current layer). Steers the assignment away from slots that would force the search to evict a non-participating atom. 0.0 recovers the legacy occupancy-blind behaviour. Default 1.0 was tuned on the 80q / depth 3 / max_pairs 10 regime; deeper sparse-pair circuits prefer larger values (~2–3). hungarian_horizon: Cap on the number of future CZ layers fed to the Hungarian forward/backward sweep. 0 disables lookahead entirely; None is unbounded (all future layers). Default 4 keeps solve time bounded regardless of circuit depth.

NoReturnStrategyBase dataclass

NoReturnStrategyBase(
    arch_spec: ArchSpec,
    strategy: SearchStrategy = (
        lambda: SearchStrategy.IDS
    )(),
    max_expansions: int | None = 100,
    restarts: int = 1,
    deadlock_policy: DeadlockPolicy = (
        lambda: DeadlockPolicy.MOVE_BLOCKERS
    )(),
    top_c: int | None = None,
)

Bases: PlacementStrategyABC


              flowchart TD
              bloqade.lanes.heuristics.physical.NoReturnStrategyBase[NoReturnStrategyBase]
              bloqade.lanes.analysis.placement.strategy.PlacementStrategyABC[PlacementStrategyABC]

                              bloqade.lanes.analysis.placement.strategy.PlacementStrategyABC --> bloqade.lanes.heuristics.physical.NoReturnStrategyBase
                


              click bloqade.lanes.heuristics.physical.NoReturnStrategyBase href "" "bloqade.lanes.heuristics.physical.NoReturnStrategyBase"
              click bloqade.lanes.analysis.placement.strategy.PlacementStrategyABC href "" "bloqade.lanes.analysis.placement.strategy.PlacementStrategyABC"
            

Abstract base for Rust-solver-driven no-return placement strategies.

Parameters

arch_spec: Architecture specification (inherited from :class:PlacementStrategyABC). Must expose exactly one CZ-capable zone; multi-zone CZ scheduling is not yet supported. strategy: Inner search strategy as a :class:SearchStrategy enum (e.g. 🇵🇾attr:SearchStrategy.IDS, 🇵🇾attr:SearchStrategy.ASTAR, 🇵🇾attr:SearchStrategy.ENTROPY, …). Passing a typo'd value fails at construction rather than at solve time. Default 🇵🇾attr:SearchStrategy.IDS. max_expansions: Maximum node expansions per solve call. None means unbounded. restarts: Number of parallel restarts with perturbed scoring inside each Rust solve. Subclasses override the default where appropriate. deadlock_policy: :class:DeadlockPolicy enum value: 🇵🇾attr:DeadlockPolicy.SKIP, 🇵🇾attr:DeadlockPolicy.MOVE_BLOCKERS (default), or 🇵🇾attr:DeadlockPolicy.ALL_MOVES. top_c: Per-qubit move-candidate pruning cap inside HeuristicGenerator. None keeps all scored bus options (default for this base — subclasses such as :class:NoReturnPlacementStrategy override to 3 to match their historical behaviour).

Notes

Subclasses are expected to be :func:dataclasses.dataclass-decorated, add their strategy-specific options as additional fields (with defaults so the inherited arch_spec field stays the only required init argument), and implement :meth:_invoke_solver.

rust_nodes_expanded_total property

rust_nodes_expanded_total: int

Total Rust solver node expansions for this strategy instance.

Mirrors :pyattr:PhysicalPlacementStrategy.rust_nodes_expanded_total. Accumulates across all cz_placements calls on the instance.

PhysicalLayoutHeuristicGraphPartitionCenterOut dataclass

PhysicalLayoutHeuristicGraphPartitionCenterOut(
    arch_spec: ArchSpec = get_physical_layout_arch_spec(),
    max_words: int | None = None,
    u_factor: int = 1,
    partitioner_seed: int = 0,
)

Bases: LayoutHeuristicABC


              flowchart TD
              bloqade.lanes.heuristics.physical.PhysicalLayoutHeuristicGraphPartitionCenterOut[PhysicalLayoutHeuristicGraphPartitionCenterOut]
              bloqade.lanes.analysis.layout.analysis.LayoutHeuristicABC[LayoutHeuristicABC]

                              bloqade.lanes.analysis.layout.analysis.LayoutHeuristicABC --> bloqade.lanes.heuristics.physical.PhysicalLayoutHeuristicGraphPartitionCenterOut
                


              click bloqade.lanes.heuristics.physical.PhysicalLayoutHeuristicGraphPartitionCenterOut href "" "bloqade.lanes.heuristics.physical.PhysicalLayoutHeuristicGraphPartitionCenterOut"
              click bloqade.lanes.analysis.layout.analysis.LayoutHeuristicABC href "" "bloqade.lanes.analysis.layout.analysis.LayoutHeuristicABC"
            

home_word_ids property

home_word_ids: tuple[int, ...]

Home words for one-zone physical layout.

Uses the arch-level home-word computation from zone entangling pairs.

sites_per_partition property

sites_per_partition: int

Maximum number of qubits placed per home word.

compute_layout

compute_layout(
    all_qubits: tuple[int, ...],
    stages: list[tuple[tuple[int, int], ...]],
    pinned: dict[int, LocationAddress] | None = None,
) -> tuple[LocationAddress, ...]

Compute the initial qubit layout from circuit stages.

Parameters:

Name Type Description Default
all_qubits tuple[int, ...]

Tuple of logical qubit indices to be mapped.

required
stages list[tuple[tuple[int, int], ...]]

List of circuit stages, where each stage is a tuple of (control, target) qubit pairs representing two-qubit gates.

required
pinned dict[int, LocationAddress] | None

Map from logical qubit ID to pre-pinned LocationAddress. Implementations MUST place each pinned qubit at its requested address and MUST NOT use any address in pinned.values() for un-pinned qubits. None or empty preserves previous behavior. All values in pinned MUST be valid home positions for the architecture (i.e. present in arch_spec.home_sites); passing an out-of-arch address raises ValueError.

None

Returns:

Type Description
LocationAddress

A tuple of LocationAddress objects mapping logical qubit indices

...

to physical locations. Pinned IDs return their pinned address;

tuple[LocationAddress, ...]

un-pinned IDs return the heuristic's choice. Raises if no legal

tuple[LocationAddress, ...]

layout exists.

Source code in .venv/lib/python3.12/site-packages/bloqade/lanes/heuristics/physical/layout.py
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
def compute_layout(
    self,
    all_qubits: tuple[int, ...],
    stages: list[tuple[tuple[int, int], ...]],
    pinned: dict[int, LocationAddress] | None = None,
) -> tuple[LocationAddress, ...]:
    pinned = {} if pinned is None else pinned
    if len(set(pinned.values())) < len(pinned):
        raise ValueError(
            "pinned addresses must be unique; two qubit IDs share the same address"
        )
    extra_keys = set(pinned) - set(all_qubits)
    if extra_keys:
        raise ValueError(
            f"pinned contains qubit IDs not in all_qubits: {sorted(extra_keys)}"
        )
    self._validate_pinned_in_arch(pinned, self.arch_spec)
    qubits = tuple(sorted(all_qubits))
    cz_layers = _to_cz_layers(stages)
    return self._compute_layout_from_cz_layers(qubits, cz_layers, pinned)

PhysicalPlacementStrategy dataclass

PhysicalPlacementStrategy(
    arch_spec: ArchSpec = get_physical_arch_spec(),
    traversal: RustPlacementTraversal = (
        lambda: RustPlacementTraversal(strategy="entropy")
    )(),
    target_generator: (
        TargetGeneratorABC | TargetGeneratorCallable | None
    ) = None,
)

Bases: PlacementStrategyABC


              flowchart TD
              bloqade.lanes.heuristics.physical.PhysicalPlacementStrategy[PhysicalPlacementStrategy]
              bloqade.lanes.analysis.placement.strategy.PlacementStrategyABC[PlacementStrategyABC]

                              bloqade.lanes.analysis.placement.strategy.PlacementStrategyABC --> bloqade.lanes.heuristics.physical.PhysicalPlacementStrategy
                


              click bloqade.lanes.heuristics.physical.PhysicalPlacementStrategy href "" "bloqade.lanes.heuristics.physical.PhysicalPlacementStrategy"
              click bloqade.lanes.analysis.placement.strategy.PlacementStrategyABC href "" "bloqade.lanes.analysis.placement.strategy.PlacementStrategyABC"
            

Physical placement strategy backed by the Rust MoveSolver.

rust_entropy_fallback_count property

rust_entropy_fallback_count: int

Number of solved Rust entropy stages that used sequential fallback.

rust_nodes_expanded_total property

rust_nodes_expanded_total: int

Total Rust solver node expansions for this strategy instance.

traced_blocked_locations property

traced_blocked_locations: tuple[LocationAddress, ...]

Spectator atom positions for the traced CZ layer (atoms not in the active placement).

traced_target property

traced_target: dict[int, LocationAddress]

First candidate target for the traced CZ layer (used by visualizers).

RecedingHorizonNoReturnPlacementStrategy dataclass

RecedingHorizonNoReturnPlacementStrategy(
    arch_spec: ArchSpec,
    strategy: SearchStrategy = (
        lambda: SearchStrategy.IDS
    )(),
    max_expansions: int | None = 100,
    restarts: int = 1,
    deadlock_policy: DeadlockPolicy = (
        lambda: DeadlockPolicy.MOVE_BLOCKERS
    )(),
    top_c: int | None = 3,
    congestion_weight: float = 0.0,
    occupancy_penalty: float = 1.0,
    hungarian_horizon: int | None = 4,
    k_candidates: int = 5,
    rollout_horizon: int = 5,
    commit_depth: int = 3,
    tier0_next_h_weight: float = 0.5,
    weight_grid: (
        tuple[tuple[float, float], ...] | None
    ) = None,
    fallback_x_decrement: int = 1,
    branch_parallel: bool = True,
    max_expansions_per_rollout: int = 300,
    greedy_first: bool = True,
    inner_beam_width: int = 2,
)

Bases: NoReturnStrategyBase


              flowchart TD
              bloqade.lanes.heuristics.physical.RecedingHorizonNoReturnPlacementStrategy[RecedingHorizonNoReturnPlacementStrategy]
              bloqade.lanes.heuristics.physical._no_return_base.NoReturnStrategyBase[NoReturnStrategyBase]
              bloqade.lanes.analysis.placement.strategy.PlacementStrategyABC[PlacementStrategyABC]

                              bloqade.lanes.heuristics.physical._no_return_base.NoReturnStrategyBase --> bloqade.lanes.heuristics.physical.RecedingHorizonNoReturnPlacementStrategy
                                bloqade.lanes.analysis.placement.strategy.PlacementStrategyABC --> bloqade.lanes.heuristics.physical._no_return_base.NoReturnStrategyBase
                



              click bloqade.lanes.heuristics.physical.RecedingHorizonNoReturnPlacementStrategy href "" "bloqade.lanes.heuristics.physical.RecedingHorizonNoReturnPlacementStrategy"
              click bloqade.lanes.heuristics.physical._no_return_base.NoReturnStrategyBase href "" "bloqade.lanes.heuristics.physical._no_return_base.NoReturnStrategyBase"
              click bloqade.lanes.analysis.placement.strategy.PlacementStrategyABC href "" "bloqade.lanes.analysis.placement.strategy.PlacementStrategyABC"
            

No-return placement using a receding-horizon orchestration.

Differs from :class:NoReturnPlacementStrategy in that it does not commit to one Hungarian assignment up front. Instead, at each stage:

  1. Generates k_candidates diverse Hungarian candidates from the current state (using the configured weight_grid).
  2. Runs each candidate forward for rollout_horizon move layers via the existing IDS infrastructure.
  3. Picks the best branch by stratified score (tier-0: goal reached mid-rollout; tier-1: completed full horizon; tier-2: dropped).
  4. Commits the full path of a tier-0 winner, or the first commit_depth layers of a tier-1 winner, then re-plans.

Positioning

Use this strategy when atom density is high and the baseline no-return loose-goal solver under-uses parallelism (the "1.23 vs 1.49 lanes/layer" gap flagged in the PR description). In low-density regimes, most rollouts will hit the constraint goal before depth x, collapsing the algorithm to "K parallel searches, pick the shortest" — which the baseline restart mechanism already does more cheaply.

Parameters

arch_spec Architecture specification. strategy Inner search strategy used for rollouts as a :class:SearchStrategy enum. Default 🇵🇾attr:SearchStrategy.IDS (the orchestration is tuned for IDS; other values still work but aren't routinely exercised). max_expansions Optional cap on total node expansions across all stages of one restart's trajectory. restarts Number of parallel restart trajectories. Each restart runs its own independent receding-horizon solve with a distinct seed; the lowest-cost trajectory wins. For evaluation, use restarts=1 to isolate the algorithm from the orthogonal restart-parallelism axis; the design's intended high-density-regime gains should be visible per-restart. congestion_weight, occupancy_penalty, hungarian_horizon Underlying Hungarian cost-matrix knobs passed to every candidate generation call (same semantics as :class:NoReturnPlacementStrategy). The weight_grid varies congestion_weight and occupancy_penalty per candidate; these field values are used by the noise top-up fallback when the grid produces fewer than k_candidates unique assignments. top_c Per-qubit move-candidate pruning cap inside HeuristicGenerator (same as the base no-return strategy). deadlock_policy :class:DeadlockPolicy enum value (default 🇵🇾attr:DeadlockPolicy.MOVE_BLOCKERS). k_candidates K: number of Hungarian candidates tried per stage. Default 5. rollout_horizon x: maximum number of move layers each branch's inner search explores. Default 5. commit_depth m: number of layers from the winning tier-1 branch's path that get committed before re-planning. Must satisfy 1 <= commit_depth <= rollout_horizon. Tier-0 winners (rollouts that reached the goal) always commit their full path regardless of this value. Default 3. tier0_next_h_weight α: weight on next-layer Hungarian cost when ranking tier-0 branches. 0.0 ignores next-layer setup; higher values trade current-layer commitment depth for better next-layer staging. Default 0.5. weight_grid Sequence of (congestion_weight, occupancy_penalty) tuples used to generate K candidates per stage. None uses a default 10- entry grid spanning congestion ∈ {0, 0.5, 1, 2, 5} × occupancy ∈ {0.5, 2.0}. fallback_x_decrement When all K branches drop (tier-2) at the current horizon, retry the stage with x ← x − decrement. Default 1. branch_parallel Run the K rollouts in parallel via rayon within a stage. Default True. When restarts > 1, set False to reserve cores for restart parallelism. max_expansions_per_rollout Per-rollout expansion budget. Caps any single rollout to bound runaway. Default 300. greedy_first, inner_beam_width Inner-rollout cheap-beam-then-IDS knobs. See the Rust struct RecedingHorizonOptions doc for details.

RustPlacementTraversal dataclass

RustPlacementTraversal(
    strategy: SearchStrategyName = "entropy",
    max_movesets_per_group: int = 3,
    max_goal_candidates: int = 3,
    max_expansions: int | None = 300,
    restarts: int = 1,
    lookahead: bool = False,
    collect_entropy_trace: bool = False,
)

Config for the Rust MoveSolver.

restarts and lookahead are now exposed and threaded into SolveOptions; per-strategy entropy knobs (max_movesets_per_group, max_goal_candidates, collect_entropy_trace) feed EntropyOptions via :func:solve_options_from_traversal.

Not yet exposed (Rust defaults used): weight, deadlock_policy, w_t. These will be threaded through once validated via Rust-only benchmarking.

TargetContext dataclass

TargetContext(
    arch_spec: ArchSpec,
    state: ConcreteState,
    controls: tuple[int, ...],
    targets: tuple[int, ...],
    lookahead_cz_layers: tuple[
        tuple[tuple[int, ...], tuple[int, ...]], ...
    ],
    cz_stage_index: int,
)

Signals passed to a TargetGenerator.

Composes ConcreteState to avoid duplicating lattice state fields.

TargetGeneratorABC

Bases: ABC


              flowchart TD
              bloqade.lanes.heuristics.physical.TargetGeneratorABC[TargetGeneratorABC]

              

              click bloqade.lanes.heuristics.physical.TargetGeneratorABC href "" "bloqade.lanes.heuristics.physical.TargetGeneratorABC"
            

Plugin interface for choosing the target configuration of a CZ stage.

Implementations return an ordered list of candidate target placements. The strategy framework appends the default candidate (DefaultTargetGenerator) as a guaranteed last-resort, so a plugin may return [] to defer entirely to the default.

make_physical_placement_strategy

make_physical_placement_strategy(
    *,
    move_solutions_per_layer: int = 3,
    search_budget: int | None = 300,
    strategy: SearchStrategyName = "entropy",
    arch_spec: ArchSpec | None = None,
    return_moves: bool = True,
    target_generator: (
        TargetGeneratorABC | TargetGeneratorCallable | None
    ) = None
) -> PlacementStrategyABC

Build a physical placement strategy from user-facing search knobs.

move_solutions_per_layer maps to the Rust solver's max_goal_candidates. search_budget maps to the per-CZ-stage max_expansions budget shared across target candidates.

Source code in .venv/lib/python3.12/site-packages/bloqade/lanes/heuristics/physical/movement.py
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
def make_physical_placement_strategy(
    *,
    move_solutions_per_layer: int = 3,
    search_budget: int | None = 300,
    strategy: SearchStrategyName = "entropy",
    arch_spec: ArchSpec | None = None,
    return_moves: bool = True,
    target_generator: TargetGeneratorABC | TargetGeneratorCallable | None = None,
) -> PlacementStrategyABC:
    """Build a physical placement strategy from user-facing search knobs.

    ``move_solutions_per_layer`` maps to the Rust solver's
    ``max_goal_candidates``. ``search_budget`` maps to the per-CZ-stage
    ``max_expansions`` budget shared across target candidates.
    """
    if move_solutions_per_layer < 1:
        raise ValueError("move_solutions_per_layer must be >= 1")
    if search_budget is not None and search_budget < 1:
        raise ValueError("search_budget must be None or >= 1")

    inner = PhysicalPlacementStrategy(
        arch_spec=get_physical_arch_spec() if arch_spec is None else arch_spec,
        traversal=RustPlacementTraversal(
            strategy=strategy,
            max_goal_candidates=move_solutions_per_layer,
            max_expansions=search_budget,
        ),
        target_generator=target_generator,
    )

    return PalindromePlacementStrategy(inner=inner) if return_moves else inner