Files
claude-scientific-skills/scientific-skills/cirq/references/transformation.md

417 lines
9.9 KiB
Markdown

# Circuit Transformations
This guide covers circuit optimization, compilation, and manipulation using Cirq's transformation framework.
## Transformer Framework
### Basic Transformers
```python
import cirq
# Example circuit
qubits = cirq.LineQubit.range(3)
circuit = cirq.Circuit(
cirq.H(qubits[0]),
cirq.CNOT(qubits[0], qubits[1]),
cirq.CNOT(qubits[1], qubits[2])
)
# Apply built-in transformer
from cirq.transformers import optimize_for_target_gateset
# Optimize to specific gate set
optimized = optimize_for_target_gateset(
circuit,
gateset=cirq.SqrtIswapTargetGateset()
)
```
### Merge Single-Qubit Gates
```python
from cirq.transformers import merge_single_qubit_gates_to_phxz
# Circuit with multiple single-qubit gates
circuit = cirq.Circuit(
cirq.H(q),
cirq.T(q),
cirq.S(q),
cirq.H(q)
)
# Merge into single operation
merged = merge_single_qubit_gates_to_phxz(circuit)
```
### Drop Negligible Operations
```python
from cirq.transformers import drop_negligible_operations
# Remove gates below threshold
circuit_with_small_rotations = cirq.Circuit(
cirq.rz(1e-10)(q), # Very small rotation
cirq.H(q)
)
cleaned = drop_negligible_operations(circuit_with_small_rotations, atol=1e-8)
```
## Custom Transformers
### Transformer Decorator
```python
from cirq.transformers import transformer_api
@transformer_api.transformer
def remove_z_gates(circuit: cirq.Circuit) -> cirq.Circuit:
"""Remove all Z gates from circuit."""
new_moments = []
for moment in circuit:
new_ops = [op for op in moment if not isinstance(op.gate, cirq.ZPowGate)]
if new_ops:
new_moments.append(cirq.Moment(new_ops))
return cirq.Circuit(new_moments)
# Use custom transformer
transformed = remove_z_gates(circuit)
```
### Transformer Class
```python
from cirq.transformers import transformer_primitives
class HToRyTransformer(transformer_primitives.Transformer):
"""Replace H gates with Ry(π/2)."""
def __call__(self, circuit: cirq.Circuit, *, context=None) -> cirq.Circuit:
def map_op(op: cirq.Operation, _) -> cirq.OP_TREE:
if isinstance(op.gate, cirq.HPowGate):
return cirq.ry(np.pi/2)(op.qubits[0])
return op
return transformer_primitives.map_operations(
circuit,
map_op,
deep=True
).unfreeze(copy=False)
# Apply transformer
transformer = HToRyTransformer()
result = transformer(circuit)
```
## Gate Decomposition
### Decompose to Target Gateset
```python
from cirq.transformers import optimize_for_target_gateset
# Decompose to CZ + single-qubit rotations
target_gateset = cirq.CZTargetGateset()
decomposed = optimize_for_target_gateset(circuit, gateset=target_gateset)
# Decompose to √iSWAP gates
sqrt_iswap_gateset = cirq.SqrtIswapTargetGateset()
decomposed = optimize_for_target_gateset(circuit, gateset=sqrt_iswap_gateset)
```
### Custom Gate Decomposition
```python
class Toffoli(cirq.Gate):
def _num_qubits_(self):
return 3
def _decompose_(self, qubits):
"""Decompose Toffoli into basic gates."""
c1, c2, t = qubits
return [
cirq.H(t),
cirq.CNOT(c2, t),
cirq.T(t)**-1,
cirq.CNOT(c1, t),
cirq.T(t),
cirq.CNOT(c2, t),
cirq.T(t)**-1,
cirq.CNOT(c1, t),
cirq.T(c2),
cirq.T(t),
cirq.H(t),
cirq.CNOT(c1, c2),
cirq.T(c1),
cirq.T(c2)**-1,
cirq.CNOT(c1, c2)
]
# Use decomposition
circuit = cirq.Circuit(Toffoli()(q0, q1, q2))
decomposed = cirq.decompose(circuit)
```
## Circuit Optimization
### Eject Z Gates
```python
from cirq.transformers import eject_z
# Move Z gates to end of circuit
circuit = cirq.Circuit(
cirq.H(q0),
cirq.Z(q0),
cirq.CNOT(q0, q1)
)
ejected = eject_z(circuit)
```
### Eject Phase Gates
```python
from cirq.transformers import eject_phased_paulis
# Consolidate phase gates
optimized = eject_phased_paulis(circuit, atol=1e-8)
```
### Drop Empty Moments
```python
from cirq.transformers import drop_empty_moments
# Remove moments with no operations
cleaned = drop_empty_moments(circuit)
```
### Align Measurements
```python
from cirq.transformers import dephase_measurements
# Move measurements to end and remove operations after
aligned = dephase_measurements(circuit)
```
## Circuit Compilation
### Compile for Hardware
```python
import cirq_google
# Get device specification
device = cirq_google.Sycamore
# Compile circuit to device
from cirq.transformers import optimize_for_target_gateset
compiled = optimize_for_target_gateset(
circuit,
gateset=cirq_google.SycamoreTargetGateset()
)
# Validate compiled circuit
device.validate_circuit(compiled)
```
### Two-Qubit Gate Compilation
```python
# Compile to specific two-qubit gate
from cirq import two_qubit_to_cz
# Convert all two-qubit gates to CZ
cz_circuit = cirq.Circuit()
for moment in circuit:
for op in moment:
if len(op.qubits) == 2:
cz_circuit.append(two_qubit_to_cz(op))
else:
cz_circuit.append(op)
```
## Qubit Routing
### Route Circuit to Device Topology
```python
from cirq.transformers import route_circuit
# Define device connectivity
device_graph = cirq.NamedTopology(
{
(0, 0): [(0, 1), (1, 0)],
(0, 1): [(0, 0), (1, 1)],
(1, 0): [(0, 0), (1, 1)],
(1, 1): [(0, 1), (1, 0)]
}
)
# Route logical qubits to physical qubits
routed_circuit = route_circuit(
circuit,
device_graph=device_graph,
routing_algo=cirq.RouteCQC(device_graph)
)
```
### SWAP Network Insertion
```python
# Manually insert SWAPs for routing
def insert_swaps(circuit, swap_locations):
"""Insert SWAP gates at specified locations."""
new_circuit = cirq.Circuit()
moment_idx = 0
for i, moment in enumerate(circuit):
if i in swap_locations:
q0, q1 = swap_locations[i]
new_circuit.append(cirq.SWAP(q0, q1))
new_circuit.append(moment)
return new_circuit
```
## Advanced Transformations
### Unitary Compilation
```python
import scipy.linalg
# Compile arbitrary unitary to gate sequence
def compile_unitary(unitary, qubits):
"""Compile 2x2 unitary using KAK decomposition."""
from cirq.linalg import kak_decomposition
decomp = kak_decomposition(unitary)
operations = []
# Add single-qubit gates before
operations.append(cirq.MatrixGate(decomp.single_qubit_operations_before[0])(qubits[0]))
operations.append(cirq.MatrixGate(decomp.single_qubit_operations_before[1])(qubits[1]))
# Add interaction (two-qubit) part
x, y, z = decomp.interaction_coefficients
operations.append(cirq.XXPowGate(exponent=x/np.pi)(qubits[0], qubits[1]))
operations.append(cirq.YYPowGate(exponent=y/np.pi)(qubits[0], qubits[1]))
operations.append(cirq.ZZPowGate(exponent=z/np.pi)(qubits[0], qubits[1]))
# Add single-qubit gates after
operations.append(cirq.MatrixGate(decomp.single_qubit_operations_after[0])(qubits[0]))
operations.append(cirq.MatrixGate(decomp.single_qubit_operations_after[1])(qubits[1]))
return operations
```
### Circuit Simplification
```python
from cirq.transformers import (
merge_k_qubit_unitaries,
merge_single_qubit_gates_to_phxz
)
# Merge adjacent single-qubit gates
simplified = merge_single_qubit_gates_to_phxz(circuit)
# Merge adjacent k-qubit unitaries
simplified = merge_k_qubit_unitaries(circuit, k=2)
```
### Commutation-Based Optimization
```python
# Commute Z gates through CNOT
def commute_z_through_cnot(circuit):
"""Move Z gates through CNOT gates."""
new_moments = []
for moment in circuit:
ops = list(moment)
# Find Z gates before CNOT
z_ops = [op for op in ops if isinstance(op.gate, cirq.ZPowGate)]
cnot_ops = [op for op in ops if isinstance(op.gate, cirq.CXPowGate)]
# Apply commutation rules
# Z on control commutes, Z on target anticommutes
# (simplified logic here)
new_moments.append(cirq.Moment(ops))
return cirq.Circuit(new_moments)
```
## Transformation Pipelines
### Compose Multiple Transformers
```python
from cirq.transformers import transformer_api
# Build transformation pipeline
@transformer_api.transformer
def optimization_pipeline(circuit: cirq.Circuit) -> cirq.Circuit:
# Step 1: Merge single-qubit gates
circuit = merge_single_qubit_gates_to_phxz(circuit)
# Step 2: Drop negligible operations
circuit = drop_negligible_operations(circuit)
# Step 3: Eject Z gates
circuit = eject_z(circuit)
# Step 4: Drop empty moments
circuit = drop_empty_moments(circuit)
return circuit
# Apply pipeline
optimized = optimization_pipeline(circuit)
```
## Validation and Analysis
### Circuit Depth Reduction
```python
# Measure circuit depth before and after
print(f"Original depth: {len(circuit)}")
optimized = optimization_pipeline(circuit)
print(f"Optimized depth: {len(optimized)}")
```
### Gate Count Analysis
```python
def count_gates(circuit):
"""Count gates by type."""
counts = {}
for moment in circuit:
for op in moment:
gate_type = type(op.gate).__name__
counts[gate_type] = counts.get(gate_type, 0) + 1
return counts
original_counts = count_gates(circuit)
optimized_counts = count_gates(optimized)
print(f"Original: {original_counts}")
print(f"Optimized: {optimized_counts}")
```
## Best Practices
1. **Start with high-level transformers**: Use built-in transformers before writing custom ones
2. **Chain transformers**: Apply multiple optimizations in sequence
3. **Validate after transformation**: Ensure circuit correctness and device compatibility
4. **Measure improvement**: Track depth and gate count reduction
5. **Use appropriate gatesets**: Match target hardware capabilities
6. **Consider commutativity**: Exploit gate commutation for optimization
7. **Test on small circuits first**: Verify transformers work correctly before scaling