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