Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(qvol): First version of adding Quantum Volume to Recirq. #27

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 94 additions & 0 deletions recirq/benchmarks/Quantum-Volume.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Running the Quantum Volume Algorithm\n",
"This example runs the quantum volume algorithm of https://arxiv.org/pdf/1811.12926.pdf. In general, the algorithm will generate a model circuit, classically compute its Heavy Output Group, then run a sampler to evaluate how often it generates Heavy results.\n",
"\n",
"TODO: Flesh out this notebook per https://github.com/quantumlib/ReCirq/issues/28.\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# This cell sets up the parameters for the quantum volume algorithm.\n",
"# Feel free to mess with these!\n",
"from recirq.benchmarks.experiments.quantum_volume import QuantumVolumeTask, run_quantum_volume\n",
"import datetime\n",
"\n",
"dataset_id = datetime.datetime.now().isoformat(timespec='minutes')\n",
"dc_task = QuantumVolumeTask(\n",
" dataset_id=dataset_id,\n",
" device_name='Syc23-simulator',\n",
" n_shots=10_000,\n",
" n_circuits=1,\n",
" n_qubits=4,\n",
" depth=4,\n",
" readout_error_correction=True,\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Actually run the task and collect the data for analysis.\n",
"from recirq.benchmarks.experiments.quantum_volume import EXPERIMENT_NAME, DEFAULT_BASE_DIR, QuantumVolumeTask, run_quantum_volume\n",
"\n",
"run_quantum_volume(dc_task)\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import recirq\n",
"import numpy as np\n",
"import pandas as pd\n",
"\n",
"records = []\n",
"# Load all data, do some light processing\n",
"for record in recirq.iterload_records(dataset_id=dataset_id, base_dir=DEFAULT_BASE_DIR):\n",
" # Expand task dataclass into columns\n",
" recirq.flatten_dataclass_into_record(record, 'task')\n",
"\n",
" records.append(record)\n",
" \n",
"df = pd.DataFrame(records)\n",
"print(len(df))\n",
"df.head()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "ReCirq",
"language": "python",
"name": "recirq"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.7"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
13 changes: 13 additions & 0 deletions recirq/benchmarks/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Copyright 2020 Google
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
13 changes: 13 additions & 0 deletions recirq/benchmarks/experiments/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Copyright 2020 Google
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
129 changes: 129 additions & 0 deletions recirq/benchmarks/experiments/quantum_volume.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
# Copyright 2020 Google
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import os
from typing import Optional, List

import numpy as np

import cirq
from cirq.contrib.quantum_volume import quantum_volume

import recirq


@recirq.json_serializable_dataclass(namespace='recirq.quantum_volume',
registry=recirq.Registry,
frozen=True)
class QuantumVolumeTask:
"""Script to run the quantum volume algorithm on a device, per the benchmark defined by IBM in
https://arxiv.org/abs/1811.12926.

This will run the Quantum Volume benchmark on the Sycamore device on the given depths (every combination of
depths 2 through 6 by default) with 100 repetitions each depth. You can configure these parameters by editing
this script directly. All the business logic is deferred to a Quantum Volume back in public Cirq - this file
exists primarily to pull in devices that we are not yet ready to release.

Attributes:
dataset_id: A unique identifier for this dataset.
device_name: The device to run on, by name.
num_qubits: The number of qubits in the generated circuits.
qubits: All of the possible qubits that the algorithm can run on. If empty,
we will use any qubits on the device.
n_shots: The number of repetitions for each circuit.
n_circuits: The number of circuits to run the algorithm.
depth: The number of layers to generate in the circuit.
"""
dataset_id: str
device_name: str
n_qubits: int
n_shots: int
n_circuits: int
depth: int
readout_error_correction: bool
qubits: Optional[List[cirq.GridQubit]] = None

@property
def fn(self):
n_shots = _abbrev_n_shots(self.n_shots)
qubits = _abbrev_grid_qubits(self.qubits) + '/'

return (f'{self.dataset_id}/'
f'{self.device_name}/'
f'{qubits}/'
f'{self.n_circuits}_{self.depth}_{self.n_qubits}_{n_shots}')


# Define the following helper functions to make nicer `fn` keys
# for the tasks:


def _abbrev_n_shots(n_shots: int) -> str:
"""Shorter n_shots component of a filename"""
if n_shots % 1000 == 0:
return f'{n_shots // 1000}k'
return str(n_shots)


def _abbrev_grid_qubits(qubits: Optional[List[cirq.GridQubit]]) -> str:
"""Formatted a list of grid qubits component of a filename"""
if not qubits:
return ''
return '-'.join([f'{qubit.row}_{qubit.col}' for qubit in qubits])


EXPERIMENT_NAME = 'quantum-volume'
DEFAULT_BASE_DIR = os.path.expanduser(f'~/cirq-results/{EXPERIMENT_NAME}')


def run_quantum_volume(task: QuantumVolumeTask, base_dir=None):
"""Execute a :py:class:`QuantumVolumeTask` task."""
if base_dir is None:
base_dir = DEFAULT_BASE_DIR

if recirq.exists(task, base_dir=base_dir):
print(f"{task} already exists. Skipping.")
return

sampler = recirq.get_sampler_by_name(device_name=task.device_name)
device = recirq.get_device_obj_by_name(device_name=task.device_name)
device_or_qubits = task.qubits if task.qubits else device

# Run the jobs
print("Collecting data", flush=True)
results = quantum_volume.calculate_quantum_volume(
num_qubits=task.n_qubits,
depth=task.depth,
num_circuits=task.n_circuits,
device_or_qubits=device_or_qubits,
samplers=[sampler],
repetitions=task.n_shots,
random_state=np.random.RandomState(
int(hash(task.dataset_id)) % (2**32 - 1)),
compiler=lambda c: cirq.google.optimized_for_sycamore(
c,
new_device=device,
optimizer_type='sycamore',
tabulation_resolution=0.008),
add_readout_error_correction=task.readout_error_correction)
# Save the results. NB: The circuits in the results have Circuits that contain a SerializableDevice, which at the
# time of this writing is not JSON serializable. Because we don't actually need the device to be in the circuits,
# we simply set them to None for now.
for result in results:
# We can't actually set the device property to None, so set _device directly.
result.compiled_circuit._device = None
result.model_circuit._device = None
recirq.save(task=task, data={
'results': results,
}, base_dir=base_dir)
48 changes: 48 additions & 0 deletions recirq/benchmarks/experiments/run-quantum-volume.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Copyright 2020 Google
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from recirq.benchmarks.experiments.quantum_volume import QuantumVolumeTask, run_quantum_volume
import datetime


def main():
"""Main driver script entry point.

This function contains configuration options and you will likely need
to edit it to suit your needs. Of particular note, please make sure
`dataset_id` and `device_name`
are set how you want them. You may also want to change the values in
the list comprehension to set the qubits.
"""
# Uncomment below for an auto-generated unique dataset_id
# dataset_id = datetime.datetime.now().isoformat(timespec='minutes')
dataset_id = '2020-05-21'
data_collection_tasks = [
QuantumVolumeTask(
dataset_id=dataset_id,
device_name='Syc23-simulator',
n_shots=10_000,
n_circuits=1,
n_qubits=4,
depth=4,
readout_error_correction=True,
)
]

for dc_task in data_collection_tasks:
run_quantum_volume(dc_task)


if __name__ == '__main__':
main()