qarp.cutting

QPD circuit cutting. Public depth: flat — the cut finders, the quasi-probability decomposition engine, shot post-processing and the per-gate decompositions. Submodules are private; CuttingPrimitive lives in qarp.algorithms.

class qarp.cutting.AutoCutFinder(commands: list, n_qubits: int, max_size_subcircuits: list, penalization_term: float, verbose: bool = True)[source]

Bases: ABC

abstractmethod cut(manual_setting: list | None = None)[source]

Find cut locations and partition the circuit into subcircuits.

Parameters:

manual_setting – Optional list of qubit-index lists, one per subcircuit.

Returns:

CutterResult

property cut_qc

2q _CutMarker command list (for decomposition iterator).

property subcircuit_qubits

Global qubit indices for each subcircuit.

property subcircuits

List of (commands, n_qubits) tuples for each subcircuit.

class qarp.cutting.CutterResult(cutter_obj: AutoCutFinder)[source]

Bases: object

Result of a circuit cutting operation.

class qarp.cutting.EAPartitioning(commands: list, n_qubits: int, max_size_subcircuits: list, verbose: bool = True)[source]

Bases: AutoCutFinder

cut(manual_setting: list | None = None) CutterResult[source]

Partition the circuit, returning a CutterResult.

Parameters:

manual_setting – If given, a list of qubit-index lists (one per subcircuit) that specifies the partition manually.

class qarp.cutting.PostProcessing(cutter_result: CutterResult, observable: QubitOperator, verbose: bool = True)[source]

Bases: ABC

property coefficients
abstractmethod compute(**kwargs) float[source]
abstractmethod decompose()[source]
property experiments
property jobs
class qarp.cutting.QPDDecomposition(cutter_result: CutterResult, observable: QubitOperator, verbose: bool = True, n_shots: int = 1024, experiment_fraction: float | None = None, rng_seed: int | None = None, shot_seed: int | None = None, force_max_number_cuts: bool = False, grouping: GroupingStrategy | None = None)[source]

Bases: PostProcessing

build_experiment_blocks_streaming() Tuple[list, list][source]

Stream experiments, build QWC-grouped sub-blocks for the engine.

Does NOT populate self.experiments or self.jobs.

compute(parallelize: bool = False, symbol_map: dict | None = None, **kwargs) float[source]

Execute experiments with QarpSimulator and return the expectation value.

Streams experiments one at a time (Plan 1). Peak memory is O(n_cuts × n_gates + n_subcircuits × local_n_qubits).

decompose() None[source]

Prepare observable metadata. No experiments are materialised.

self.coefficients is populated lazily on the first compute() call.

initialize_qubit_dict(n_qubits: int) dict[source]
property n_experiments: int

Number of experiments that will actually be executed.

normalize_SV_probs(SV: dict) dict[source]
overhead() float[source]
reconstruct_statevector(parallelize: bool = False) dict[source]

Reconstruct the statevector via shot simulation.

Plan 2: replaces itertools.product with incremental subcircuit folding. Peak memory is O(2^n_full_qubits) instead of O(outcomes^n_subcircuits). Streams experiments (Plan 1) — self.jobs is never required.

property sampling_strategy: str

the strategy that will be used for subsampling.

'top_k' if any cut is parametric (auto-selected), 'uniform' otherwise. Always 'uniform' when no subsampling is active.

Type:

Read-only

class qarp.cutting.Reconstructer(commands: list, n_qubits: int)[source]

Bases: object

reconstruct_delete_gates(to_delete: list) tuple[list, int][source]

Remove all 2q gates between qubit pairs listed in to_delete.

Parameters:

to_delete – List of [q0, q1] pairs; gates on these pairs are removed.

Returns:

pruned command list and number of removed gates.

Return type:

(new_commands, n_cuts)

static reconstruct_filter_qubits(commands: list, n_qubits: int, qubits: list) tuple[list, int][source]

Filter a command list to only include commands acting on qubits in the subset.

Qubit indices are remapped to be 0-based local indices within the subset. QPD Measure commands are kept and their cbit indices are re-assigned sequentially (0, 1, …) in the order they are encountered.

Parameters:
  • commands – Command list (may contain _CutMarker objects — they are skipped).

  • n_qubits – Total qubit count (used for validation).

  • qubits – Subset of qubit indices to include.

Returns:

(filtered_commands, local_n_qubits)

reconstruct_swap_gates_by_customs(to_delete: list) tuple[list, list, int, dict][source]

Replace 2q gates at cut positions with _CutMarker sentinels.

Returns two variants of the cut circuit: a 1q-representation (each cut gate replaced by two single-qubit _CutMarkers at [q0] and [q1]) used for qubit filtering, and a 2q-representation (one marker spanning [q0, q1]) used for the decomposition iterator.

Parameters:

to_delete – List of [q0, q1] pairs to cut.

Returns:

  • cut_cmds_1q: command list where each cut 2q gate is replaced by two single-qubit _CutMarker objects (one per qubit).

  • cut_cmds_2q: command list where each cut 2q gate is replaced by one two-qubit _CutMarker object (used in _iterate_experiment).

  • n_cuts: number of cuts performed.

  • cut_names: dict {name: (gate_type_str, params)} for each cut.

Return type:

A (cut_cmds_1q, cut_cmds_2q, n_cuts, cut_names) tuple

static remove_measure_gates(commands: list) tuple[list, list][source]

Remove all Measure commands, returning them and the rest separately.

Returns:

(filtered_commands, measured_qubit_indices)

qarp.cutting.check_cut_budget(n_cuts: int, *, force: bool = False) None[source]

Reject cut counts past config.max_number_of_cuts.

Every cut multiplies the experiment count by 6 (6^n_cuts total) — the guard lives here, in qarp.cutting, so both the engine-integrated and the standalone execution paths consult it.

qarp.cutting.decompose_crx(prefix, n_qubits, idx, idx_to_be_used_bit) tuple[list, ndarray][source]
qarp.cutting.decompose_cry(prefix, n_qubits, idx, idx_to_be_used_bit) tuple[list, ndarray][source]
qarp.cutting.decompose_crz(prefix, n_qubits, idx, idx_to_be_used_bit) tuple[list, ndarray][source]
qarp.cutting.decompose_cx(prefix: list, n_qubits: int, idx: list, idx_to_be_used_bit: ndarray) tuple[list, ndarray][source]

QPD decomposition of a CX gate into 6 single-qubit experiments.

Parameters:
  • prefix – Command list accumulated before this cut.

  • n_qubits – Qubit count of the circuit.

  • idx – [ctrl_qubit, tgt_qubit].

  • idx_to_be_used_bit – Array of 6 ints; idx_to_be_used_bit[i] is the next available QPD cbit index for experiment i.

Returns:

(experiments, coefficients) where experiments is a list of 6 command lists.

qarp.cutting.decompose_cy(prefix, n_qubits, idx, idx_to_be_used_bit) tuple[list, ndarray][source]
qarp.cutting.decompose_cz(prefix, n_qubits, idx, idx_to_be_used_bit) tuple[list, ndarray][source]
qarp.cutting.decompose_rzz(prefix: list, n_qubits: int, idx: list, idx_to_be_used_bit: ndarray, parameter) tuple[list, ndarray][source]

QPD decomposition of an RZZ gate.

Parameters:
  • prefix – Command list accumulated before this cut.

  • n_qubits – Qubit count.

  • idx – [q0, q1].

  • idx_to_be_used_bit – Next available QPD cbit per experiment.

  • parameter – RZZ rotation angle in radians (qarpx convention). May be a float or sympy.Symbol for parametric circuits.

Returns:

(experiments, coefficients)