QCut API reference#

Submodules#

QCut.backend_utility module#

Utility functions for running on real backends.

QCut.backend_utility.expectation_values(counts: dict, observables: list, shots: int) list[source]#

Calculate expectation values.

Args:#

counts: counts obtained from circuit run observables: observables to calculate expectation values for shots: number of shots probs

Returns:#

cut_locations: a list of cut locations subcircuits: subcircuits with placeholder operations

QCut.backend_utility.run_and_expectation_value(circuit: QuantumCircuit, backend, observables: list, shots: int, mitigate=False) tuple[dict, list][source]#

Run circuit and calculate expectation value.

Args:#

circuit: a quantum circuit backend: backend to run circuit on observables: observables to calculate expectation values for shots: number of shots mitigate: if True use readout error mitigation

Returns:#

expectation_values: a list of expectation values

QCut.backend_utility.run_on_backend(circuit: QuantumCircuit, backend, shots: int) dict[source]#

Run circuit on backend.

Args:#

circuit: a quantum circuit to be executed backend: backend to use for executing circuit shots: number of shots probs

Returns:#

dict: a dictionary of counts from circuit run

QCut.backend_utility.transpile_experiments(experiment_circuits: list, backend) list[source]#

Transpile experiment circuits.

Args:#

experiment_circuits: experiment circuits backend: backend to transpile to

Returns:#

transpiled_experiments: a list of transpiled experiment circuits

QCut.helper module#

Helper functions for circuit knitting.

QCut.helper.get_pauli_list(input_list: list, length: int) PauliList[source]#

Transform list of observable indices to Paulilist of Z observables.

Args:#

input_list: lits of observables as qubit indices length: number of qubits in the circuit

Returns:#

PauliList: a PauliList of Z observables

QCut.helper.isclose(a: float, b: float) bool[source]#

Check if two floats equal-ish.

Args:#

b: float to be compared a: float to be compared.

Returns:#

bool: whether a and b close to each other or not.

QCut.helper.relative_error(actual: list, approx: list) list[source]#

Calculate the relative error.

QCut.qpd_gates module#

Helper gates for circuit knitting.

QCut.identity_qpd module#

Define identity channel quasi probability decomposition.

QCut.wirecut module#

Circuit knitting wire cut functionality.

class QCut.wirecut.CutLocation(cut_location: tuple[tuple[tuple[QuantumRegister, int]], int])[source]#

Bases: object

Storage class for storing cut locations.

exception QCut.wirecut.QCutError(message: str = 'An error occurred', code: int | None = None)[source]#

Bases: Exception

Exception raised for custom error conditions.

message(str)#
Type:

Explanation of the error.

code(int, optional)#
Type:

Error code representing the error type.

class QCut.wirecut.SubResult(measurements: list, count: int)[source]#

Bases: object

Storage class for easier storage/access to the results of a subcircuit.

class QCut.wirecut.TotalResult(*subcircuits: list[SubResult])[source]#

Bases: object

Storage class for easier access to the results of a subcircuit group.

QCut.wirecut.estimate_expectation_values(results: list[TotalResult], coefficients: list[int], cut_locations: ndarray[CutLocation], observables: list[int | list[int]]) list[float][source]#

Calculate the estimated expectation values.

Loop through processed results. For each result group generate all products of different measurements from different subcircuits of the group. For each result from qpd measurements calculate qpd coefficient and from counts calculate weight. Get results for qubits corresponding to the observables. If multiqubit observable multiply individual qubit eigenvalues and multiply by (-1)^(m+1) where m is number of qubits in the observable. Multiply by weight and add to sub expectation value. Once all results iterated over move to next circuit group. Lastly multiply by 4^(2*n), where n is the number of cuts, and divide by number of samples.

Args:#

results: results from experiment circuits coefficients: list of coefficients for each subcircuit group cut_locations: cut locations observables: observables to calculate expectation values for

Returns:#

list: expectations as a list of floats list of floats

QCut.wirecut.get_experiment_circuits(subcircuits: list[QuantumCircuit], cut_locations: ndarray[CutLocation]) tuple[list[list[QuantumCircuit]], list[int], list[tuple[int, int, int]]][source]#

Generate experiment circuits by inserting QPD operations on measure/initialize nodes.

Loop through qpd combinations. Calculate coefficient for subcircuit group by taking the product of all coefficients in the current qpd row. Loop through subcircuits generated in 4. Make deepcopy of subcircuit and iterate over its circuit data. When hit either Meas_{ind} of Init_{ind} repace it with operation found in qpd[ind][“op”/”init”]. WHile generating experiment circuits also generate a list of locations that have an identity basis measurement. These measurement outcomes need to be added during post-processing. Locations added as [index of experiment circuit, index of subcircuit, index of classical bit corresponding to measurement]. Repeat untill looped through all qpd rows. sircuits reutrned as [circuit_group0, circuit_group1, …], where circuit_goup is [subciruit0, subcircuit1, …].

Args:#

subcircuits: subcircuits with measure/initialize nodes. cut_locations: cut locations.

Returns:#

experimentCircuits: list of experiment circuits. coefficients: sign coefficients for each circuit. id_meas: list of index pointers to results that need additional post-processing due to identity basis measurement.

QCut.wirecut.get_locations_and_bounds(circuit: QuantumCircuit) tuple[ndarray[CutLocation], list[int]][source]#

Get the locations of the cuts in the circuit and the subcircuit bounds.

Args:#

circuit: Quantum circuit with Move() operations.

Returns:#

Locations of the cuts and bounds as a list.

QCut.wirecut.get_locations_and_subcircuits(circuit: QuantumCircuit) tuple[list[CutLocation], list[QuantumCircuit]][source]#

Get cut locations and subcircuits with placeholder operations.

Args:#

circuit: circuit with cuts inserted

Returns:#

cut_locations: a list of cut locations subcircuits: subcircuits with placeholder operations

QCut.wirecut.get_placeholder_locations(subcircuits: list[QuantumCircuit]) list[source]#

Test.

QCut.wirecut.get_qpd_combinations(cut_locations: np.ndarray[CutLocation]) Iterable[tuple[dict]][source]#

Get all possible combinations of the QPD operations so that each combination has len(cut_locations) elements.

For a single cut operations can be straightforwardly inserted from the identity qpd. If multiple cuts are made one need to take the cartesian product of the identity qpd with itself n times, where n is number of cuts. This will give a qpd with 8^n rows. Each row corresponds to a subcircuit group. These operations can then be inserted to generate the experiment circuits.

Args:#

cut_locations: cut locations

Returns:#

ops: list of the possible QPD operations

Raises:

QCut.wirecut.run(circuit: QuantumCircuit, observables: list[int, list[int]], backend=AerSimulator('aer_simulator'), mitigate: bool = False) list[float][source]#

Run the whole circuit knitting sequence with one function call.

Args:#

circuit: circuit with cut experiments observables: list of observbles in the form of qubit indices (Z-obsevable). backend: backend to use for running experiment circuits (optional) mitigate: wether or not to use readout error mitigation (optional)

Returns:#

list: a list of expectation values

QCut.wirecut.run_cut_circuit(subcircuits: list[QuantumCircuit], cut_locations: ndarray[CutLocation], observables: list[int | list[int]], backend=AerSimulator('aer_simulator'), mitigate: bool = False) ndarray[float][source]#

After splitting the circuit run the rest of the circuit knitting sequence.

Args:#

subcircuits: subcircuits containing the placeholder operations cut_locations: list of cut locations observables: list of observables as qubit indices (Z observable) backend: backend to use for running experiment circuits (optional) mitigate: wether or not to use readout error mitigation (optional)

Returns:#

list: a list of expectation values

QCut.wirecut.run_experiments(experiment_circuits: list[list[QuantumCircuit]], cut_locations: ndarray[CutLocation], id_meas: list[tuple[int, int, int]], shots: int = 4096, backend: None = None, mitigate: bool = False) list[TotalResult][source]#

Run experiment circuits.

Loop through experiment circuits and then loop through circuit group and run each circuit. Store results as [group0, group1, …] where group is [res0, res1, …]. where res is “xxx yy”: count xxx are the measurements from the end of circuit measurements on the meas classical register and yy are the qpd basis measurement results from the qpd_meas class register.

Args:#

experiment_circuits: experiment circuits cut_locations: list of cut locations id_meas: list of identity basis measurement locations shots: number of shots per circuit run (optional) backend: backend used for running the circuits (optional) mitigate: wether to use readout error mitigation or not (optional)

Returns:#

processed_results: list of transformed results

Module contents#

Init circuit knitting.

QCut.estimate_expectation_values(results: list[TotalResult], coefficients: list[int], cut_locations: ndarray[CutLocation], observables: list[int | list[int]]) list[float][source]#

Calculate the estimated expectation values.

Loop through processed results. For each result group generate all products of different measurements from different subcircuits of the group. For each result from qpd measurements calculate qpd coefficient and from counts calculate weight. Get results for qubits corresponding to the observables. If multiqubit observable multiply individual qubit eigenvalues and multiply by (-1)^(m+1) where m is number of qubits in the observable. Multiply by weight and add to sub expectation value. Once all results iterated over move to next circuit group. Lastly multiply by 4^(2*n), where n is the number of cuts, and divide by number of samples.

Args:#

results: results from experiment circuits coefficients: list of coefficients for each subcircuit group cut_locations: cut locations observables: observables to calculate expectation values for

Returns:#

list: expectations as a list of floats list of floats

QCut.expectation_values(counts: dict, observables: list, shots: int) list[source]#

Calculate expectation values.

Args:#

counts: counts obtained from circuit run observables: observables to calculate expectation values for shots: number of shots probs

Returns:#

cut_locations: a list of cut locations subcircuits: subcircuits with placeholder operations

QCut.get_experiment_circuits(subcircuits: list[QuantumCircuit], cut_locations: ndarray[CutLocation]) tuple[list[list[QuantumCircuit]], list[int], list[tuple[int, int, int]]][source]#

Generate experiment circuits by inserting QPD operations on measure/initialize nodes.

Loop through qpd combinations. Calculate coefficient for subcircuit group by taking the product of all coefficients in the current qpd row. Loop through subcircuits generated in 4. Make deepcopy of subcircuit and iterate over its circuit data. When hit either Meas_{ind} of Init_{ind} repace it with operation found in qpd[ind][“op”/”init”]. WHile generating experiment circuits also generate a list of locations that have an identity basis measurement. These measurement outcomes need to be added during post-processing. Locations added as [index of experiment circuit, index of subcircuit, index of classical bit corresponding to measurement]. Repeat untill looped through all qpd rows. sircuits reutrned as [circuit_group0, circuit_group1, …], where circuit_goup is [subciruit0, subcircuit1, …].

Args:#

subcircuits: subcircuits with measure/initialize nodes. cut_locations: cut locations.

Returns:#

experimentCircuits: list of experiment circuits. coefficients: sign coefficients for each circuit. id_meas: list of index pointers to results that need additional post-processing due to identity basis measurement.

QCut.get_locations_and_subcircuits(circuit: QuantumCircuit) tuple[list[CutLocation], list[QuantumCircuit]][source]#

Get cut locations and subcircuits with placeholder operations.

Args:#

circuit: circuit with cuts inserted

Returns:#

cut_locations: a list of cut locations subcircuits: subcircuits with placeholder operations

QCut.get_pauli_list(input_list: list, length: int) PauliList[source]#

Transform list of observable indices to Paulilist of Z observables.

Args:#

input_list: lits of observables as qubit indices length: number of qubits in the circuit

Returns:#

PauliList: a PauliList of Z observables

QCut.run(circuit: QuantumCircuit, observables: list[int, list[int]], backend=AerSimulator('aer_simulator'), mitigate: bool = False) list[float][source]#

Run the whole circuit knitting sequence with one function call.

Args:#

circuit: circuit with cut experiments observables: list of observbles in the form of qubit indices (Z-obsevable). backend: backend to use for running experiment circuits (optional) mitigate: wether or not to use readout error mitigation (optional)

Returns:#

list: a list of expectation values

QCut.run_and_expectation_value(circuit: QuantumCircuit, backend, observables: list, shots: int, mitigate=False) tuple[dict, list][source]#

Run circuit and calculate expectation value.

Args:#

circuit: a quantum circuit backend: backend to run circuit on observables: observables to calculate expectation values for shots: number of shots mitigate: if True use readout error mitigation

Returns:#

expectation_values: a list of expectation values

QCut.run_cut_circuit(subcircuits: list[QuantumCircuit], cut_locations: ndarray[CutLocation], observables: list[int | list[int]], backend=AerSimulator('aer_simulator'), mitigate: bool = False) ndarray[float][source]#

After splitting the circuit run the rest of the circuit knitting sequence.

Args:#

subcircuits: subcircuits containing the placeholder operations cut_locations: list of cut locations observables: list of observables as qubit indices (Z observable) backend: backend to use for running experiment circuits (optional) mitigate: wether or not to use readout error mitigation (optional)

Returns:#

list: a list of expectation values

QCut.run_experiments(experiment_circuits: list[list[QuantumCircuit]], cut_locations: ndarray[CutLocation], id_meas: list[tuple[int, int, int]], shots: int = 4096, backend: None = None, mitigate: bool = False) list[TotalResult][source]#

Run experiment circuits.

Loop through experiment circuits and then loop through circuit group and run each circuit. Store results as [group0, group1, …] where group is [res0, res1, …]. where res is “xxx yy”: count xxx are the measurements from the end of circuit measurements on the meas classical register and yy are the qpd basis measurement results from the qpd_meas class register.

Args:#

experiment_circuits: experiment circuits cut_locations: list of cut locations id_meas: list of identity basis measurement locations shots: number of shots per circuit run (optional) backend: backend used for running the circuits (optional) mitigate: wether to use readout error mitigation or not (optional)

Returns:#

processed_results: list of transformed results

QCut.run_on_backend(circuit: QuantumCircuit, backend, shots: int) dict[source]#

Run circuit on backend.

Args:#

circuit: a quantum circuit to be executed backend: backend to use for executing circuit shots: number of shots probs

Returns:#

dict: a dictionary of counts from circuit run

QCut.transpile_experiments(experiment_circuits: list, backend) list[source]#

Transpile experiment circuits.

Args:#

experiment_circuits: experiment circuits backend: backend to transpile to

Returns:#

transpiled_experiments: a list of transpiled experiment circuits