QCut Basic Usage

QCut Basic Usage#

import QCut as ck
from QCut import cut, cutGate
from qiskit import QuantumCircuit, transpile
from qiskit.circuit.library import CXGate
from qiskit.quantum_info import SparsePauliOp
from qiskit_aer import AerSimulator
from qiskit.primitives import StatevectorEstimator, BackendEstimatorV2 as BackendEstimator
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.draw("mpl")
../_images/0a38b6fe6ab176d5549f46c32b0fd1317b1ba2a101b4a66889ad89d745bec382.png
#insert cuts
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/1070e02c1bc983d3c2ea6917e0501c2a40148692415febcd46abde19265660ec.png
#extract cut locations and separate into subcircuits

cut_circuit = ck.get_locations_and_subcircuits(cut_circuit)
cut_circuit.subcircuits[0].draw("mpl")
../_images/e6cec3d06c91953de69bdb0e8fa6e1deac094e196152ba2b29e30a628356b9a9.png
cut_circuit.subcircuits[1].draw("mpl")
../_images/1fbec1237aff02ad1e184aa09897601201c108953b918e8df11d74a3861ac212.png
cut_circuit.subcircuits[2].draw("mpl")
../_images/e921a806dbd827c7bf134872b36f74a5e67389da5e1f917d9a6ca7a5b166eb07.png
#define backends
fake = IQMFakeAdonis()
sim = AerSimulator()
#transpile subcircuits for backend

transpiled = ck.transpile_subcircuits(cut_circuit, fake, optimization_level=3)
#generate experiment circuits
observables = SparsePauliOp(["IIIZ", "IIZI", "IZII", "IIZZ"])

cut_experiment = ck.get_experiment_circuits(transpiled, observables)
#run experiment circuits
#run_experiments() also post processes the results

results = ck.run_experiments(cut_experiment, backend=fake)
#get the approximated expectation values
expectation_values = ck.estimate_expectation_values(results, cut_experiment.expv_data())
obs = [ob.to_label() for ob in observables.paulis]

estimator = StatevectorEstimator()
exact_expvals = [e.data.evs for e in
    estimator.run([(x) for x in zip([circuit] * len(obs), obs)]).result()
]


tr = transpile(circuit, backend=fake)

tr_obs = observables.apply_layout(tr.layout)

tr_obs_separate = [
    SparsePauliOp(pauli.to_label()) for pauli in tr_obs.paulis
]

fake_estimator = BackendEstimator(backend=fake)
exps = [e.data.evs for e in
    fake_estimator.run([(x) for x in zip([tr] * len(tr_obs_separate), tr_obs_separate)]).result()
]
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 expectation values:[0.690654 0.537297 0.596472 0.714923]
Noisy expectation values with fake backend:[0.656250 0.600586 0.625488 0.797363]
Exact expectation values with ideal simulator :[0.727323 0.727323 0.727323 1.000000]