A package for performing wire cuts of hardware without reset-gates or mid-circuit measurements. Built on top of qiskit
Project description
QCut
QCut is a quantum circuit knitting package for gate cuts and resrtless wire cuts. QCut has been designed to work with IQM's qpus, and therefore on the Finnish Quantum Computing Infrastructure (FiQCI), and tested with an IQM qpus. Additionally, QCut is built to be combatible with IQM’s Qiskit fork iqm_qiskit.
QCut has been built at CSC - IT Center for Science (Finnish IT Center for Science).
Check out jooniv.github.io/QCut/ for documentation and more examples.
Installation
For installation a UNIX-like system is currently needed due to pymetis being used for automatic cut finding. On Windows use WSL
Pip:
Installation should be done via uv
uv pip install QCut
#or
uv add QCut
Uv can be installed with
#Linux / mac
curl -LsSf https://astral.sh/uv/install.sh | sh
Note: for drawing circuits you might have to install pylatexenc. This can also be done with uv.
uv pip install pylatexenc
#or
uv add pylatexenc
Install from source
It is also possible to use QCut by cloning this repository and including it in your project folder.
cd QCut
uv pip install .
#or
uv sync --no-dev
#or with dev deps
uv sync
Usage
Manual Usage
1: Import needed packages
import QCut as ck
from QCut import cut, cutGate
from qiskit import QuantumCircuit
from qiskit_aer import AerSimulator
from qiskit_aer.primitives import Estimator
2: Start by defining a QuantumCircuit just like in Qiskit
circuit = QuantumCircuit(4)
mult = 1.635
circuit.r(mult*0.46262, mult*0.1446, 0)
circuit.cx(0,1)
circuit.cx(1,2)
circuit.cx(2,3)
circuit.measure_all()
circuit.draw("mpl")
3: Insert cut operations to the circuit to denote where we want to cut the circuit
Note that here we don't insert any measurements. Measurements will be automatically handled by QCut.
from qiskit.circuit.library import CXGate
cut_circuit = QuantumCircuit(4)
mult = 1.635
cut_circuit.r(mult*0.46262, mult*0.1446, 0)
cut_circuit.append(**cutGate(CXGate(), 0, 1))
cut_circuit.append(cut, [1])
cut_circuit.cx(1,2)
cut_circuit.cx(2,3)
cut_circuit.draw("mpl")
Note that currently QCut only supports cutting Cz gates so cut gates get transpiled down to cutCZ gates (hence the added H gates)
4: Extract cut locations from cut_circuit and split it into independent subcircuit.
cut_locations, subcircuits, map_qubit = ck.get_locations_and_subcircuits(cut_circuit)
Now we can draw our subcircuits.
subcircuits[0].draw("mpl")
subcircuits[1].draw("mpl")
subcircuits[2].draw("mpl")
5 Define backend and transpile the cut circuit
fake = IQMFakeAdonis() #noisy
sim = AerSimulator() #ideal
transpiled = ck.transpile_subcircuits(subcircuits, cut_locations, fake, optimization_level=3)
6: Generate experiment circuits
experiment_circuits, coefficients, id_meas = ck.get_experiment_circuits(transpiled, cut_locations)
7: Run the experiment circuits
results = ck.run_experiments(experiment_circuits, cut_locations, id_meas, backend=fake)
8: Define observables and calculate expectation values
Observables are Pauli-Z observables and are defined as a list of qubit indices. Multi-qubit observables are defined as a list inside the observable list.
If one wishes to calculate other than Pauli-Z observable expectation values currently this needs to be done by manually modifying the initial circuit to perform the basis transform.
observables = [0,1,2, [0,1]]
expectation_values = ck.estimate_expectation_values(results, coefficients, cut_locations, observables, map_qubit)
9: Finally calculate the exact and noisy expectation values of the original circuit and compare them to the results calculated with QCut
paulilist_observables = ck.get_pauli_list(observables, circuit.num_qubits)
estimator = Estimator(run_options={"shots": None}, approximation=True)
exact_expvals = (
estimator.run([circuit] * len(paulilist_observables), # noqa: PD011
list(paulilist_observables)).result().values
)
tr = transpile(circuit, backend=fake)
counts, exps = ck.run_and_expectation_value(tr, fake, observables, shots=2048)
import numpy as np
np.set_printoptions(formatter={"float": lambda x: f"{x:0.6f}"})
print(f"QCut expectation values:{np.array(expectation_values)}")
print(f"Noisy expectation values with fake backend:{np.array(exps)}")
print(f"Exact expectation values with ideal simulator :{np.array(exact_expvals)}")
QCut circuit knitting expectation values: [0.007532 0.007532 -0.003662 1.010128]
Noisy expectation values with fake backend:[0.478516 0.621094 0.558594 0.689453]
Exact expectation values with ideal simulator :[0.000000 0.000000 0.000000 1.000000]
As we can see QCut is able to accurately reconstruct the expectation values and be more accurate that just using the fake backend as is. (Note that since this is a probabilistic method the results vary a bit each run)
Additionally we can execute QCut using the ideal Aer simulator and see that we get (practically) exact results:
QCut ideal expectation values:[0.727968 0.727968 0.727968 1.015832]
Usage shorthand
For convenience, it is not necessary to go through each of the aforementioned steps individually. Instead, QCut provides a function run() that executes the whole wire-cutting sequence.
The same example can then be run like this:
sim = AerSimulator()
observables = [0,1,2, [0,2]]
estimated_expectation_values = ck.run(cut_circuit, observables, sim)
Automatic cuts
QCut comes with functionality for automatically finding good cut locations that can place both wire and gate cuts.
from QCut import find_cuts
cut_locations, subcircuits, map_qubit = find_cuts(circuit , 3, cuts="both")
estimated_expectation_values = ck.run_cut_circuit(subcircuits, cut_locations, observables, map_qubit, sim)
np.set_printoptions(formatter={"float": lambda x: f"{x:0.6f}"})
print(f"QCut expectation values:{np.array(estimated_expectation_values)}")
print(f"Exact expectation values with ideal simulator :{np.array(exact_expvals)}")
QCut expectation values:[0.729648 0.745609 0.702871 0.992620]
Exact expectation values with ideal simulator :[0.727323 0.727323 0.727323 1.000000]
Running on IQM fake backends
To use QCut with IQM's fake backends it is required to install Qiskit IQM. QCut supports version 17.8. Installation can be done with uv:
uv pip install qiskit-iqm==17.8
#or
uv add qiskit-iqm==17.8
After installation just import the backend you want to use:
from iqm.qiskit_iqm import IQMFakeAdonis()
backend = IQMFakeAdonis()
Running on FiQCI
For running on real hardware through the Lumi supercomputer's FiQCI partition follow the instructions here. If you are used to using Qiskit on jupyter notebooks it is recommended to use the Lumi web interface.
Running on other hardware
Running on other providers such as IBM is untested at the moment but as long as the hardware can be accessed with Qiskit QCut should be compatible.
Documentation
Check out jooniv.github.io/QCut/ for documentation and more examples.
The docs are built with sphinx using the sphinx book theme. To build the docs:
cd docs
uv pip install -r requirements-docs.txt
sphinx-build -v -b html . build/sphinx/html -W
HTML files can then be found under build/sphinx/html/
Acknowledgements
This project is built on top of Qiskit which is licensed under the Apache 2.0 license.
License
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file qcut-0.8.0.tar.gz.
File metadata
- Download URL: qcut-0.8.0.tar.gz
- Upload date:
- Size: 508.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bb1126f907ecd5e8fa5ab088ccd8db12fdafa48beafd68f0ea0e74f0f1177fe6
|
|
| MD5 |
04c1a5ecaf141ee341f87c4286825cf0
|
|
| BLAKE2b-256 |
751346978807a549e4b033289fcc9ac6a4a34ac7d37e9bd0f79f951a98d01f96
|
Provenance
The following attestation bundles were made for qcut-0.8.0.tar.gz:
Publisher:
publish_to_pypi.yml on JooNiv/QCut
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
qcut-0.8.0.tar.gz -
Subject digest:
bb1126f907ecd5e8fa5ab088ccd8db12fdafa48beafd68f0ea0e74f0f1177fe6 - Sigstore transparency entry: 761171599
- Sigstore integration time:
-
Permalink:
JooNiv/QCut@63b78a353c3da7afb1fa9195e8ae9b4292f9eb7b -
Branch / Tag:
refs/tags/v0.8.0 - Owner: https://github.com/JooNiv
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish_to_pypi.yml@63b78a353c3da7afb1fa9195e8ae9b4292f9eb7b -
Trigger Event:
release
-
Statement type:
File details
Details for the file qcut-0.8.0-py3-none-any.whl.
File metadata
- Download URL: qcut-0.8.0-py3-none-any.whl
- Upload date:
- Size: 506.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
73054c80d612ddea43479d60baf1fe3e2f6082e718f7d96d903a75e18207c3c6
|
|
| MD5 |
57d027df54ee08e9c18997abea5ca687
|
|
| BLAKE2b-256 |
4b02bfb43383172bf7e6af5e63e48c772c3378d729e364a41d4109cfe8901e0c
|
Provenance
The following attestation bundles were made for qcut-0.8.0-py3-none-any.whl:
Publisher:
publish_to_pypi.yml on JooNiv/QCut
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
qcut-0.8.0-py3-none-any.whl -
Subject digest:
73054c80d612ddea43479d60baf1fe3e2f6082e718f7d96d903a75e18207c3c6 - Sigstore transparency entry: 761171657
- Sigstore integration time:
-
Permalink:
JooNiv/QCut@63b78a353c3da7afb1fa9195e8ae9b4292f9eb7b -
Branch / Tag:
refs/tags/v0.8.0 - Owner: https://github.com/JooNiv
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish_to_pypi.yml@63b78a353c3da7afb1fa9195e8ae9b4292f9eb7b -
Trigger Event:
release
-
Statement type: