diff --git a/docs/google/devices.md b/docs/google/devices.md index 8b998fa4201..8ecdb12a9ea 100644 --- a/docs/google/devices.md +++ b/docs/google/devices.md @@ -84,6 +84,77 @@ using a error rate of 0.5% per gate, a circuit of depth 20 and width 20 could be at 0.995^(20*20) = 0.135. Using separate error rates per gates (i.e. based on calibration metrics) or a more complicated noise model can result in more accurate error estimation. +### Use sweeps when possible + +Round trip network time to and from the engine typically adds latency on the order of a second +to the overall computation time. Reducing the number of trips and allowing the engine to +properly batch circuits can improve the throughput of your calculations. One way to do this +is to use parameter sweeps to send multiple variations of a circuit at once. + +One example is to turn single-qubit gates on or off by using parameter sweeps. +For instance, the following code illustrates how to combine measuring in the +Z basis or the X basis in one circuit. + +```python +import cirq +import sympy +q = cirq.GridQubit(1, 1) +sampler = cirq.Simulator() + +# STRATEGY #1: Have a separate circuit and sample call for each basis. +circuit_z = cirq.Circuit( + cirq.measure(q, key='out')) +circuit_x = cirq.Circuit( + cirq.H(q), + cirq.measure(q, key='out')) +samples_z = sampler.sample(circuit_z, repetitions=5) +samples_x = sampler.sample(circuit_x, repetitions=5) + +print(samples_z) +# prints +# out +# 0 0 +# 1 0 +# 2 0 +# 3 0 +# 4 0 + +print(samples_x) +# prints something like: +# out +# 0 0 +# 1 1 +# 2 1 +# 3 0 +# 4 0 + +# STRATEGY #2: Have a parameterized circuit. +circuit_sweep = cirq.Circuit( + cirq.H(q)**sympy.Symbol('t'), + cirq.measure(q, key='out')) + +samples_sweep = sampler.sample(circuit_sweep, + repetitions=5, + params=[{'t': 0}, {'t': 1}]) +print(samples_sweep) +# prints something like: +# t out +# 0 0 0 +# 1 0 0 +# 2 0 0 +# 3 0 0 +# 4 0 0 +# 0 1 0 +# 1 1 1 +# 2 1 1 +# 3 1 0 +# 4 1 1 +``` + +One word of caution is there is a limit to the total number of repetitions. Take some care +that your parameter sweeps, especially products of sweeps, do not become so excessively large +that they overcome this limit. + ### Keep qubits busy @@ -105,6 +176,16 @@ of the circuit by pushing them back to the next non-commuting operator. If the r circuit still contains Z operations, they should be aggregated into their own moment, if possible. +### Use caution with symbols + +Symbols are extremely useful for constructing parameterized circuits (see above). However, +only some sympy formulas can be serialized for network transport to the engine. +Currently, sums and products of symbols, including linear combinations, are supported. +See `cirq.google.arg_func_langs` for details. + +The sympy library is also infamous for being slow, so avoid using complicated formulas if you +care about performance. Avoid using parameter resolvers that have formulas in them. + ## Specific Device Layouts ### Sycamore diff --git a/docs/google/engine.md b/docs/google/engine.md new file mode 100644 index 00000000000..019db9d7e67 --- /dev/null +++ b/docs/google/engine.md @@ -0,0 +1,107 @@ +# Quantum Engine + +The Quantum Engine, via the `cirq.google.Engine` class, executes programs and jobs using the +Quantum Engine API. + +Note that the Quantum Engine API is not yet open for public access. + +## 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 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](https://cloud.google.com/docs/authentication/production) 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](https://console.cloud.google.com)). +You can use this instance to run quantum circuits or sweeps (parameterized +variants of a general circuit). + + + +```python +import cirq +import cirq.google as cg +import random +import string + +# 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 to use. +# Replace YOUR_PROJECT_ID with the id from your cloud project. +engine = cg.Engine(project_id=YOUR_PROJECT_ID, proto_version=cg.ProtoVersion.V2) + +# Create a sampler from the engine +sampler = engine.sampler(processor_id='PROCESSOR_ID', gate_set=cg.SYC_GATESET) + +# This will run the circuit and return the results in a 'TrialResult' +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](devices.md) page. + +However, you can also retrieve the device using the `get_device_specification` of an +`Engine` object. This is a [protocol buffer](https://developers.google.com/protocol-buffers) +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.SerializableDevice.from_proto()` that will +enforce constraints imposed by the hardware. + +See the [Device Specification](specification.md) page for more information on +device specifications. + + +## Calibration Metrics + +Metrics from the current status of the device can be retrieved using the\ +`get_latest_calibration` method of the `Engine` object. 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. + +Information about specific metrics will be released at a later date. diff --git a/docs/google/index.rst b/docs/google/index.rst index 02e1feabc05..b0ba5165aa3 100644 --- a/docs/google/index.rst +++ b/docs/google/index.rst @@ -10,3 +10,5 @@ of devices that have become public information. :maxdepth: 1 devices + engine + specification diff --git a/docs/google/specification.md b/docs/google/specification.md new file mode 100644 index 00000000000..4a7ef054c43 --- /dev/null +++ b/docs/google/specification.md @@ -0,0 +1,130 @@ +# Device Specifications + +The device specification proto defines basic layout of a device as well as the +gate set and serialized ids that can be used. This specification can be used +to find out specific characteristics of though. + +Though several standard [Google devices](devices.md) are defined for your +convenience, specific devices may have specialized layouts particular to that +processor. For instance, there may be one or more qubit "drop-outs" that are +non-functional for whatever reason. There could also be new or experimental +features enabled on some devices but not on others. + +This specification is defined in the Device proto within `cirq.google.api.v2`. + +## Gate Set Specifications + +Most devices can only accept a limited set of gates. This is known as the +gate set of the device. Any circuits sent to this device must only use gates +within this set. The gate set portion of the protocol buffer defines which +gate set(s) are valid on the device, and which gates make up that set. + +### Gate Definitions + +Each gate in the gate set will have a definition that defines the id that +the gate is serialized as, the number of qubits for the gates, the arguments +to the gate, the duration, and which qubits it can be applied to. + +This definition uses "target sets" to specify which qubits the operation can +be applied to. See the section below for more information. + +### Gate Durations + +The time it takes the device to perform each gate is stored within the device +specification. This time is stored as an integer number of picoseconds. + +Example code to print out the gate durations for every gate supported by the +device is shown below: + +``` +import cirq + +# Create an Engine object to use. +engine = cirq.google.Engine(project_id='your_project_id', + proto_version=cirq.google.ProtoVersion.V2) + +# Replace the processor id to get the device specification with that id. +spec = engine.get_device_specification('processor_id') + +# Iterate through each gate set valid on the device. +for gateset in spec.valid_gate_sets: + print(gateset.name) + print('-------') + # Prints each gate valid in the set with its duration + for gate in gateset.valid_gates: + print('%s %d' % (gate.id, gate.gate_duration_picos)) +``` + +Note that, by convention, measurement gate duration includes both the duration +of "read-out" pulses to measure the qubit as well as the "ring-down" time that +it takes the measurement resonator to reset to a ground state. + +## Target Sets + +Generally, most gates apply to the same set of qubits. To avoid repeating +these qubits (or pairs of qubits) for each gate, each gate instead uses a +target set to define the set of qubits that are valid. + +Each target set contains a list of valid targets. A target is a list of qubits. +For one-qubit gates, a target is simply a single qubit. For two qubit gates, +a target is a pair of qubits. + +The type of a target set defines how the targets are interpreted. If the +target set is set to SYMMETRIC, the order of each target does not matter (e.g. +if `gate.on(q1, q2)` is valid, then so is `gate.on(q2, q1)`). If the target +type is set to ASSYMMETRIC, then the order of qubits does matter, and other +orderings of the qubits that are not specified in the definition cannot be +assumed to be valid. + +The last type is PERMUTATION_SET. This type specified that any permutation of +the targets is valid. This is typically used for measurement gates. If `q0`, +`q1` and `q2` are all specified as valid targets for a permutation set of the +gate, then `gate.on(q0)`, `gate.on(q1)`, `gate.on(q2)`, `gate.on(q0, q1)`, +`gate.on(q0, q2)`, `gate.on(q1, q2)` and `gate.on(q0, q1, q2)` are all valid +uses of the gate. + +### Developer Recommendations + +This is a free form text field for additional recommendations and soft +requirements that should be followed for proper operation of the device that +are not captured by the hard requirements above. + +For instance, "Do not apply two CZ gates in a row." + +## Serializable Devices + +The `cirq.google.SerializableDevice` class allows someone to take this +device specification and turn it into a `cirq.Device` that can be used to +verify a circuit. + +The `cirq.google.SerializableDevice` combines a `DeviceSpecification` protocol +buffer (defining the device) with a `SerializableGateSet` (that defines the +translation from serialized id to cirq) to produce a `cirq.Device` that can +be used to validate a circuit. + +The following example illustrates retrieving the device specification live +from the engine and then using it to validate a circuit. + +``` +import cirq +import cirq.google as cg + +# Create an Engine object to use. +engine = cg.Engine(project_id='your_project_id', + proto_version=cirq.google.ProtoVersion.V2) + +# Replace the processor id to get the device specification with that id. +spec = engine.get_device_specification('processor_id') + +device = cg.SerializableDevice.from_proto( + proto=spec, + gate_sets=[cg.gate_sets.SQRT_ISWAP_GATESET) + +q0, q1 = cirq.LineQubit.range(2) + +# Raises a ValueError, since this is not a supported gate. +cirq.Circuit(cirq.CZ(q0,q1), device=device) +``` + +Note that, if network traffic is undesired, the `DeviceSpecification` can +easily be stored in either binary format or TextProto format for later usage.