View on QuantumAI | Run in Google Colab | View source on GitHub | Download notebook |
Setup
try:
import cirq
except ImportError:
print("installing cirq...")
!pip install --quiet cirq
import cirq
print("installed cirq.")
What is a Transformer?
A transformer in Cirq is any callable that satisfies the cirq.TRANSFORMER
API, and transforms an input circuit into an output circuit.
Circuit transformations are often necessary to compile a user-defined circuit to an equivalent circuit that satisfies the constraints necessary to be executable on a specific device or simulator. The compilation process often involves steps like:
- Gate Decompositions: Rewrite the circuit using only gates that belong to the device target gateset, i.e. set of gates which the device can execute.
- Qubit Mapping and Routing: Map the logic qubits in the input circuit to physical qubits on the device and insert appropriate swap operations such that final circuit respects the hardware topology.
- Circuit Optimizations: Perform hardware specific optimizations, like merging and replacing connected components of 1 and 2 operations with more efficient rewrite operations, commuting Z gates through the circuit, aligning gates in moments and more.
Cirq provides many out-of-the-box transformers which can be used as individual compilation passes. It also supplies a general framework for users to create their own transformers, by using powerful primitives and by bundling existing transformers together, to enable the compilation of circuits for specific targets. This page covers the available transformers in Cirq, how to use them, and how to write a simple transformer. The Custom Transformers page presents the details on creating more complex custom transformers through primitives and composition.
Built-in Transformers in Cirq
Overview
Transformers that come with cirq can be found in the /cirq/transformers
package.
A few notable examples are:
cirq.align_left
/cirq.align_right
: Align gates to the left/right of the circuit by sliding them as far as possible along each qubit in the chosen direction.cirq.defer_measurements
: Moves all (non-terminal) measurements in a circuit to the end of circuit by implementing the deferred measurement principle.cirq.drop_empty_moments
/cirq.drop_negligible_operations
: Removes moments that are empty or operations that have very small effects, respectively.cirq.eject_phased_paulis
: Pushes X, Y, and PhasedX gates towards the end of the circuit, potentially absorbing Z gates and modifying gates along the way.cirq.eject_z
: Pushes Z gates towards the end of the circuit, potentially adjusting phases of gates that they pass through.cirq.expand_composite
: Usescirq.decompose
to expand gates built from other gates (composite gates).cirq.merge_k_qubit_unitaries
: Replaces connected components of unitary operations, acting on <= k qubits, with op-tree given byrewriter(circuit_op)
.cirq.optimize_for_target_gateset
: Attempts to convert a circuit into an equivalent circuit using only gates from a given target gateset.cirq.stratified_circuit
: Repacks the circuit to ensure that moments only contain operations from the same category.cirq.synchronize_terminal_measurements
: Moves all terminal measurements in a circuit to the final moment, if possible.
Below you can see how to implement a transformer pipeline as a function called optimize_circuit
, which composes a few of the available Cirq transformers.
def optimize_circuit(circuit, context=None, k=2):
# Merge 2-qubit connected components into circuit operations.
optimized_circuit = cirq.merge_k_qubit_unitaries(
circuit, k=k, rewriter=lambda op: op.with_tags("merged"), context=context
)
# Drop operations with negligible effect / close to identity.
optimized_circuit = cirq.drop_negligible_operations(optimized_circuit, context=context)
# Expand all remaining merged connected components.
optimized_circuit = cirq.expand_composite(
optimized_circuit, no_decomp=lambda op: "merged" not in op.tags, context=context
)
# Synchronize terminal measurements to be in the same moment.
optimized_circuit = cirq.synchronize_terminal_measurements(optimized_circuit, context=context)
# Assert the original and optimized circuit are equivalent.
cirq.testing.assert_circuits_with_terminal_measurements_are_equivalent(
circuit, optimized_circuit
)
return optimized_circuit
q = cirq.LineQubit.range(3)
circuit = cirq.Circuit(
cirq.H(q[1]),
cirq.CNOT(*q[1:]),
cirq.H(q[0]),
cirq.CNOT(*q[:2]),
cirq.H(q[1]),
cirq.CZ(*q[:2]),
cirq.H.on_each(*q[:2]),
cirq.CNOT(q[2], q[0]),
cirq.measure_each(*q),
)
print("Original Circuit:", circuit, sep="\n")
print("Optimized Circuit:", optimize_circuit(circuit), sep="\n")
Original Circuit: ┌──┐ 0: ───H───────@───────@───H────X─────M─── │ │ │ 1: ───H───@───X───H───@───H────┼M──────── │ │ 2: ───────X────────────────────@─────M─── └──┘ Optimized Circuit: 0: ───────────X───M─── │ 1: ───H───@───┼───M─── │ │ 2: ───────X───@───M───
Inspecting transformer actions
Every transformer in Cirq accepts a cirq.TransformerContext
instance, which stores common configurable options useful for all transformers.
One of the members of transformer context dataclass is cirq.TransformerLogger
instance. When a logger instance is specified, every cirq transformer logs its action on the input circuit using the given logger instance. The logs can then be inspected to understand the action of each individual transformer on the circuit.
Below, you can inspect the action of each transformer in the optimize_circuit
method defined above.
context = cirq.TransformerContext(logger=cirq.TransformerLogger())
optimized_circuit = optimize_circuit(circuit, context)
context.logger.show()
Transformer-1: merge_k_qubit_unitaries Initial Circuit: ┌──┐ 0: ───H───────@───────@───H────X─────M─── │ │ │ 1: ───H───@───X───H───@───H────┼M──────── │ │ 2: ───────X────────────────────@─────M─── └──┘ Final Circuit: ┌───────────────────────┐ [ 0: ───H───@───────@───H─── ] [ 0: ───X─── ] 0: ────────────────────────────────[ │ │ ]─────────────[ │ ]────────────M─── [ 1: ───────X───H───@───H─── ][merged] [ 2: ───@─── ][merged] │ │ [ 1: ───H───@─── ] │ │ 1: ───[ │ ]───────────#2────────────────────────────────────────M┼───────────────────────────── [ 2: ───────X─── ][merged] │ │ │ 2: ───#2──────────────────────────────────────────────────────────────────────#2────────────────────────M─── └───────────────────────┘ ---------------------------------------- Transformer-2: drop_negligible_operations Initial Circuit: ┌───────────────────────┐ [ 0: ───H───@───────@───H─── ] [ 0: ───X─── ] 0: ────────────────────────────────[ │ │ ]─────────────[ │ ]────────────M─── [ 1: ───────X───H───@───H─── ][merged] [ 2: ───@─── ][merged] │ │ [ 1: ───H───@─── ] │ │ 1: ───[ │ ]───────────#2────────────────────────────────────────M┼───────────────────────────── [ 2: ───────X─── ][merged] │ │ │ 2: ───#2──────────────────────────────────────────────────────────────────────#2────────────────────────M─── └───────────────────────┘ Final Circuit: ┌───────────────────────┐ [ 0: ───X─── ] 0: ──────────────────────────────────────[ │ ]────────────M─── [ 2: ───@─── ][merged] │ [ 1: ───H───@─── ] │ 1: ───[ │ ]────────────────M┼───────────────────────────── [ 2: ───────X─── ][merged] │ │ │ 2: ───#2─────────────────────────────────#2────────────────────────M─── └───────────────────────┘ ---------------------------------------- Transformer-3: expand_composite Initial Circuit: ┌───────────────────────┐ [ 0: ───X─── ] 0: ──────────────────────────────────────[ │ ]────────────M─── [ 2: ───@─── ][merged] │ [ 1: ───H───@─── ] │ 1: ───[ │ ]────────────────M┼───────────────────────────── [ 2: ───────X─── ][merged] │ │ │ 2: ───#2─────────────────────────────────#2────────────────────────M─── └───────────────────────┘ Final Circuit: ┌──┐ 0: ─────────────X────M─── │ 1: ───H───@────M┼──────── │ │ 2: ───────X─────@────M─── └──┘ ---------------------------------------- Transformer-4: synchronize_terminal_measurements Initial Circuit: ┌──┐ 0: ─────────────X────M─── │ 1: ───H───@────M┼──────── │ │ 2: ───────X─────@────M─── └──┘ Final Circuit: 0: ───────────X───M─── │ 1: ───H───@───┼───M─── │ │ 2: ───────X───@───M─── ----------------------------------------
By first using cirq.merge_k_qubit_unitaries
to turn connected components of the circuit into cirq.CircuitOperation
s, cirq.drop_negligible_operations
was able to identify that one of the merged connected components was equivalent to the identity operation and remove it. The remaining steps returned the circuit to a more typical state, expanding intermediate cirq.CircuitOperation
s and aligning measurements to be terminal measurements.
Support for no-compile tags
Cirq also supports tagging operations with no-compile tags such that these tagged operations are ignored when applying transformations on the circuit. This allows users to gain more fine-grained conrol over the compilation process.
Any valid tag can be used as a "no-compile" tag by adding it to the tags_to_ignore
field in cirq.TransformerContext
. When called with a context, cirq transformers will inspect the context.tags_to_ignore
field and ignore an operation if op.tags & context.tags_to_ignore
is not empty.
Below, you can use no-compile tags when transforming a circuit using the optimize_circuit
mehod defined above.
# Echo pulses inserted in the circuit to prevent dephasing during idling should be ignored.
circuit = cirq.Circuit(
cirq.H(q[0]),
cirq.CNOT(*q[:2]),
[
op.with_tags("spin_echoes") for op in [cirq.X(q[0]) ** 0.5, cirq.X(q[0]) ** -0.5]
], # the echo pulses
[cirq.CNOT(*q[1:]), cirq.CNOT(*q[1:])],
[cirq.CNOT(*q[:2]), cirq.H(q[0])],
cirq.measure_each(*q),
)
# Original Circuit
print("Original Circuit:", circuit, "\n", sep="\n")
# Optimized Circuit without tags_to_ignore
print("Optimized Circuit without specifying tags_to_ignore:")
print(optimize_circuit(circuit, k=1), "\n")
# Optimized Circuit ignoring operations marked with tags_to_ignore.
print("Optimized Circuit while ignoring operations marked with tags_to_ignore:")
context = cirq.TransformerContext(tags_to_ignore=["spin_echoes"])
print(optimize_circuit(circuit, k=1, context=context), "\n")
Original Circuit: 0: ───H───@───X[spin_echoes]^0.5───X[spin_echoes]^-0.5───@───H───M─── │ │ 1: ───────X───@────────────────────@─────────────────────X───M─────── │ │ 2: ───────────X────────────────────X─────────────────────M─────────── Optimized Circuit without specifying tags_to_ignore: 0: ───H───@───────────@───H───M─── │ │ 1: ───────X───@───@───X───────M─── │ │ 2: ───────────X───X───────────M─── Optimized Circuit while ignoring operations marked with tags_to_ignore: 0: ───H───@───X[spin_echoes]^0.5───X[spin_echoes]^-0.5───@───H───M─── │ │ 1: ───────X───@────────────────────@─────────────────────X───────M─── │ │ 2: ───────────X────────────────────X─────────────────────────────M───
Support for recursively transforming sub-circuits
By default, an operation op
of type cirq.CircuitOperation
is considered as a single top-level operation by cirq transformers. As a result, the sub-circuits wrapped inside circuit operations will often be left as it is and a transformer will only modify the top-level circuit.
If you wish to recursively run a transformer on every nested sub-circuit wrapped inside a cirq.CircuitOperation
, you can set context.deep=True
in the cirq.TransformerContext
object. Note that tagged circuit operations marked with any of context.tags_to_ignore
will be ignored even if context.deep is True
. See the example below for a better understanding.
q = cirq.LineQubit.range(2)
circuit_op = cirq.CircuitOperation(
cirq.FrozenCircuit(cirq.I.on_each(*q), cirq.CNOT(*q), cirq.I(q[0]).with_tags("ignore"))
)
circuit = cirq.Circuit(
cirq.I(q[0]), cirq.I(q[1]).with_tags("ignore"), circuit_op, circuit_op.with_tags("ignore")
)
print("Original Circuit:", circuit, "\n", sep="\n\n")
context = cirq.TransformerContext(tags_to_ignore=["ignore"], deep=False)
print("Optimized Circuit with deep=False and tags_to_ignore=['ignore']:\n")
print(cirq.drop_negligible_operations(circuit, context=context), "\n\n")
context = cirq.TransformerContext(tags_to_ignore=["ignore"], deep=True)
print("Optimized Circuit with deep=True and tags_to_ignore=['ignore']:\n")
print(cirq.drop_negligible_operations(circuit, context=context), "\n")
Original Circuit: [ 0: ───I───@───I[ignore]─── ] [ 0: ───I───@───I[ignore]─── ] 0: ───I───────────[ │ ]───[ │ ]─────────── [ 1: ───I───X─────────────── ] [ 1: ───I───X─────────────── ][ignore] │ │ 1: ───I[ignore]───#2───────────────────────────────#2─────────────────────────────────────── Optimized Circuit with deep=False and tags_to_ignore=['ignore']: [ 0: ───I───@───I[ignore]─── ] [ 0: ───I───@───I[ignore]─── ] 0: ───────────────[ │ ]───[ │ ]─────────── [ 1: ───I───X─────────────── ] [ 1: ───I───X─────────────── ][ignore] │ │ 1: ───I[ignore]───#2───────────────────────────────#2─────────────────────────────────────── Optimized Circuit with deep=True and tags_to_ignore=['ignore']: [ 0: ───────@───I[ignore]─── ] [ 0: ───I───@───I[ignore]─── ] 0: ───────────────[ │ ]───[ │ ]─────────── [ 1: ───────X─────────────── ] [ 1: ───I───X─────────────── ][ignore] │ │ 1: ───I[ignore]───#2───────────────────────────────#2───────────────────────────────────────
The leading identity gate that wasn't tagged was removed from both optimized circuits, but the identity gates within each cirq.CircuitOperation
were removed if deep = true
and the CircuitOperation
wasn't tagged and the identity operation wasn't tagged.
Compiling to NISQ targets: cirq.CompilationTargetGateset
Cirq's philosophy on compiling circuits for execution on a NISQ target device or simulator is that it would often require running only a handful of individual compilation passes on the input circuit, one after the other.
cirq.CompilationTargetGateset
is an abstraction in Cirq to represent such compilation targets as well as the bundles of transformer passes which should be executed to compile a circuit to this target. Cirq has implementations for common target gatesets like cirq.CZTargetGateset
, cirq.SqrtIswapTargetGateset
etc.
cirq.optimize_for_target_gateset
is a transformer which compiles a given circuit for a cirq.CompilationTargetGateset
via the following steps:
- Run all
gateset.preprocess_transformers
- Convert operations using built-in
cirq.decompose
+gateset.decompose_to_target_gateset
. - Run all
gateset.postprocess_transformers
The preprocess transformers often includes optimizations like merging connected components of 1/2 qubit unitaries into a single unitary matrix, which can then be replaced with an efficient analytical decomposition as part of step-2.
The post-process transformers often includes cleanups and optimizations like dropping negligible operations, converting single qubit rotations into desired form, circuit alignments etc.
# Original QFT Circuit on 3 qubits.
q = cirq.LineQubit.range(3)
circuit = cirq.Circuit(cirq.QuantumFourierTransformGate(3).on(*q), cirq.measure(*q))
print("Original Circuit:", circuit, "\n", sep="\n")
# Compile the circuit for CZ Target Gateset.
gateset = cirq.CZTargetGateset(allow_partial_czs=True)
cz_circuit = cirq.optimize_for_target_gateset(circuit, gateset=gateset)
cirq.testing.assert_circuits_with_terminal_measurements_are_equivalent(circuit, cz_circuit)
print("Circuit compiled for CZ Target Gateset:", cz_circuit, "\n", sep="\n")
Original Circuit: 0: ───qft───M─── │ │ 1: ───#2────M─── │ │ 2: ───#3────M─── Circuit compiled for CZ Target Gateset: 0: ───PhXZ(a=0.5,x=0.5,z=0)───@────────PhXZ(a=1.11e-16,x=1,z=0)───────────PhXZ(a=0.5,x=-0.5,z=0)───@───PhXZ(a=0.5,x=0.5,z=0)────@───PhXZ(a=0.5,x=-0.5,z=0)───@────────PhXZ(a=0.5,x=0.5,z=-1)───M─── │ │ │ │ │ 1: ───────────────────────────@^-0.5───PhXZ(a=-1,x=0.5,z=-0.5)────@────────────────────────────────┼────────────────────────────┼────────────────────────────┼─────────────────────────────────M─── │ │ │ │ │ 2: ───────────────────────────────────────────────────────────────@^0.5───PhXZ(a=0.5,x=-0.5,z=0)───@───PhXZ(a=0.5,x=-0.5,z=0)───@───PhXZ(a=0.5,x=0.5,z=0)────@^0.75───PhXZ(a=0,x=0,z=0.25)─────M───
cirq.optimize_for_target_gateset
also supports all the features discussed above, using cirq.TransformerContext
. For example, you can compile the circuit for sqrt-iswap target gateset and inspect action of individual transformers using cirq.TransformerLogger
, as shown below.
context = cirq.TransformerContext(logger=cirq.TransformerLogger())
gateset = cirq.SqrtIswapTargetGateset()
sqrt_iswap_circuit = cirq.optimize_for_target_gateset(circuit, gateset=gateset, context=context)
cirq.testing.assert_circuits_with_terminal_measurements_are_equivalent(circuit, sqrt_iswap_circuit)
context.logger.show()
Transformer-1: optimize_for_target_gateset Initial Circuit: 0: ───qft───M─── │ │ 1: ───#2────M─── │ │ 2: ───#3────M─── Final Circuit: 0: ───PhXZ(a=-1,x=0.676,z=-0.5)────────iSwap───────PhXZ(a=-0.5,x=0,z=-1)────iSwap───────PhXZ(a=0,x=0.5,z=-0.574)──────────────────────────────────────────────────────────────────PhXZ(a=-0.5,x=0.5,z=-1)──────────iSwap───────PhXZ(a=0.585,x=0.5,z=-0.585)───iSwap───────PhXZ(a=-0.5,x=0.199,z=0)───iSwap───────PhXZ(a=0.879,x=0.532,z=-0.457)───M─── │ │ │ │ │ │ 1: ───PhXZ(a=0.709,x=0.136,z=-0.709)───iSwap^0.5───PhXZ(a=-1,x=0.364,z=0)───iSwap^0.5───PhXZ(a=0.999,x=0.866,z=0.542)────iSwap────────────────────────────────────────iSwap───────PhXZ(a=-1,x=0.5,z=0.748)─────────┼──────────────────────────────────────────┼──────────────────────────────────────┼────────────────────────────────────────────M─── │ │ │ │ │ │ 2: ─────────────────────────────────────────────────────────────────────────────────────PhXZ(a=0.966,x=0.864,z=-0.966)───iSwap^0.5───PhXZ(a=2.22e-16,x=0.364,z=1.0)───iSwap^0.5───PhXZ(a=-0.299,x=0.584,z=0.907)───iSwap^0.5───PhXZ(a=0.852,x=0.5,z=-0.852)───iSwap^0.5───PhXZ(a=-0.5,x=0.623,z=0)───iSwap^0.5───PhXZ(a=-0.5,x=0.648,z=0.625)─────M─── ---------------------------------------- Transformer-2: expand_composite Initial Circuit: 0: ───qft───M─── │ │ 1: ───#2────M─── │ │ 2: ───#3────M─── Final Circuit: 0: ───H───Grad^0.5───────────────@────────────×───M─── │ │ │ │ 1: ───────@──────────H───@───────┼────────────┼───M─── │ │ │ │ 2: ──────────────────────@^0.5───@^0.25───H───×───M─── ---------------------------------------- Transformer-3: merge_k_qubit_unitaries Initial Circuit: 0: ───H───Grad^0.5───────────────@────────────×───M─── │ │ │ │ 1: ───────@──────────H───@───────┼────────────┼───M─── │ │ │ │ 2: ──────────────────────@^0.5───@^0.25───H───×───M─── Final Circuit: [ 0: ───H───Grad^0.5─────── ] [ 0: ───@────────────×─── ] 0: ───[ │ ]──────────────────────────────────────────────────────────────────────────────────────────────[ │ │ ]──────────────────────────────────────M─── [ 1: ───────@──────────H─── ][_default_merged_k_qubit_unitaries] [ 2: ───@^0.25───H───×─── ][_default_merged_k_qubit_unitaries] │ │ │ │ │ [ 1: ───@─────── ] │ │ 1: ───#2─────────────────────────────────────────────────────────────────[ │ ]──────────────────────────────────────┼────────────────────────────────────────────────────────────────M─── [ 2: ───@^0.5─── ][_default_merged_k_qubit_unitaries] │ │ │ │ │ 2: ──────────────────────────────────────────────────────────────────────#2──────────────────────────────────────────────────────#2───────────────────────────────────────────────────────────────M─── ---------------------------------------- Transformer-4: _decompose_operations_to_target_gateset Initial Circuit: [ 0: ───H───Grad^0.5─────── ] [ 0: ───@────────────×─── ] 0: ───[ │ ]──────────────────────────────────────────────────────────────────────────────────────────────[ │ │ ]──────────────────────────────────────M─── [ 1: ───────@──────────H─── ][_default_merged_k_qubit_unitaries] [ 2: ───@^0.25───H───×─── ][_default_merged_k_qubit_unitaries] │ │ │ │ │ [ 1: ───@─────── ] │ │ 1: ───#2─────────────────────────────────────────────────────────────────[ │ ]──────────────────────────────────────┼────────────────────────────────────────────────────────────────M─── [ 2: ───@^0.5─── ][_default_merged_k_qubit_unitaries] │ │ │ │ │ 2: ──────────────────────────────────────────────────────────────────────#2──────────────────────────────────────────────────────#2───────────────────────────────────────────────────────────────M─── Final Circuit: 0: ───PhXZ(a=-1,x=0.676,z=-0.5)────────iSwap───────PhXZ(a=-0.5,x=0,z=-1)────iSwap───────PhXZ(a=0,x=0.5,z=-0.574)────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────PhXZ(a=-0.5,x=0.5,z=-1)───iSwap───────PhXZ(a=0.585,x=0.5,z=-0.585)───iSwap───────PhXZ(a=-0.5,x=0.199,z=0)───iSwap───────PhXZ(a=0.879,x=0.532,z=-0.457)───M─── │ │ │ │ │ │ 1: ───PhXZ(a=0.709,x=0.136,z=-0.709)───iSwap^0.5───PhXZ(a=-1,x=0.364,z=0)───iSwap^0.5───PhXZ(a=0.537,x=0.483,z=-0.172)───PhXZ(a=0.498,x=0.5,z=-0.498)─────iSwap────────────────────────────────────────iSwap───────PhXZ(a=-1,x=0.5,z=0.748)───────────────────────────────┼──────────────────────────────────────────┼──────────────────────────────────────┼────────────────────────────────────────────M─── │ │ │ │ │ │ 2: ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────PhXZ(a=0.966,x=0.864,z=-0.966)───iSwap^0.5───PhXZ(a=2.22e-16,x=0.364,z=1.0)───iSwap^0.5───PhXZ(a=-1,x=0.864,z=0.216)───PhXZ(a=-0.5,x=0.5,z=0)────iSwap^0.5───PhXZ(a=0.852,x=0.5,z=-0.852)───iSwap^0.5───PhXZ(a=-0.5,x=0.623,z=0)───iSwap^0.5───PhXZ(a=-0.5,x=0.648,z=0.625)─────M─── ---------------------------------------- Transformer-5: merge_single_qubit_moments_to_phxz Initial Circuit: 0: ───PhXZ(a=-1,x=0.676,z=-0.5)────────iSwap───────PhXZ(a=-0.5,x=0,z=-1)────iSwap───────PhXZ(a=0,x=0.5,z=-0.574)────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────PhXZ(a=-0.5,x=0.5,z=-1)───iSwap───────PhXZ(a=0.585,x=0.5,z=-0.585)───iSwap───────PhXZ(a=-0.5,x=0.199,z=0)───iSwap───────PhXZ(a=0.879,x=0.532,z=-0.457)───M─── │ │ │ │ │ │ 1: ───PhXZ(a=0.709,x=0.136,z=-0.709)───iSwap^0.5───PhXZ(a=-1,x=0.364,z=0)───iSwap^0.5───PhXZ(a=0.537,x=0.483,z=-0.172)───PhXZ(a=0.498,x=0.5,z=-0.498)─────iSwap────────────────────────────────────────iSwap───────PhXZ(a=-1,x=0.5,z=0.748)───────────────────────────────┼──────────────────────────────────────────┼──────────────────────────────────────┼────────────────────────────────────────────M─── │ │ │ │ │ │ 2: ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────PhXZ(a=0.966,x=0.864,z=-0.966)───iSwap^0.5───PhXZ(a=2.22e-16,x=0.364,z=1.0)───iSwap^0.5───PhXZ(a=-1,x=0.864,z=0.216)───PhXZ(a=-0.5,x=0.5,z=0)────iSwap^0.5───PhXZ(a=0.852,x=0.5,z=-0.852)───iSwap^0.5───PhXZ(a=-0.5,x=0.623,z=0)───iSwap^0.5───PhXZ(a=-0.5,x=0.648,z=0.625)─────M─── Final Circuit: 0: ───PhXZ(a=-1,x=0.676,z=-0.5)────────iSwap───────PhXZ(a=-0.5,x=0,z=-1)────iSwap───────PhXZ(a=0,x=0.5,z=-0.574)──────────────────────────────────────────────────────────────────PhXZ(a=-0.5,x=0.5,z=-1)──────────iSwap───────PhXZ(a=0.585,x=0.5,z=-0.585)───iSwap───────PhXZ(a=-0.5,x=0.199,z=0)───iSwap───────PhXZ(a=0.879,x=0.532,z=-0.457)───M─── │ │ │ │ │ │ 1: ───PhXZ(a=0.709,x=0.136,z=-0.709)───iSwap^0.5───PhXZ(a=-1,x=0.364,z=0)───iSwap^0.5───PhXZ(a=0.999,x=0.866,z=0.542)────iSwap────────────────────────────────────────iSwap───────PhXZ(a=-1,x=0.5,z=0.748)─────────┼──────────────────────────────────────────┼──────────────────────────────────────┼────────────────────────────────────────────M─── │ │ │ │ │ │ 2: ─────────────────────────────────────────────────────────────────────────────────────PhXZ(a=0.966,x=0.864,z=-0.966)───iSwap^0.5───PhXZ(a=2.22e-16,x=0.364,z=1.0)───iSwap^0.5───PhXZ(a=-0.299,x=0.584,z=0.907)───iSwap^0.5───PhXZ(a=0.852,x=0.5,z=-0.852)───iSwap^0.5───PhXZ(a=-0.5,x=0.623,z=0)───iSwap^0.5───PhXZ(a=-0.5,x=0.648,z=0.625)─────M─── ---------------------------------------- Transformer-6: drop_negligible_operations Initial Circuit: 0: ───PhXZ(a=-1,x=0.676,z=-0.5)────────iSwap───────PhXZ(a=-0.5,x=0,z=-1)────iSwap───────PhXZ(a=0,x=0.5,z=-0.574)──────────────────────────────────────────────────────────────────PhXZ(a=-0.5,x=0.5,z=-1)──────────iSwap───────PhXZ(a=0.585,x=0.5,z=-0.585)───iSwap───────PhXZ(a=-0.5,x=0.199,z=0)───iSwap───────PhXZ(a=0.879,x=0.532,z=-0.457)───M─── │ │ │ │ │ │ 1: ───PhXZ(a=0.709,x=0.136,z=-0.709)───iSwap^0.5───PhXZ(a=-1,x=0.364,z=0)───iSwap^0.5───PhXZ(a=0.999,x=0.866,z=0.542)────iSwap────────────────────────────────────────iSwap───────PhXZ(a=-1,x=0.5,z=0.748)─────────┼──────────────────────────────────────────┼──────────────────────────────────────┼────────────────────────────────────────────M─── │ │ │ │ │ │ 2: ─────────────────────────────────────────────────────────────────────────────────────PhXZ(a=0.966,x=0.864,z=-0.966)───iSwap^0.5───PhXZ(a=2.22e-16,x=0.364,z=1.0)───iSwap^0.5───PhXZ(a=-0.299,x=0.584,z=0.907)───iSwap^0.5───PhXZ(a=0.852,x=0.5,z=-0.852)───iSwap^0.5───PhXZ(a=-0.5,x=0.623,z=0)───iSwap^0.5───PhXZ(a=-0.5,x=0.648,z=0.625)─────M─── Final Circuit: 0: ───PhXZ(a=-1,x=0.676,z=-0.5)────────iSwap───────PhXZ(a=-0.5,x=0,z=-1)────iSwap───────PhXZ(a=0,x=0.5,z=-0.574)──────────────────────────────────────────────────────────────────PhXZ(a=-0.5,x=0.5,z=-1)──────────iSwap───────PhXZ(a=0.585,x=0.5,z=-0.585)───iSwap───────PhXZ(a=-0.5,x=0.199,z=0)───iSwap───────PhXZ(a=0.879,x=0.532,z=-0.457)───M─── │ │ │ │ │ │ 1: ───PhXZ(a=0.709,x=0.136,z=-0.709)───iSwap^0.5───PhXZ(a=-1,x=0.364,z=0)───iSwap^0.5───PhXZ(a=0.999,x=0.866,z=0.542)────iSwap────────────────────────────────────────iSwap───────PhXZ(a=-1,x=0.5,z=0.748)─────────┼──────────────────────────────────────────┼──────────────────────────────────────┼────────────────────────────────────────────M─── │ │ │ │ │ │ 2: ─────────────────────────────────────────────────────────────────────────────────────PhXZ(a=0.966,x=0.864,z=-0.966)───iSwap^0.5───PhXZ(a=2.22e-16,x=0.364,z=1.0)───iSwap^0.5───PhXZ(a=-0.299,x=0.584,z=0.907)───iSwap^0.5───PhXZ(a=0.852,x=0.5,z=-0.852)───iSwap^0.5───PhXZ(a=-0.5,x=0.623,z=0)───iSwap^0.5───PhXZ(a=-0.5,x=0.648,z=0.625)─────M─── ---------------------------------------- Transformer-7: drop_empty_moments Initial Circuit: 0: ───PhXZ(a=-1,x=0.676,z=-0.5)────────iSwap───────PhXZ(a=-0.5,x=0,z=-1)────iSwap───────PhXZ(a=0,x=0.5,z=-0.574)──────────────────────────────────────────────────────────────────PhXZ(a=-0.5,x=0.5,z=-1)──────────iSwap───────PhXZ(a=0.585,x=0.5,z=-0.585)───iSwap───────PhXZ(a=-0.5,x=0.199,z=0)───iSwap───────PhXZ(a=0.879,x=0.532,z=-0.457)───M─── │ │ │ │ │ │ 1: ───PhXZ(a=0.709,x=0.136,z=-0.709)───iSwap^0.5───PhXZ(a=-1,x=0.364,z=0)───iSwap^0.5───PhXZ(a=0.999,x=0.866,z=0.542)────iSwap────────────────────────────────────────iSwap───────PhXZ(a=-1,x=0.5,z=0.748)─────────┼──────────────────────────────────────────┼──────────────────────────────────────┼────────────────────────────────────────────M─── │ │ │ │ │ │ 2: ─────────────────────────────────────────────────────────────────────────────────────PhXZ(a=0.966,x=0.864,z=-0.966)───iSwap^0.5───PhXZ(a=2.22e-16,x=0.364,z=1.0)───iSwap^0.5───PhXZ(a=-0.299,x=0.584,z=0.907)───iSwap^0.5───PhXZ(a=0.852,x=0.5,z=-0.852)───iSwap^0.5───PhXZ(a=-0.5,x=0.623,z=0)───iSwap^0.5───PhXZ(a=-0.5,x=0.648,z=0.625)─────M─── Final Circuit: 0: ───PhXZ(a=-1,x=0.676,z=-0.5)────────iSwap───────PhXZ(a=-0.5,x=0,z=-1)────iSwap───────PhXZ(a=0,x=0.5,z=-0.574)──────────────────────────────────────────────────────────────────PhXZ(a=-0.5,x=0.5,z=-1)──────────iSwap───────PhXZ(a=0.585,x=0.5,z=-0.585)───iSwap───────PhXZ(a=-0.5,x=0.199,z=0)───iSwap───────PhXZ(a=0.879,x=0.532,z=-0.457)───M─── │ │ │ │ │ │ 1: ───PhXZ(a=0.709,x=0.136,z=-0.709)───iSwap^0.5───PhXZ(a=-1,x=0.364,z=0)───iSwap^0.5───PhXZ(a=0.999,x=0.866,z=0.542)────iSwap────────────────────────────────────────iSwap───────PhXZ(a=-1,x=0.5,z=0.748)─────────┼──────────────────────────────────────────┼──────────────────────────────────────┼────────────────────────────────────────────M─── │ │ │ │ │ │ 2: ─────────────────────────────────────────────────────────────────────────────────────PhXZ(a=0.966,x=0.864,z=-0.966)───iSwap^0.5───PhXZ(a=2.22e-16,x=0.364,z=1.0)───iSwap^0.5───PhXZ(a=-0.299,x=0.584,z=0.907)───iSwap^0.5───PhXZ(a=0.852,x=0.5,z=-0.852)───iSwap^0.5───PhXZ(a=-0.5,x=0.623,z=0)───iSwap^0.5───PhXZ(a=-0.5,x=0.648,z=0.625)─────M─── ----------------------------------------
Summary
Cirq provides a plethora of built-in transformers which can be composed together into useful abstractions, like cirq.CompilationTargetGateset
, which in-turn can be serialized and can be used as a parameter in larger compilation pipelines and experiment workflows.
Try using these transformers to compile your circuits and refer to the API reference docs of cirq.TRANSFORMER
for more details.