Placement
PhysicalPlacementStrategy
dataclass
PhysicalPlacementStrategy(
arch_spec: ArchSpec = get_physical_arch_spec(),
traversal: RustPlacementTraversal = (
lambda: RustPlacementTraversal(strategy="entropy")
)(),
target_generator: (
TargetGeneratorABC | TargetGeneratorCallable | None
) = None,
)
Bases: MoveToPlacementStrategyABC
flowchart TD
bloqade.lanes.heuristics.physical.placement.PhysicalPlacementStrategy[PhysicalPlacementStrategy]
bloqade.lanes.analysis.placement.strategy.MoveToPlacementStrategyABC[MoveToPlacementStrategyABC]
bloqade.lanes.analysis.placement.strategy.PlacementStrategyABC[PlacementStrategyABC]
bloqade.lanes.analysis.placement.strategy.MoveToPlacementStrategyABC --> bloqade.lanes.heuristics.physical.placement.PhysicalPlacementStrategy
bloqade.lanes.analysis.placement.strategy.PlacementStrategyABC --> bloqade.lanes.analysis.placement.strategy.MoveToPlacementStrategyABC
click bloqade.lanes.heuristics.physical.placement.PhysicalPlacementStrategy href "" "bloqade.lanes.heuristics.physical.placement.PhysicalPlacementStrategy"
click bloqade.lanes.analysis.placement.strategy.MoveToPlacementStrategyABC href "" "bloqade.lanes.analysis.placement.strategy.MoveToPlacementStrategyABC"
click bloqade.lanes.analysis.placement.strategy.PlacementStrategyABC href "" "bloqade.lanes.analysis.placement.strategy.PlacementStrategyABC"
Physical placement strategy backed by the Rust TargetSolver.
rust_bound_stats_total
property
rust_bound_stats_total: dict[str, float]
Branch-and-bound pruning statistics summed over every solve.
Counters and depth sums add; the per-instance root_lower_bound /
incumbent_cost / gap do not aggregate meaningfully across solves, so
the widest observed gap is kept as max_optimality_gap instead.
Empty — not zeroed — before the first solve, and after any number of
solves run with :pyattr:RustPlacementTraversal.completion_bound set to
None: an unbounded run measured nothing, and reporting zeros would
be indistinguishable from a bounded run that pruned nothing. Key-check
rather than expecting the keys to exist.
rust_entropy_fallback_count
property
rust_entropy_fallback_count: int
Number of solved Rust entropy stages that used the budget-exhaustion fallback (Push and Rotate, with the greedy sequential router as the out-of-regime tertiary).
rust_nodes_expanded_total
property
rust_nodes_expanded_total: int
Total Rust solver node expansions for this strategy instance.
rust_proven_total
property
rust_proven_total: int
Solves whose plan the bound proved optimal.
Read against the solve count rather than alone: False on a solve
means unproven, not suboptimal.
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).
compute_moves
compute_moves(
state_before: ConcreteState, state_after: ConcreteState
) -> tuple[tuple[LaneAddress, ...], ...]
Route atoms between two fixed layouts for user-directed MoveTo.
Delegates to the shared compute_move_layers primitive, passing this
strategy's own traversal and cached :class:SearchEngine so MoveTo
routing uses the same search configuration and per-arch lane index as
cz_placements (the docstring on compute_move_layers notes the two
callsites are meant to share a traversal).
The import is deferred to call time: heuristics.move_synthesis
imports this module, so a top-level import would be a cycle.
Source code in .venv/lib/python3.12/site-packages/bloqade/lanes/heuristics/physical/movement.py
501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 | |
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,
seed: int = 0,
bound_terminates: bool = True,
completion_bound: str | None = None,
block_spectators: bool = True,
)
Config for the Rust search engine (TargetSolver).
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:_move_search_from_traversal.
Not yet exposed (Rust defaults used): weight, deadlock_policy,
w_t. These will be threaded through once validated via Rust-only
benchmarking.
block_spectators
class-attribute
instance-attribute
block_spectators: bool = True
Scope each CZ solve to the participating qubits.
When True (default), qubits not in the CZ's controls/targets are
treated as blocked obstacles for that solve rather than free atoms to route.
This keeps the search effort independent of how many unrelated qubits share
the same merged StaticPlacement block (under always_merge every CZ
would otherwise search over all block qubits, inflating nodes_expanded).
Set False to let each CZ route over all block qubits. Note: blocking
spectators removes routing freedom, so for some strategies it can change
(sometimes increase) move counts (e.g. DFS may relocate a spectator to
shorten a participant's path); the search-effort reduction is not always
move-count-free.
bound_terminates
class-attribute
instance-attribute
bound_terminates: bool = True
Let the completion bound end the search once the plan is proven optimal.
On by default. The proof is the root certificate -- the plan's cost has
reached h(root), which lower-bounds every legal plan -- so it holds
without a complete generator, and the solve reports proven.
Stopping skips no expansion: a cut root cannot be expanded from, so what
it ends is a spin over already-cut nodes. False restores that spin and
is useful only for A/B measurement. Requires completion_bound; inert
without one.
completion_bound
class-attribute
instance-attribute
completion_bound: str | None = None
Admissible completion bound for branch-and-bound pruning.
None (default) prunes a branch only once its accumulated cost alone
reaches the incumbent's. "weighted_distance" additionally prunes when
g + h reaches it, where h is the max objective-weighted distance
over unresolved atoms. Affects which subtrees are explored, never candidate
generation, and never returns a worse plan.
Only consulted by the entropy strategy, and ignored for loose-goal (CZ pair) solves where the bound is not admissible.