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