1# Best practices
2
3This section lists some best practices for creating a circuit that performs well
4on Google hardware devices. This is an area of active research, so users are
5encouraged to try multiple approaches to improve results.
6
7This guide is split into three parts:
8*  Getting your circuit to run
9*  Making it run faster
10*  Lowering error
11
12
13## Getting a circuit to run on hardware
14
15In order to run on hardware, the circuit must only use qubits and gates that the
16device supports.  Using inactive qubits, non-adjacent qubits, or non-native
17gates will immediately cause a circuit to fail.
18
19Validating a circuit with a device, such as
20`cirq_google.Sycamore.validate_circuit(circuit)` will test a lot of these
21conditions.  Calling the `validate_circuit` function will work with any
22device, including those retrieved directly from the API using the
23[engine object](./specification.md#serializable-devices), which can help
24identify any qubits used in the circuit that have been disabled on the actual
25device.
26
27
28### Using built-in optimizers as a first pass
29
30Using built-in optimizers will allow you to compile to the correct gate set. As they are
31automated solutions, they will not always perform as well as a hand-crafted solution, but
32they provide a good starting point for creating a circuit that is likely to run successfully
33on hardware. Best practice is to inspect the circuit after optimization to make sure
34that it has compiled without unintended consequences.
35
36```python
37import cirq
38import cirq_google as cg
39
40
41# Create your circuit here
42my_circuit = cirq.Circuit()
43
44# Convert the circuit onto a Google device.
45# Specifying a device will verify that the circuit satisfies constraints of the device
46# The optimizer type (e.g. 'sqrt_iswap' or 'sycamore') specifies which gate set
47# to convert into and which optimization routines are appropriate.
48# This can include combining successive one-qubit gates and ejecting virtual Z gates.
49sycamore_circuit = cg.optimized_for_sycamore(my_circuit, new_device=cg.Sycamore, optimizer_type='sqrt_iswap')
50```
51
52### Using CircuitOperation to reduce circuit size
53
54Particularly large batches (or sweeps) of circuits may encounter errors when
55sent to Quantum Engine due to an upper limit on request size. If the circuits
56in question have a repetitive structure, `cirq.CircuitOperation`s can be used
57to reduce the request size and avoid this limit.
58
59`optimized_for_sycamore` will preserve `CircuitOperation`s while optimizing
60their contents.
61
62```python
63import cirq
64import cirq_google as cg
65
66# Repeatedly apply Hadamard and measurement to 10 qubits.
67my_circuit = cirq.Circuit()
68qubits = cirq.GridQubit.rect(2, 5)
69for i in range(100):
70    my_circuit.append(cirq.H.on_each(*qubits))
71    for q in qubits:
72        my_circuit.append(cirq.measure(q, key=f'm{q}'))
73
74# The same circuit, but defined using CircuitOperations.
75# This is ~1000x smaller when serialized!
76sub_circuit = cirq.Circuit(cirq.H(qubits[0]), cirq.measure(qubits[0], key='m'))
77circuit_op = cirq.CircuitOperation(sub_circuit.freeze())
78circuit_op = circuit_op.with_qubits([q])
79circuit_op = circuit_op.with_measurement_key_mapping({'m': f'm{q}'})
80circuit_op = circuit_op.repeat(100)
81short_circuit = cirq.Circuit(circuit_op for q in qubits)
82```
83
84
85## Running circuits faster
86
87The following sections give tips and tricks that allow you to improve your
88repetition rate (how many repetitions per second the device will run).
89
90This will allow you to make the most out of limited time on the
91device by getting results faster. The shorter experiment time may
92also reduce error due to drift of qubits away from calibration.
93
94There are costs to sending circuits over the network, to compiling each
95circuit into waveforms, to initializing the device,
96and to sending results back over the network.
97These tips will aid you in removing some of this overhead by combining your
98circuits into sweeps or batches.
99
100### Use sweeps when possible
101
102Round trip network time to and from the engine typically adds latency on the order of a second
103to the overall computation time.  Reducing the number of trips and allowing the engine to
104properly batch circuits can improve the throughput of your calculations.  One way to do this
105is to use parameter sweeps to send multiple variations of a circuit at once.
106
107One example is to turn single-qubit gates on or off by using parameter sweeps.
108For instance, the following code illustrates how to combine measuring in the
109Z basis or the X basis in one circuit.
110
111```python
112import cirq
113import sympy
114q = cirq.GridQubit(1, 1)
115sampler = cirq.Simulator()
116
117# STRATEGY #1: Have a separate circuit and sample call for each basis.
118circuit_z = cirq.Circuit(
119    cirq.measure(q, key='out'))
120circuit_x = cirq.Circuit(
121    cirq.H(q),
122    cirq.measure(q, key='out'))
123samples_z = sampler.sample(circuit_z, repetitions=5)
124samples_x = sampler.sample(circuit_x, repetitions=5)
125
126print(samples_z)
127# prints
128#    out
129# 0    0
130# 1    0
131# 2    0
132# 3    0
133# 4    0
134
135print(samples_x)
136# prints something like:
137#    out
138# 0    0
139# 1    1
140# 2    1
141# 3    0
142# 4    0
143
144# STRATEGY #2: Have a parameterized circuit.
145circuit_sweep = cirq.Circuit(
146    cirq.H(q)**sympy.Symbol('t'),
147    cirq.measure(q, key='out'))
148
149samples_sweep = sampler.sample(circuit_sweep,
150                               repetitions=5,
151                               params=[{'t': 0}, {'t': 1}])
152print(samples_sweep)
153# prints something like:
154#    t  out
155# 0  0    0
156# 1  0    0
157# 2  0    0
158# 3  0    0
159# 4  0    0
160# 0  1    0
161# 1  1    1
162# 2  1    1
163# 3  1    0
164# 4  1    1
165```
166
167One word of caution is there is a limit to the total number of repetitions.  Take some care
168that your parameter sweeps, especially products of sweeps, do not become so excessively large
169that they overcome this limit.
170
171### Use batches if sweeps are not possible
172
173The engine has a method called `run_batch()` that can be used to send multiple
174circuits in a single request.  This can be used to increase the efficiency
175of your program so that more repetitions are completed per second.
176
177The circuits that are grouped into the same batch must
178measure the same qubits and have the same number of repetitions for each
179circuit.  Otherwise, the circuits will not be batched together
180on the device, and there will be no gain in efficiency.
181
182
183### Flatten sympy formulas into symbols
184
185Symbols are extremely useful for constructing parameterized circuits (see above).  However,
186only some sympy formulas can be serialized for network transport to the engine.
187Currently, sums and products of symbols, including linear combinations, are supported.
188See `cirq_google.arg_func_langs` for details.
189
190The sympy library is also infamous for being slow, so avoid using complicated formulas if you
191care about performance.  Avoid using parameter resolvers that have formulas in them.
192
193One way to eliminate formulas in your gates is to flatten your expressions.
194The following example shows how to take a gate with a formula and flatten it
195to a single symbol with the formula pre-computed for each value of the sweep:
196
197```python
198import cirq
199import sympy
200
201# Suppose we have a gate with a complicated formula.  (e.g. "2^t - 1")
202# This formula cannot be serialized
203# It could potentially encounter sympy slowness.
204gate_with_formula = cirq.XPowGate(exponent=2 ** sympy.Symbol('t') - 1)
205sweep = cirq.Linspace('t', start=0, stop=1, length=5)
206
207# Instead of sweeping the formula, we will pre-compute the values of the formula
208# at every point and store it a new symbol called '<2**t - 1>'
209sweep_for_gate, flat_sweep = cirq.flatten_with_sweep(gate_with_formula, sweep)
210
211print(repr(sweep_for_gate))
212# prints:
213# (cirq.X**sympy.Symbol('<2**t - 1>'))
214
215# The sweep now contains the non-linear progression of the formula instead:
216print(list(flat_sweep.param_tuples()))
217# prints something like:
218# [(('<2**t - 1>', 0.0),),
219#  (('<2**t - 1>', 0.18920711500272103),),
220#  (('<2**t - 1>', 0.41421356237309515),),
221#  (('<2**t - 1>', 0.681792830507429),),
222#  (('<2**t - 1>', 1.0),)]
223```
224
225## Improving circuit fidelity
226
227The following tips and tricks show how to modify your circuit to
228reduce error rates by following good circuit design principles that
229minimize the length of circuits.
230
231Quantum Engine will execute a circuit as faithfully as possible.
232This means that moment structure will be preserved. That is, all gates in a
233moment are guaranteed to be executed before those in any later moment and
234after gates in previous moments.  Many of these tips focus on having a
235good moment structure that avoids problematic missteps that can cause
236unwanted noise and error.
237
238Note: See the [Circuit optimization, gate alignment, and spin echoes tutorial](../tutorials/google/spin_echoes.ipynb) for an example of the best practices discussed in this section.
239
240### Short gate depth
241
242In the current NISQ (noisy intermediate scale quantum) era, gates and devices still
243have significant error. Both gate errors and T1 decay rate can cause long circuits
244to have noise that overwhelms any signal in the circuit.
245
246The recommended gate depths vary significantly with the structure of the circuit itself
247and will likely increase as the devices improve. Total circuit fidelity can be roughly
248estimated by multiplying the fidelity for all gates in the circuit. For example,
249using a error rate of 0.5% per gate, a circuit of depth 20 and width 20 could be estimated
250at 0.995^(20 * 20) = 0.135. Using separate error rates per gates (i.e. based on calibration
251metrics) or a more complicated noise model can result in more accurate error estimation.
252
253### Terminal Measurements
254
255Make sure that measurements are kept in the same moment as the final moment in
256the circuit.  Make sure that any circuit optimizers do not alter this by
257incorrectly pushing measurements forward. This behavior can be avoided by
258measuring all qubits with a single gate or by adding
259the measurement gate after all optimizers have run.
260
261Currently, only terminal measurements are supported by the hardware.  If you
262absolutely need intermediate measurements for your application, reach out to
263your Google sponsor to see if they can help devise a proper circuit using
264intermediate measurements.
265
266
267### Keep qubits busy
268
269Qubits that remain idle for long periods tend to dephase and decohere. Inserting a
270[Spin Echo](https://en.wikipedia.org/wiki/Spin_echo) into your circuit onto
271qubits that have long idle periods, such as a pair
272of involutions, such as two successive Pauli Y gates, will generally increase
273performance of the circuit.
274
275Be aware that this should be done after calling
276`cirq_google.optimized_for_sycamore`, since this function will 'optimize'
277these operations out of the circuit.
278
279### Delay initialization of qubits
280
281The |0⟩ state is more robust than the |1⟩ state. As a result, one should
282not initialize a qubit to |1⟩ at the beginning of the circuit until shortly
283before other gates are applied to it.
284
285### Align single-qubit and two-qubit layers
286
287Devices are generally calibrated to circuits that alternate single-qubit gates with
288two-qubit gates in each layer. Staying close to this paradigm will often improve
289performance of circuits.  This will also reduce the circuit's total duration,
290since the duration of a moment is its longest gate.  Making sure that each layer
291contains similar gates of the same duration can be challenging, but it will
292likely have a measurable impact on the fidelity of your circuit.
293
294Devices generally operate in the Z basis, so that rotations around the Z axis will become
295book-keeping measures rather than physical operations on the device. These
296virtual Z operations have zero duration and have no cost, if they add no moments
297to your circuit.  In order to guarantee that they do not add moments, you can
298make sure that virtual Z are aggregated into their own layer.  Alternatively,
299you can use the `EjectZ` optimizer to propagate these Z gates forward through
300commuting operators.
301
302See the function `cirq.stratified_circuit` for an automated way to organize gates
303into moments with similar gates.
304
305### Qubit picking
306
307On current NISQ devices, qubits cannot be considered identical.  Different
308qubits can have vastly different performance and can vary greatly from day
309to day.  It is important for experiments to have a dynamic method to
310pick well-performing qubits that maximize the fidelity of the experiment.
311There are several techniques that can assist with this.
312
313*   Analyze calibration metrics:  performance of readout, single-qubit, and
314two-qubit gates are measured as a side effect of running the device's
315calibration procedure.  These metrics can be used as a baseline to evaluate
316circuit performance or identify outliers to avoid.  This data can be inspected
317programmatically by retrieving metrics from the [API](calibration.md) or
318[visually by applying a cirq.Heatmap](../tutorials/google/visualizing_calibration_metrics.md)
319to that data or by using the built-in
320heatmaps in the Cloud console page for the processor.  Note that, since this
321data is only taken during calibration (e.g. at most daily), drifts and other
322concerns may affect the values significantly, so these metrics should only be
323used as a first approximation.  There is no substitute for actually running characterizations
324on the device.
325*   Loschmidt echo:  Running a small circuit on a string of qubits and then
326applying the circuit's inverse can be used as a quick but effective way to
327judge qubit quality.  See
328[this tutorial](../tutorials/google/echoes.ipynb) for instructions.
329*   XEB:  Cross-entropy benchmarking is another way to gauge qubit performance
330on a set of random circuits.  See tutorials on
331[parallel XEB](../qcvv/parallel_xeb.ipynb)
332or [isolated XEB](../qcvv/parallel_xeb.ipynb) for instructions.
333
334
335### Refitting gates
336
337Virtual Z gates (or even single qubit gates) can be added to adjust for errors
338in two qubit gates.  Two qubit gates can have errors due to drift, coherent
339error, unintended cross-talk, or other sources.  Refitting these gates and
340adjusting the circuit for the observed unitary of the two qubit gate
341compared to the ideal unitary can substantially improve results.
342However, this approach can use a substantial amount of resources.
343
344This technique involves two distinct steps.  The first is *characterization*,
345which is to identify the true behavior of the two-qubit gate.  This typically
346involves running many varied circuits involving the two qubit gate in a method
347(either periodic or random) to identify the parameters of the gate's behavior.
348
349Entangling gates used in Google's architecture fall into a general category of FSim gates,
350standing for *Fermionic simulation*.  The generalized version of this gate can
351be parameterized into 5 angles, or degrees of freedom.  Characterization will
352attempt to identify the values of these five angles.
353
354The second step is calibrating (or refitting) the gate.  Out of the five angles
355that comprise the generalized FSim gate, three can be corrected for by adding
356Z rotations before or after the gate.  Since these gates are propagated forward
357automatically, they add no duration or error to the circuit and can essentially
358be added "for free".  See the [devices page](devices.md#virtual_z_gates) for more
359information on Virtual Z gates.  Note that it is important to keep the single-qubit and
360two-qubit gates aligned (see above) while performing this procedure so that
361the circuit stays the same duration.
362
363For more on calibration and detailed instructions on how to perform these procedures, see the following tutorials:
364
365* [Calibration API](../tutorials/google/calibration_api.ipynb)
366* [Floquet calibration example](../tutorials/google/floquet_calibration_example.ipynb)
367* [XEB calibration example](../tutorials/google/xeb_calibration_example.ipynb)
368