Graph State Bipartite Entanglement#

%load_ext autoreload
%autoreload 2

Set IQM Token if using Resonance#

import os
from iqm.qiskit_iqm import IQMProvider

token = ""
os.environ["IQM_TOKEN"] = token
quantum_computer = "" # provide actual quantum computer name. i.e. "emerald", "garnet", "sirius"
iqm_server_url = "https://resonance.iqm.tech/" # provide actual IQM server URL
os.environ["IQM_SERVER_URL"] = iqm_server_url

provider = IQMProvider(iqm_server_url, quantum_computer=quantum_computer)
backend = provider.get_backend()
import matplotlib as mpl
mpl.rcParams['figure.dpi'] = 300

Graph State Configuration#

from iqm.benchmarks.entanglement.graph_states import *
EXAMPLE_GRAPHSTATE = GraphStateConfiguration(
    qubits=list(range(backend.num_qubits)),
    shots=2**12,
    tomography=TomographyType.STATE,
    num_bootstraps = 150,
    max_circuits_per_batch=100,
    # n_random_unitaries=25,
    # n_median_of_means=4,
)

Run the experiment#

benchmark_graphstate = GraphStateBenchmark(backend, EXAMPLE_GRAPHSTATE)
#run_graphstate = benchmark_graphstate.run()

Perform Analysis#

result_graphstate = benchmark_graphstate.analyze()

Display the maximum negativity for all qubit pairs#

The negativity is shown as a percentage of the ideal maximum value of 0.5 (which would be achieved on a noiseless backend).

for idx, o in enumerate(result_graphstate.observations):
    if idx == 0:
        print(f"Observations: {o.name}\n****************************\n")
    print(f"{o.identifier.qubit_indices}: {100.0*(o.value/0.5):.2f} +/- {100.0*(o.uncertainty/0.5):.2f} %")

Inspect the available plots#

result_graphstate.plots.keys()
result_graphstate.plots['max_negativities_IQM_Backend_20250325-160833']

Plot the lowest and highest negativity resconstructed density matrices

observation_dict = {obs.identifier.qubit_indices: obs.value for obs in result_graphstate.observations}
sorted_indices = np.argsort(list(observation_dict.values()))
lowest_negativity_pair = list(observation_dict.keys())[sorted_indices[0]]
highest_negativity_pair = list(observation_dict.keys())[sorted_indices[-1]]
result_graphstate.plots[f"{lowest_negativity_pair}"]
result_graphstate.plots[f"{highest_negativity_pair}"]

Display max negativities in the backend graph

result_graphstate.plots['max_negativities_graph_20250325-160833']

Display all available dataset attributes#

result_graphstate.dataset.attrs.keys()

If using state tomography: inspect the bootstrap bias (difference between each bootstrap mean and the measured sample)#

for qubits, x in result_graphstate.dataset.attrs['max_negativities'].items():
    print(f"{qubits} bootstrap bias: {np.abs(x['value'] - x['bootstrapped_average']):.2e}")
    print(f"\t (sample) {x['value']} | (adjusted) {(2*x['value'] - x['bootstrapped_average'])}")

All the qubit pair groups generated during execution

result_graphstate.dataset.attrs["all_neighbor_groups"]

Inspect a graph state for some particular Pauli measurement#

benchmark_graphstate.circuits.benchmark_circuits[0].circuit_groups[0].circuits[7].draw(fold=0,style='iqp')