HPCA 2023 Supermarq Tutorial using cirq-superstaq
You can run this notebook on Colab or Binder. The Colab requires sign in while Binder does not.
[1]:
try:
import cirq_superstaq as css
except ImportError:
print("Installing cirq-superstaq...")
%pip install --quiet 'cirq-superstaq[examples]'
print("Installed cirq-superstaq.")
print("You may need to restart the kernel to import newly installed packages.")
import cirq_superstaq as css
[2]:
try:
import supermarq
except ImportError:
print("Installing supermarq...")
%pip install --quiet supermarq
print("Installed supermarq.")
print("You may need to restart the kernel to import newly installed packages.")
import supermarq
[3]:
# Optional
import os # Used to store a token in an environment variable
Basics:
1. Service creation
[4]:
# Provide your api key to `css.Service()` using the `api_key=` argument if
# the SUPERSTAQ_API_KEY environment variable is not set.
# Submit cirq circuits via `cirq-superstaq`
service = css.Service()
print(service.get_balance())
20 credits
[5]:
# See which targets are available
service.get_targets(available=True)
[5]:
[Target(target='aqt_keysight_qpu', supports_submit=False, supports_submit_qubo=False, supports_compile=True, available=True, retired=False),
Target(target='aqt_zurich_qpu', supports_submit=False, supports_submit_qubo=False, supports_compile=True, available=True, retired=False),
Target(target='aws_dm1_simulator', supports_submit=True, supports_submit_qubo=False, supports_compile=True, available=True, retired=False),
Target(target='aws_sv1_simulator', supports_submit=True, supports_submit_qubo=False, supports_compile=True, available=True, retired=False),
Target(target='aws_tn1_simulator', supports_submit=True, supports_submit_qubo=False, supports_compile=True, available=True, retired=False),
Target(target='cq_sqale_qpu', supports_submit=True, supports_submit_qubo=False, supports_compile=True, available=True, retired=False),
Target(target='cq_sqale_simulator', supports_submit=True, supports_submit_qubo=False, supports_compile=True, available=True, retired=False),
Target(target='ibmq_brisbane_qpu', supports_submit=True, supports_submit_qubo=False, supports_compile=True, available=True, retired=False),
Target(target='ibmq_kyoto_qpu', supports_submit=True, supports_submit_qubo=False, supports_compile=True, available=True, retired=False),
Target(target='ibmq_osaka_qpu', supports_submit=True, supports_submit_qubo=False, supports_compile=True, available=True, retired=False),
Target(target='ionq_harmony_qpu', supports_submit=True, supports_submit_qubo=False, supports_compile=True, available=True, retired=False),
Target(target='ionq_ion_simulator', supports_submit=True, supports_submit_qubo=False, supports_compile=True, available=True, retired=False),
Target(target='qtm_h1-1_qpu', supports_submit=True, supports_submit_qubo=False, supports_compile=True, available=True, retired=False),
Target(target='qtm_h1-1e_simulator', supports_submit=True, supports_submit_qubo=False, supports_compile=True, available=True, retired=False),
Target(target='qtm_h2-1_qpu', supports_submit=True, supports_submit_qubo=False, supports_compile=True, available=True, retired=False),
Target(target='qscout_peregrine_qpu', supports_submit=False, supports_submit_qubo=False, supports_compile=True, available=True, retired=False),
Target(target='ss_unconstrained_simulator', supports_submit=True, supports_submit_qubo=True, supports_compile=True, available=True, retired=False)]
2. Benchmark instantiation
NOTE: after executing a benchmark circuit, the score should always be evaluated using the same Benchmark object that was used to generate the circuit.
All of the benchmarks can be found in supermarq/benchmarks/.
Think about other circuits/benchmarks you would like to implement and run!
[6]:
# Create your benchmark using cirq circuits
ghz = supermarq.ghz.GHZ(5)
print(ghz.cirq_circuit())
0: ───H───@───────────────M───
│ │
1: ───────X───@───────────M───
│ │
2: ───────────X───@───────M───
│ │
3: ───────────────X───@───M───
│ │
4: ───────────────────X───M───
3. Circuit evaluation
The generated circuits can be evaluated on a backend using any compatible service: AWS Braket, IBM Qiskit, cirq-superstaq, qiskit-superstaq, etc. Here we use cirq-superstaq
[7]:
job_css = service.create_job(
ghz.cirq_circuit(), repetitions=1000, target="ss_unconstrained_simulator", method="dry-run"
)
4. Compute the score
NOTE: after executing a benchmark circuit, the score should always be evaluated using the same Benchmark object that was used to generate the circuit.
[8]:
job_css.status()
[8]:
'Done'
[9]:
counts = job_css.counts(0)
print(counts)
score_css = ghz.score(counts)
print(score_css)
{'00000': 484, '11111': 516}
0.9997439344304242
5. Visualize the results
The function in supermarq/plotting.plot_results produces a simple bar plot. Feel free to copy and paste that code here to generate more detailed figures.
[10]:
supermarq.plotting.plot_results([score_css], ["ghz_css"])
Quantum Program Profiling
The current hardware-agnostic application features can be found in supermarq/features.py. Quantum program profiling is an exciting area of research that is just getting started – what kinds of features would you find meaningful? Try implementing them!
Compute features
[11]:
ghz_circuit = supermarq.ghz.GHZ(10).cirq_circuit()
ghz_features = [
supermarq.features.compute_communication(ghz_circuit),
supermarq.features.compute_depth(ghz_circuit),
supermarq.features.compute_entanglement(ghz_circuit),
supermarq.features.compute_liveness(ghz_circuit),
supermarq.features.compute_measurement(ghz_circuit),
supermarq.features.compute_parallelism(ghz_circuit),
]
print(ghz_features)
[0.2, 1.0, 0.9, 0.2636363636363636, 0.0, 0]
Visualize the feature vector
[12]:
supermarq.plotting.plot_benchmark(
title="A single GHZ benchmark",
labels=["ghz10"],
features=[ghz_features],
spoke_labels=["PC", "CD", "Ent", "Liv", "Mea", "Par"],
)
Correlating performance <> features
To correlate the performance of a particular device with a certain application feature, it is helpful to evaluate several different benchmarks on that same device. This code example creates 4 different benchmarks, computes their feature vectors, evaluates them on a backend, and then measures the correlation between the performance seen and the application features.
Characterize the benchmarks
[13]:
benchmark_features = {}
benchmarks = [
(supermarq.ghz.GHZ(5), "ghz5"),
(supermarq.hamiltonian_simulation.HamiltonianSimulation(4), "hsim4"),
(supermarq.mermin_bell.MerminBell(3), "mb3"),
(supermarq.bit_code.BitCode(3, 3, [1, 0, 1]), "bitcode3"),
]
for benchmark, label in benchmarks:
benchmark_features[label] = [
supermarq.features.compute_communication(benchmark.cirq_circuit()),
supermarq.features.compute_depth(benchmark.cirq_circuit()),
supermarq.features.compute_entanglement(benchmark.cirq_circuit()),
supermarq.features.compute_liveness(benchmark.cirq_circuit()),
supermarq.features.compute_measurement(benchmark.cirq_circuit()),
supermarq.features.compute_parallelism(benchmark.cirq_circuit()),
]
print(benchmark_features)
{'ghz5': [0.4, 1.0, 0.8, 0.4666666666666667, 0.0, 0], 'hsim4': [0.5, 1.0, 0.2857142857142857, 0.5961538461538461, 0.0, 0.38095238095238093], 'mb3': [1.0, 1.0, 0.4375, 0.6666666666666666, 0.0, 0.1875], 'bitcode3': [0.4, 0.5, 0.8571428571428571, 0.6142857142857143, 0.46153846153846156, 0.0]}
Evaluate
[14]:
jobs = []
for benchmark, label in benchmarks:
job = service.create_job(
benchmark.cirq_circuit(), repetitions=1000, target="ss_unconstrained_simulator"
)
jobs.append((label, job, benchmark))
Wait until the benchmarks have successfully executed…
[15]:
device_scores = {}
for label, job, benchmark in jobs:
if job.status() == "Done":
counts = job.counts(0)
print(counts)
score = benchmark.score(counts)
print(score)
device_scores[label] = score
else:
print(label, "not done!")
{'00000': 481, '11111': 519}
0.9996388695848232
{'0000': 1, '0001': 2, '0010': 3, '0011': 22, '0100': 2, '0101': 13, '0110': 14, '0111': 89, '1000': 4, '1001': 11, '1010': 14, '1011': 93, '1100': 14, '1101': 83, '1110': 99, '1111': 536}
0.9978033905932742
{'001': 1000}
1.0
{'11111110001': 1000}
1.0
Measure the correlation between device performance and application features
[16]:
supermarq.plotting.plot_correlations(
benchmark_features,
device_scores,
["PC", "CD", "Ent", "Liv", "Mea", "Par"],
device_name="ibmq_sim",
)