![]() |
![]() |
![]() |
![]() |
try:
import cirq
except ImportError:
print("installing cirq...")
!pip install --quiet cirq
print("installed cirq.")
Circuit optimizers
Cirq comes with the concept of an optimizer. Optimizers will pass over a circuit and perform tasks that will modify the circuit in place. These can be used to transform a circuit in specific ways, such as combining single-qubit gates, commuting Z gates through the circuit, or readying the circuit for certain hardware or gate set configurations.
Optimizers will have a function optimize_circuit()
that can be used to perform this optimization. Here is a simple example that removes empty moments:
import cirq
c=cirq.Circuit()
c.append(cirq.Moment([]))
c.append(cirq.Moment([cirq.X(cirq.GridQubit(1,1))]))
c.append(cirq.Moment([]))
print(f'Before optimization, Circuit has {len(c)} moments')
cirq.DropEmptyMoments().optimize_circuit(circuit=c)
print(f'After optimization, Circuit has {len(c)} moments')
Before optimization, Circuit has 3 moments After optimization, Circuit has 1 moments
Optimizers that come with cirq can be found in the cirq.optimizers
package.
A few notable examples are:
- ConvertToCzAndSingleGates: Attempts to convert a circuit into CZ gates and single qubit gates. This uses gate's unitary and decompose methods to transform them into CZ + single qubit gates.
- DropEmptyMoments / DropNegligible: Removes moments that are empty or have very small effects, respectively.
- EjectPhasedPaulis: Pushes X, Y, and PhasedX gates towards the end of the circuit, potentially absorbing Z gates and modifying gates along the way.
- EjectZ: Pushes Z gates towards the end of the circuit, potentially adjusting phases of gates that they pass through.
- ExpandComposite: Uses
cirq.decompose
to expand composite gates. - MergeInteractions: Combines series of adjacent one and two-qubit gates acting on a pair of qubits.
- MergeSingleQubitGates: Combines series of adjacent unitary 1-qubit operations
- SynchronizeTerminalMeasurements: Moves all measurements in a circuit to the final moment if possible.
Create your own optimizers
You can create your own optimizers to transform and modify circuits to fit hardware, gate sets, or other requirements. Optimizers can also be used to generate noise. See noise for details.
You can do this by implementing the function optimize_circuit
.
If your optimizer is a local optimizer and depends primarily on operator being examined, you can alternatively inherit cirq.PointOptimizer
and implement the function optimization_at(self, circuit, index, op)
that optimizes a single operation.
Below is an example of implementing a simple PointOptimizer
that removes measurements.
class RemoveMeasurements(cirq.PointOptimizer):
def optimization_at(self, circuit: cirq.Circuit, index: int, op: cirq.Operation):
if isinstance(op.gate, cirq.MeasurementGate):
return cirq.PointOptimizationSummary(clear_span=1,
new_operations=[],
clear_qubits=op.qubits)
else:
return None
q=cirq.LineQubit(0)
c=cirq.Circuit(cirq.X(q), cirq.measure(q))
print('Before optimization')
print(c)
RemoveMeasurements().optimize_circuit(c)
print('After optimization')
print(c)
Before optimization 0: ───X───M─── After optimization 0: ───X───────