QCut Basic Usage

QCut Basic Usage#

import QCut as ck
from QCut import cut, cutGate
from qiskit import QuantumCircuit, transpile
from qiskit_aer import AerSimulator
from qiskit_aer.primitives import Estimator
from iqm.qiskit_iqm import IQMFakeAdonis
#define initial circuit

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")
../_images/d0a68920950b30e7813291cc4e4d51947ed87768634cea9f374ffc7ec61c22a3.png
#insert cuts

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.decompose(["CutGate"]).draw("mpl")
../_images/0e330f1c6565882ec158bed1d4271f86924f15fceaceee9ac35b5aeae90043c9.png
#extract cut locations and separate into subcircuits

cut_locations, subcircuits, map_qubit = ck.get_locations_and_subcircuits(cut_circuit)
subcircuits[0].draw("mpl")
../_images/64b1cb41f3f483d1174c7f34b744c11022758d62307efce201a03d794867f7dc.png
subcircuits[1].draw("mpl")
../_images/5af4892478a23594943fcc416991cd3ec9c743feec7b6a33db42426927721a5d.png
subcircuits[2].draw("mpl")
../_images/57c9d64faa59085ea3bc8e149f7179455325a631614041cb008e8f047966ec88.png
#define backends
fake = IQMFakeAdonis()
sim = AerSimulator()
#transpile subcircuits for backend

transpiled = ck.transpile_subcircuits(subcircuits, cut_locations, fake, optimization_level=3)
#generate experiment circuits
experiment_circuits, coefficients, id_meas = ck.get_experiment_circuits(transpiled, cut_locations)
#run experiment circuits
#run_experiments() also post processes the results

results = ck.run_experiments(experiment_circuits, cut_locations, id_meas, backend=fake)
#define observables to calculate expectation values for
observables = [0,1,2, [0,2]]

#get the approximated expectation values
expectation_values = ck.estimate_expectation_values(results, coefficients, cut_locations, observables, map_qubit)
#transform observables into a PauliList for the Qiskit Estimator
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

#set numpy print options
np.set_printoptions(formatter={"float": lambda x: f"{x:0.6f}"})
expectation_values = np.array(expectation_values).astype(float)

#compare QCut to Estimator and noisy simulation
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 expectation values:[0.618428 0.537705 0.567099 0.798735]
Noisy expectation values with fake backend:[0.516602 0.611328 0.559570 0.687500]
Exact expectation values with ideal simulator :[0.727323 0.727323 0.727323 1.000000]