Skip to content

Commit

Permalink
Add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
mar-be committed May 6, 2024
1 parent 144d462 commit 8a69824
Show file tree
Hide file tree
Showing 3 changed files with 147 additions and 5 deletions.
6 changes: 4 additions & 2 deletions app/CKT_cutter.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,11 @@ def cut_circuit(cutting_request: CutCircuitsRequest):
return CKTCutCircuitsResponse(format=cutting_request.circuit_format, **res)


def automatic_cut(circuit, qubits_per_subcircuit, max_cuts=None):
def automatic_cut(
circuit, qubits_per_subcircuit, max_cuts=None, optimization_seed=None
):
# Specify settings for the cut-finding optimizer
optimization_settings = OptimizationParameters(seed=111)
optimization_settings = OptimizationParameters(seed=optimization_seed)

# Specify the size of the QPUs available
device_constraints = DeviceConstraints(qubits_per_subcircuit=qubits_per_subcircuit)
Expand Down
4 changes: 4 additions & 0 deletions app/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,3 +123,7 @@ def remove_bits(number, bit_positions):
number = left_part | right_part

return number


def replace_str_index(text, index=0, replacement=""):
return f"{text[:index]}{replacement}{text[index+1:]}"
142 changes: 139 additions & 3 deletions test/test_CKT_cutter.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,26 @@
from collections import defaultdict

import numpy as np
from circuit_knitting.cutting import (
DeviceConstraints,
OptimizationParameters,
find_cuts,
cut_wires,
expand_observables,
partition_problem,
generate_cutting_experiments,
reconstruct_expectation_values,
)
from qiskit import QuantumCircuit
from qiskit.circuit.random import random_circuit
from qiskit_aer.primitives import Sampler
from qiskit.quantum_info import SparsePauliOp
from qiskit_aer import AerSimulator
from qiskit_aer.primitives import Sampler, EstimatorV2
from qiskit_ibm_runtime.qiskit.primitives import BackendSamplerV2

from app import create_app
from app.CKT_cutter import automatic_cut, reconstruct_distribution
from app.utils import counts_to_array
from app.utils import counts_to_array, replace_str_index


class CutFindingTestCase(unittest.TestCase):
Expand Down Expand Up @@ -109,6 +123,128 @@ def test_reconstruction(self):
reconstructed_dist = counts_to_array(reconstructed_counts, circuit.num_qubits)

self.assertTrue(
np.allclose(exact_distribution, reconstructed_dist, atol=0.025),
np.allclose(exact_distribution, reconstructed_dist, atol=0.1),
msg=f"\nExact distribution: {exact_distribution}\nReconstruced distribution: {reconstructed_dist}\nDiff: {np.abs(exact_distribution- reconstructed_dist)}",
)

def test_reconstruction_2(self):

circuit = QuantumCircuit(4)
circuit.x(0)
circuit.cx(0, 1)
circuit.cx(1, 2)
circuit.cx(2, 3)
circuit.cx(3, 2)
circuit.cx(2, 1)
circuit.cx(1, 0)

exact_expval_list, actual_expval_list = get_expals(circuit, 2 ** 12)

self.assertTrue(
np.allclose(exact_expval_list, actual_expval_list, atol=0.1),
msg=f"\nExact expectations: {exact_expval_list}\nReconstruced expectations: {actual_expval_list}",
)

def test_reconstruction_3(self):

circuit = QuantumCircuit(4)
circuit.h(0)
circuit.cx(0, 1)
circuit.cx(1, 2)
circuit.cx(2, 3)
circuit.cx(3, 2)
circuit.cx(2, 1)
circuit.cx(1, 0)

exact_expval_list, actual_expval_list = get_expals(circuit, 2 ** 12)

self.assertTrue(
np.allclose(exact_expval_list, actual_expval_list, atol=0.1),
msg=f"\nExact expectations: {exact_expval_list}\nReconstruced expectations: {actual_expval_list}",
)

def test_reconstruction_3(self):

circuit = QuantumCircuit(4)
circuit.h(0)
circuit.cx(0, 1)
circuit.cx(1, 2)
circuit.cx(2, 3)
circuit.cx(3, 2)
circuit.cx(2, 1)
circuit.cx(1, 0)

exact_expval_list, actual_expval_list = get_expals(circuit, 2 ** 12)

self.assertTrue(
np.allclose(exact_expval_list, actual_expval_list, atol=0.1),
msg=f"\nExact expectations: {exact_expval_list}\nReconstruced expectations: {actual_expval_list}",
)

def test_reconstruction_4(self):

circuit = QuantumCircuit(5)
circuit.x(0)
circuit.cx(0, 1)
circuit.cx(1, 2)
circuit.cx(1, 0)
circuit.cx(2, 0)
circuit.cx(2, 3)
circuit.cx(3, 4)
circuit.cx(2, 4)

exact_expval_list, actual_expval_list = get_expals(circuit, 2 ** 12)

self.assertTrue(
np.allclose(exact_expval_list, actual_expval_list, atol=0.1),
msg=f"\nExact expectations: {exact_expval_list}\nReconstruced expectations: {actual_expval_list}",
)


def get_expals(circuit, shots):
n_qubits = circuit.num_qubits
i_string = "I" * n_qubits

observable = SparsePauliOp(
[replace_str_index(i_string, i, "Z") for i in range(n_qubits - 1, -1, -1)]
)

qubits_per_subcircuit = (n_qubits // 2) + (n_qubits % 2)
optimization_seed = 111

cut_result = automatic_cut(
circuit, qubits_per_subcircuit, optimization_seed=optimization_seed
)

individual_subcircuits = cut_result["individual_subcircuits"]
subcircuit_labels = cut_result["subcircuit_labels"]
coefficients = cut_result["coefficients"]
metadata = cut_result["metadata"]
qubit_map = metadata["qubit_map"]
subobservables = metadata["subobservables"]

sampler = Sampler(run_options={"shots": shots})
# Retrieve results from each partition's subexperiments
results = sampler.run(individual_subcircuits).result()

results_dict = defaultdict(list)
for label, res in zip(subcircuit_labels, results.quasi_dists):
results_dict[label].append(res)

reconstructed_counts = reconstruct_distribution(
results_dict, coefficients, qubit_map, subobservables
)

estimator = EstimatorV2()

actual_expval_list = []
exact_expval_list = []
for i in range(n_qubits):
actual_expval = 0
for meas, count in reconstructed_counts.items():
actual_expval += (-1) ** ((meas >> i) % 2) * count
actual_expval_list.append(actual_expval)
exact_expval = estimator.run([(circuit, observable.paulis[i])]).result()
exact_expval_list.append(exact_expval[0].data.evs)

return exact_expval_list, actual_expval_list

0 comments on commit 8a69824

Please sign in to comment.