Quantum Engine API

Google's Quantum Computing Service provides the Quantum Engine API to execute circuits on Google's quantum processor or simulator backends and to access or manage the jobs, programs, reservations and calibrations. Cirq is the only supported client for this API, using the cirq_google.Engine class. For other use cases (e.g. from a different language), contact cirq-maintainers@googlegroups.com with a short proposal or submit an RFC.

Authenticating to Google Cloud

Before you begin, you will need to create a Google Cloud project with the API enabled and billing enabled. You will then need to create credentials in order to access the API.

You can create application default credentials from the command line using the gcloud client:

gcloud auth application-default login

From a colab, you can execute:

from google.colab import auth
auth.authenticate_user(clear_output=False)

More information on creating application default credentials can be found on the Google cloud website.

Engine class

The Engine class is the entry point to communicate with the API.

It can be initialized using your project id (found within your Google Cloud Platform Console). You can use this instance to run quantum circuits or sweeps (parameterized variants of a general circuit).

import cirq
import cirq_google as cg

# A simple sample circuit
qubit = cirq.GridQubit(5, 2)
circuit = cirq.Circuit(
    cirq.X(qubit)**0.5,                 # Square root of NOT.
    cirq.measure(qubit, key='result')   # Measurement.
)

# Create an Engine object.
# Replace YOUR_PROJECT_ID with the id from your cloud project.
engine = cg.Engine(project_id=YOUR_PROJECT_ID)

# Create a sampler from the engine
sampler = engine.get_sampler(processor_id='PROCESSOR_ID')

# This will run the circuit and return the results in a 'Result'
results = sampler.run(circuit, repetitions=1000)

# Sampler results can be accessed several ways

# For instance, to see the histogram of results
print(results.histogram(key='result'))

# Or the data itself
print(results.data)

Device Specification

Several public devices have been released and can be found in the cirq_google package. These are documented further on the Google Device page.

However, you can also retrieve the device using the get_device_specification of an Engine object. This is a protocol buffer message that contains information about the qubits on the device, the connectivity, and the supported gates.

This proto can be queried directly to get information about the device or can be transformed into a cirq.Device by using cirq_google.GridDevice.from_proto() that will enforce constraints imposed by the hardware.

See the Device Specification page for more information on device specifications.

Calibration Metrics

Metrics from the current status of the device can be retrieved using the
get_current_calibration method of an EngineProcessor object. EngineProcessor objects can be retrieved from Engine using get_processor. This will return a Python dictionary where each key is the metric name. The value of the dictionary will be the value of the metric, which can also be a dictionary.

For example, the key may refer to a two-qubit gate error, and the value may be a dictionary from 2-tuples of cirq.GridQubits to an error rate represented as a float value.

See the Calibration Metrics page for more information.

Running circuits in batch

Circuits can be batched together. This may improve performance in certain instances (when circuits measure the same qubits and have the same number of repetitions). However, performance is implementation dependant and may change as the underlying server infrastructure evolves.

To use this functionality, use the run_batch() method of the sampler associated with the processor. This will return a Sequence of Sequences of cirq.Result objects.

Downloading historical results

Results from previous computations are archived and can be downloaded later by those in the same cloud project. You must use the same project id to access historical results or your request will be denied.

Each time that you run a circuit or sweep, the Engine class will generate a program id and job id for you. (You can also specify the program and job id yourself when running the program). Both the program and job id will need to be unique within the project. In order to retrieve previous results, you will need both this program id as well as the job id. If these were generated by the Engine, they can be retrieved from the job object when you run a sweep. Currently, getting the program and job ids can only be done through the Engine interface and not through the sampler interface. You can then use get_program and get_job to retrieve the results. See below for an example:

# Initialize the engine object
engine = cirq_google.Engine(project_id='YOUR_PROJECT_ID')

# Create an example circuit
qubit = cirq.GridQubit(5, 2)
circuit = cirq.Circuit(
    cirq.X(qubit)**sympy.Symbol('t'),
    cirq.measure(qubit, key='result')
)
param_sweep = cirq.Linspace('t', start=0, stop=1, length=10)

# Run the circuit
job = e.run_sweep(program=circuit,
                  params=param_sweep,
                  repetitions=1000,
                  processor_id='PROCESSOR_ID',
                  gate_set=GATE_SET)

# Save the program and jo id for later
program_id = job.program_id
job_id = job.job_id

# Retrieve the results
results = job.results()

# ...
# Some time later, the results can be retrieved
# ...

# Recreate the job object
historical_job = engine.get_program(program_id=program_id).get_job(job_id=job_id)

# Retrieve the results
historical_results = historical_job.results()

If you did not save the ids, you can still find them from your job using the Cloud Console or by using our list methods.

Listing jobs

To list the executions of your circuit, i.e. the jobs, you can use cirq_google.Engine.list_jobs(). You can search in all the jobs within your project using filtering criteria on creation time, execution state and labels.

from cirq_google.engine.client.quantum import enums

# Initialize the engine object
engine = cirq_google.Engine(project_id='YOUR_PROJECT_ID')

# List all the jobs on the project since 2020/09/20 that succeeded:
jobs = engine.list_jobs(created_after=datetime.date(2020,9,20),
                        execution_states=[enums.ExecutionStatus.State.SUCCESS])
for j in jobs:
   print(j.job_id, j.status(), j.create_time())

Listing programs

To list the different instances of your circuits uploaded, i.e. the programs, you can use cirq_google.Engine.list_programs(). Similar to jobs, filtering makes it possible to list programs by creation time and labels. With an existing cirq_google.EngineProgram object, you can list any jobs that were run using that program.

from cirq_google.engine.client.quantum import enums

# Initialize the engine object
engine = cirq_google.Engine(project_id='YOUR_PROJECT_ID')

# List all the programs on the project since 2020/09/20 that have
# the "variational" label with any value and the "experiment" label
# with value "vqe001":
programs = engine.list_programs(
                created_after=datetime.date(2020,9,20),
                has_labels={"variational":"*", "experiment":"vqe001"}
           )
for p in programs:
   print(p.program_id, p.create_time())
   # the same filtering parametrization is available as in engine.list_jobs()
   # for example here we list the jobs under the programs that failed
   for j in p.list_jobs(execution_states=[enums.ExecutionStatus.State.FAILURE]):
     print(j.job_id, j.status())