Skill Tracer
Skills › Scientific Agent Skills › cirq › building.md

building.md

333 lines · skills/cirq/references/building.md at 5f2bc03

Open on GitHub
1# Building Quantum Circuits
2
3This guide covers circuit construction in Cirq 1.7.0. The code blocks build on
4the imports and qubits introduced earlier; the complete sequence is locally tested.
5

Building Quantum Circuits

This guide covers circuit construction in Cirq 1.7.0. The code blocks build on the imports and qubits introduced earlier; the complete sequence is locally tested.

Raw lines 1 to 5
6## Basic Circuit Construction
7

Basic Circuit Construction

Raw lines 6 to 7
8### Creating Circuits
9
10```python
11import cirq
12import numpy as np
14# Create a circuit
15circuit = cirq.Circuit()
17# Create qubits
18q0 = cirq.GridQubit(0, 0)
19q1 = cirq.GridQubit(0, 1)
20q2 = cirq.LineQubit(0)
22# Add gates to circuit
23circuit.append([
24 cirq.H(q0),
25 cirq.CNOT(q0, q1),
26 cirq.measure(q0, q1, key='result')
27])
28```

Creating Circuits

import cirq
import numpy as np

# Create a circuit
circuit = cirq.Circuit()

# Create qubits
q0 = cirq.GridQubit(0, 0)
q1 = cirq.GridQubit(0, 1)
q2 = cirq.LineQubit(0)

# Add gates to circuit
circuit.append([
    cirq.H(q0),
    cirq.CNOT(q0, q1),
    cirq.measure(q0, q1, key='result')
])
Raw lines 8 to 29
30### Qubit Types
32**GridQubit**: 2D grid topology for hardware-like layouts
33```python
34qubits = cirq.GridQubit.square(2) # 2x2 grid
35qubit = cirq.GridQubit(row=0, col=1)
36```
38**LineQubit**: 1D linear topology
39```python
40qubits = cirq.LineQubit.range(5) # 5 qubits in a line
41qubit = cirq.LineQubit(3)
42```
44**NamedQubit**: Custom-named qubits
45```python
46qubit = cirq.NamedQubit('my_qubit')
47```

Qubit Types

GridQubit: 2D grid topology for hardware-like layouts

qubits = cirq.GridQubit.square(2)  # 2x2 grid
qubit = cirq.GridQubit(row=0, col=1)

LineQubit: 1D linear topology

qubits = cirq.LineQubit.range(5)  # 5 qubits in a line
qubit = cirq.LineQubit(3)

NamedQubit: Custom-named qubits

qubit = cirq.NamedQubit('my_qubit')
Raw lines 30 to 48
49## Common Gates and Operations

Common Gates and Operations

Raw lines 49 to 50
51### Single-Qubit Gates
53```python
54# Pauli gates
55cirq.X(qubit) # NOT gate
56cirq.Y(qubit)
57cirq.Z(qubit)
59# Hadamard
60cirq.H(qubit)
62# Rotation angles are radians; XPowGate/YPowGate/ZPowGate exponents are half-turns.
63angle = np.pi / 4 # requires import numpy as np
64cirq.rx(angle)(qubit) # Rotation around X-axis
65cirq.ry(angle)(qubit) # Rotation around Y-axis
66cirq.rz(angle)(qubit) # Rotation around Z-axis
68# Phase gates
69cirq.S(qubit) # √Z gate
70cirq.T(qubit) # ⁴√Z gate
71```

Single-Qubit Gates

# Pauli gates
cirq.X(qubit)  # NOT gate
cirq.Y(qubit)
cirq.Z(qubit)

# Hadamard
cirq.H(qubit)

# Rotation angles are radians; XPowGate/YPowGate/ZPowGate exponents are half-turns.
angle = np.pi / 4  # requires import numpy as np
cirq.rx(angle)(qubit)  # Rotation around X-axis
cirq.ry(angle)(qubit)  # Rotation around Y-axis
cirq.rz(angle)(qubit)  # Rotation around Z-axis

# Phase gates
cirq.S(qubit)  # √Z gate
cirq.T(qubit)  # ⁴√Z gate
Raw lines 51 to 72
73### Two-Qubit Gates
75```python
76# CNOT (Controlled-NOT)
77control, target = q0, q1
78cirq.CNOT(control, target)
79cirq.CX(control, target) # Alias
81# CZ (Controlled-Z)
82cirq.CZ(q0, q1)
84# SWAP
85cirq.SWAP(q0, q1)
87# iSWAP
88cirq.ISWAP(q0, q1)
90# Controlled rotations
91cirq.CZPowGate(exponent=0.5)(q0, q1)
92```

Two-Qubit Gates

# CNOT (Controlled-NOT)
control, target = q0, q1
cirq.CNOT(control, target)
cirq.CX(control, target)  # Alias

# CZ (Controlled-Z)
cirq.CZ(q0, q1)

# SWAP
cirq.SWAP(q0, q1)

# iSWAP
cirq.ISWAP(q0, q1)

# Controlled rotations
cirq.CZPowGate(exponent=0.5)(q0, q1)
Raw lines 73 to 93
94### Measurement Operations
96```python
97# Measure single qubit
98cirq.measure(qubit, key='m')
100# Measure multiple qubits
101cirq.measure(q0, q1, q2, key='result')
103# Measure all qubits in circuit
104circuit.append(cirq.measure(*qubits, key='final'))
105```

Measurement Operations

# Measure single qubit
cirq.measure(qubit, key='m')

# Measure multiple qubits
cirq.measure(q0, q1, q2, key='result')

# Measure all qubits in circuit
circuit.append(cirq.measure(*qubits, key='final'))
Raw lines 94 to 106
107## Advanced Circuit Construction

Advanced Circuit Construction

Raw lines 107 to 108
109### Parameterized Gates
111```python
112import sympy
114# Create symbolic parameters
115theta = sympy.Symbol('theta')
116phi = sympy.Symbol('phi')
118# Use in gates
119circuit = cirq.Circuit(
120 cirq.rx(theta)(q0),
121 cirq.ry(phi)(q1),
122 cirq.CNOT(q0, q1)
125# Resolve parameters later
126resolved = cirq.resolve_parameters(circuit, {'theta': 0.5, 'phi': 1.2})
127```

Parameterized Gates

import sympy

# Create symbolic parameters
theta = sympy.Symbol('theta')
phi = sympy.Symbol('phi')

# Use in gates
circuit = cirq.Circuit(
    cirq.rx(theta)(q0),
    cirq.ry(phi)(q1),
    cirq.CNOT(q0, q1)
)

# Resolve parameters later
resolved = cirq.resolve_parameters(circuit, {'theta': 0.5, 'phi': 1.2})
Raw lines 109 to 128
129### Custom Gates via Unitaries
131```python
132import numpy as np
134# Define unitary matrix
135unitary = np.array([
136 [1, 0, 0, 0],
137 [0, 1, 0, 0],
138 [0, 0, 0, 1],
139 [0, 0, 1, 0]
140], dtype=complex)
141assert np.allclose(unitary.conj().T @ unitary, np.eye(4))
143# Create gate from unitary
144gate = cirq.MatrixGate(unitary)
145operation = gate(q0, q1)
146```

Custom Gates via Unitaries

import numpy as np

# Define unitary matrix
unitary = np.array([
    [1, 0, 0, 0],
    [0, 1, 0, 0],
    [0, 0, 0, 1],
    [0, 0, 1, 0]
], dtype=complex)
assert np.allclose(unitary.conj().T @ unitary, np.eye(4))

# Create gate from unitary
gate = cirq.MatrixGate(unitary)
operation = gate(q0, q1)
Raw lines 129 to 147
148### Gate Decomposition
150```python
151# Define custom gate with decomposition
152class MyGate(cirq.Gate):
153 def _num_qubits_(self):
154 return 1
156 def _decompose_(self, qubits):
157 q = qubits[0]
158 return [cirq.H(q), cirq.T(q), cirq.H(q)]
160 def _circuit_diagram_info_(self, args):
161 return 'MyGate'
163# Use the custom gate
164my_gate = MyGate()
165circuit.append(my_gate(q0))
166```

Gate Decomposition

# Define custom gate with decomposition
class MyGate(cirq.Gate):
    def _num_qubits_(self):
        return 1

    def _decompose_(self, qubits):
        q = qubits[0]
        return [cirq.H(q), cirq.T(q), cirq.H(q)]

    def _circuit_diagram_info_(self, args):
        return 'MyGate'

# Use the custom gate
my_gate = MyGate()
circuit.append(my_gate(q0))
Raw lines 148 to 167
168## Circuit Organization

Circuit Organization

Raw lines 168 to 169
170### Moments
172Circuits are organized into moments (parallel operations):
174```python
175# Explicit moment construction
176circuit = cirq.Circuit(
177 cirq.Moment([cirq.H(q0), cirq.H(q1)]),
178 cirq.Moment([cirq.CNOT(q0, q1)]),
179 cirq.Moment([cirq.measure(q0, key='m0'), cirq.measure(q1, key='m1')])
182# Access moments
183for i, moment in enumerate(circuit):
184 print(f"Moment {i}: {moment}")
185```

Moments

Circuits are organized into moments (parallel operations):

# Explicit moment construction
circuit = cirq.Circuit(
    cirq.Moment([cirq.H(q0), cirq.H(q1)]),
    cirq.Moment([cirq.CNOT(q0, q1)]),
    cirq.Moment([cirq.measure(q0, key='m0'), cirq.measure(q1, key='m1')])
)

# Access moments
for i, moment in enumerate(circuit):
    print(f"Moment {i}: {moment}")
Raw lines 170 to 186
187### Circuit Operations
189```python
190# Concatenate circuits
191circuit1 = cirq.Circuit(cirq.H(q0))
192circuit2 = cirq.Circuit(cirq.CNOT(q0, q1))
193circuit3 = circuit1 + circuit2
195# Insert operations
196index, operation = 0, cirq.X(q0)
197circuit.insert(index, operation)
199# Append with strategy
200operations = [cirq.X(q1)]
201circuit.append(operations, strategy=cirq.InsertStrategy.NEW_THEN_INLINE)
202```

Circuit Operations

# Concatenate circuits
circuit1 = cirq.Circuit(cirq.H(q0))
circuit2 = cirq.Circuit(cirq.CNOT(q0, q1))
circuit3 = circuit1 + circuit2

# Insert operations
index, operation = 0, cirq.X(q0)
circuit.insert(index, operation)

# Append with strategy
operations = [cirq.X(q1)]
circuit.append(operations, strategy=cirq.InsertStrategy.NEW_THEN_INLINE)
Raw lines 187 to 203
204## Circuit Patterns

Circuit Patterns

Raw lines 204 to 205
206### Bell State Preparation
208```python
209def bell_state_circuit():
210 q0, q1 = cirq.LineQubit.range(2)
211 return cirq.Circuit(
212 cirq.H(q0),
213 cirq.CNOT(q0, q1)
214 )
215```

Bell State Preparation

def bell_state_circuit():
    q0, q1 = cirq.LineQubit.range(2)
    return cirq.Circuit(
        cirq.H(q0),
        cirq.CNOT(q0, q1)
    )
Raw lines 206 to 216
217### GHZ State
219```python
220def ghz_circuit(qubits):
221 circuit = cirq.Circuit()
222 circuit.append(cirq.H(qubits[0]))
223 for i in range(len(qubits) - 1):
224 circuit.append(cirq.CNOT(qubits[i], qubits[i+1]))
225 return circuit
226```

GHZ State

def ghz_circuit(qubits):
    circuit = cirq.Circuit()
    circuit.append(cirq.H(qubits[0]))
    for i in range(len(qubits) - 1):
        circuit.append(cirq.CNOT(qubits[i], qubits[i+1]))
    return circuit
Raw lines 217 to 227
228### Quantum Fourier Transform
230```python
231def qft_circuit(qubits):
232 circuit = cirq.Circuit()
233 for i, q in enumerate(qubits):
234 circuit.append(cirq.H(q))
235 for j in range(i + 1, len(qubits)):
236 circuit.append(cirq.CZPowGate(exponent=1/2**(j-i))(qubits[j], q))
238 # Reverse qubit order
239 for i in range(len(qubits) // 2):
240 circuit.append(cirq.SWAP(qubits[i], qubits[len(qubits) - i - 1]))
242 return circuit
243```

Quantum Fourier Transform

def qft_circuit(qubits):
    circuit = cirq.Circuit()
    for i, q in enumerate(qubits):
        circuit.append(cirq.H(q))
        for j in range(i + 1, len(qubits)):
            circuit.append(cirq.CZPowGate(exponent=1/2**(j-i))(qubits[j], q))

    # Reverse qubit order
    for i in range(len(qubits) // 2):
        circuit.append(cirq.SWAP(qubits[i], qubits[len(qubits) - i - 1]))

    return circuit
Raw lines 228 to 244
245## Circuit Import/Export

Circuit Import/Export

Raw lines 245 to 246
247### OpenQASM
249The import parser requires `ply` (`uv pip install ply`). Export/import supports
250only representable gates; arbitrary custom gates may need decomposition. The
251following uses OpenQASM 2; Cirq 1.7 also has expanded QASM 3 support.
253```python
254# Export to QASM
255qasm_str = circuit.to_qasm()
257# Import from QASM
258from cirq.contrib.qasm_import import circuit_from_qasm
259circuit = circuit_from_qasm(qasm_str)
260```

OpenQASM

The import parser requires ply (uv pip install ply). Export/import supports only representable gates; arbitrary custom gates may need decomposition. The following uses OpenQASM 2; Cirq 1.7 also has expanded QASM 3 support.

# Export to QASM
qasm_str = circuit.to_qasm()

# Import from QASM
from cirq.contrib.qasm_import import circuit_from_qasm
circuit = circuit_from_qasm(qasm_str)
Raw lines 247 to 261
262### Circuit JSON
264```python
265import json
267# Serialize
268json_str = cirq.to_json(circuit)
270# Deserialize
271circuit = cirq.read_json(json_text=json_str)
272```

Circuit JSON

import json

# Serialize
json_str = cirq.to_json(circuit)

# Deserialize
circuit = cirq.read_json(json_text=json_str)
Raw lines 262 to 273
274## Working with Qudits
276Qudits are higher-dimensional quantum systems (qutrits, ququarts, etc.):
278```python
279# Create qutrit (3-level system)
280qutrit = cirq.LineQid(0, dimension=3)
282# Custom qutrit gate
283class QutritXGate(cirq.Gate):
284 def _qid_shape_(self):
285 return (3,)
287 def _unitary_(self):
288 return np.array([
289 [0, 0, 1],
290 [1, 0, 0],
291 [0, 1, 0]
292 ])
294gate = QutritXGate()
295circuit = cirq.Circuit(gate(qutrit))
296```

Working with Qudits

Qudits are higher-dimensional quantum systems (qutrits, ququarts, etc.):

# Create qutrit (3-level system)
qutrit = cirq.LineQid(0, dimension=3)

# Custom qutrit gate
class QutritXGate(cirq.Gate):
    def _qid_shape_(self):
        return (3,)

    def _unitary_(self):
        return np.array([
            [0, 0, 1],
            [1, 0, 0],
            [0, 1, 0]
        ])

gate = QutritXGate()
circuit = cirq.Circuit(gate(qutrit))
Raw lines 274 to 297
298## Observables
300Create observables from Pauli operators:
302```python
303# Single Pauli observable
304obs = cirq.Z(q0)
306# Pauli string
307obs = cirq.X(q0) * cirq.Y(q1) * cirq.Z(q2)
309# Linear combination
310from cirq import PauliSum
311obs = 0.5 * cirq.X(q0) + 0.3 * cirq.Z(q1)
312```

Observables

Create observables from Pauli operators:

# Single Pauli observable
obs = cirq.Z(q0)

# Pauli string
obs = cirq.X(q0) * cirq.Y(q1) * cirq.Z(q2)

# Linear combination
from cirq import PauliSum
obs = 0.5 * cirq.X(q0) + 0.3 * cirq.Z(q1)
Raw lines 298 to 313
314## Best Practices
3161. **Use appropriate qubit types**: GridQubit for hardware-like topologies, LineQubit for 1D problems
3172. **Keep circuits modular**: Build reusable circuit functions
3183. **Use symbolic parameters**: For parameter sweeps and optimization
3194. **Label measurements clearly**: Use descriptive keys for measurement results
3205. **Document custom gates**: Include circuit diagram information for visualization

Best Practices

  1. Use appropriate qubit types: GridQubit for hardware-like topologies, LineQubit for 1D problems
  2. Keep circuits modular: Build reusable circuit functions
  3. Use symbolic parameters: For parameter sweeps and optimization
  4. Label measurements clearly: Use descriptive keys for measurement results
  5. Document custom gates: Include circuit diagram information for visualization
Raw lines 314 to 321
322## Ordering and validation
324Pass an explicit `qubit_order` to simulation/unitary calculations and build the
325observable qubit map from that same list. `measure(q0, q1)` packs histogram
326integers big-endian: q0 is the most significant bit. Keep raw measurement columns
327in this argument order. `GridQubit` coordinates alone do not enforce connectivity;
328validate against a device after routing and compilation.
330Official references: [circuits](https://quantumai.google/cirq/build/circuits),
331[qubits](https://quantumai.google/cirq/build/qubits),
332[MatrixGate](https://quantumai.google/reference/python/cirq/MatrixGate),
333[QFT](https://quantumai.google/reference/python/cirq/qft).

Ordering and validation

Pass an explicit qubit_order to simulation/unitary calculations and build the observable qubit map from that same list. measure(q0, q1) packs histogram integers big-endian: q0 is the most significant bit. Keep raw measurement columns in this argument order. GridQubit coordinates alone do not enforce connectivity; validate against a device after routing and compilation.

Official references: circuits, qubits, MatrixGate, QFT.

Raw lines 322 to 333