Cirq Beginner Free 6/13 in series 20 min read

Hello World in Cirq

Write your first quantum program in Cirq, create a Bell state using GridQubits and Moments, run it on the Cirq simulator.

What you'll learn

  • cirq
  • quantum circuits
  • bell state
  • ghz state
  • google
  • python

Prerequisites

  • Basic Python (variables, functions, loops)
  • No quantum physics background needed

Cirq is Google’s open-source Python library for writing, simulating, and running quantum circuits. It gives you precise control over qubit placement and gate scheduling, making it a natural fit for research on near-term quantum hardware.

What makes Cirq distinctive is that qubits carry physical placement information. GridQubit(0, 0) is not just an abstract bit; it corresponds to a specific physical location on Google’s Sycamore quantum processor chip. This design forces you to think about hardware constraints from the start, which produces circuits that map directly to real device topology. For getting started, though, LineQubit gives you numbered abstract qubits that work like most other frameworks.

In this tutorial you will create two classic entangled states (the Bell state and the GHZ state), simulate them locally, and learn the core Cirq concepts along the way.

Setting Up Cirq

Install Cirq with pip:

pip install cirq

This installs the core cirq package, which includes the local simulator and all standard gates. If you plan to target Google hardware later, you will also install cirq-google, but the core package is all you need for this tutorial.

Example 1: Bell State

The Bell state Φ+=12(00+11)|\Phi^+\rangle = \frac{1}{\sqrt{2}}(|00\rangle + |11\rangle) is the simplest example of quantum entanglement. Two qubits become perfectly correlated: when you measure them, you always get either both 0 or both 1, with equal probability. Creating a Bell state requires just two gates: a Hadamard followed by a CNOT.

import cirq

# Define two qubits on a 2D grid
q0 = cirq.LineQubit(0)
q1 = cirq.LineQubit(1)

# Build the circuit
circuit = cirq.Circuit([
    cirq.H(q0),           # Superposition on qubit 0
    cirq.CNOT(q0, q1),    # Entangle q0 and q1
    cirq.measure(q0, q1, key='result'),
])

print("Bell State Circuit:")
print(circuit)

# Simulate with 1000 repetitions
simulator = cirq.Simulator()
result = simulator.run(circuit, repetitions=1000)
print("\nMeasurement counts:")
print(result.histogram(key='result'))

What Each Line Does

  • cirq.LineQubit(0) and cirq.LineQubit(1): Creates two numbered abstract qubits. LineQubit assigns each qubit a position on a one-dimensional line. In a real application targeting Google hardware, you would use cirq.GridQubit(row, col) to place qubits on the chip’s two-dimensional grid.

  • cirq.Circuit([...]): Creates a circuit from a list of operations. Cirq automatically schedules independent operations into parallel “Moments” (time steps). You do not need to manage timing yourself; Cirq figures out which gates can run simultaneously.

  • cirq.H(q0): Applies the Hadamard gate to qubit 0. This puts the qubit into an equal superposition of 0|0\rangle and 1|1\rangle, so it has a 50/50 chance of being measured as either value.

  • cirq.CNOT(q0, q1): Applies the controlled-NOT gate. If q0 is 1|1\rangle, the gate flips q1. Because q0 is in superposition after the Hadamard, the CNOT entangles the two qubits so their outcomes are always correlated.

  • cirq.measure(q0, q1, key='result'): Measures both qubits and labels the measurement with the key 'result'. You use this key later to retrieve the measurement outcomes.

  • simulator.run(circuit, repetitions=1000): Runs the circuit 1000 times (equivalent to 1000 “shots”). Each run collapses the quantum state and produces one classical measurement outcome.

  • result.histogram(key='result'): Converts the 1000 measurement results into a count dictionary. The keys are integers representing the measured bitstring: 0 corresponds to binary 00 (both qubits measured 0), and 3 corresponds to binary 11 (both qubits measured 1).

Expected Output

Bell State Circuit:
0: ───H───@───M('result')───
          │   │
1: ───────X───M─────────────

Measurement counts:
Counter({3: 514, 0: 486})

Only two outcomes appear: 0 (binary 00) and 3 (binary 11). You never see 1 (binary 01) or 2 (binary 10). This confirms that the two qubits are entangled; their measurement results are always the same. Your exact counts will vary because quantum measurement is inherently probabilistic, but the two values will be roughly equal, each close to 500.

Example 2: GHZ State (Three Qubits)

A GHZ (Greenberger-Horne-Zeilinger) state extends entanglement from two qubits to three. Where the Bell state correlates two qubits, the GHZ state correlates three: all three qubits are either all 0 or all 1 when measured. The resulting state is 12(000+111)\frac{1}{\sqrt{2}}(|000\rangle + |111\rangle).

The construction follows the same pattern as the Bell state. Apply a Hadamard to the first qubit to create superposition, then use CNOT gates from the first qubit to each subsequent qubit to spread the entanglement. Each additional CNOT adds one more qubit to the entangled group.

import cirq

q0, q1, q2 = cirq.LineQubit.range(3)

circuit = cirq.Circuit([
    cirq.H(q0),
    cirq.CNOT(q0, q1),
    cirq.CNOT(q0, q2),
    cirq.measure(q0, q1, q2, key='result'),
])

print("GHZ State Circuit:")
print(circuit)

simulator = cirq.Simulator()
result = simulator.run(circuit, repetitions=1000)
print("\nMeasurement counts:")
print(result.histogram(key='result'))

Notice that cirq.LineQubit.range(3) is a shorthand for creating multiple qubits at once. It works just like Python’s range() and returns qubits numbered 0 through 2.

Expected Output

GHZ State Circuit:
0: ───H───@───@───M('result')───
          │   │   │
1: ───────X───┼───M─────────────
              │   │
2: ───────────X───M─────────────

Measurement counts:
Counter({0: 502, 7: 498})

Here 0 equals binary 000 and 7 equals binary 111. All three qubits are perfectly correlated. You can extend this pattern to any number of qubits by adding more CNOT gates from q0 to each new qubit.

Key Cirq Concepts

Here is a summary of the core Cirq objects and methods used in this tutorial:

  • LineQubit(i): An abstract qubit at linear position i. Use LineQubit for learning and algorithm development when you do not need to worry about physical hardware layout.
  • GridQubit(row, col): A qubit at a specific row and column on a two-dimensional grid. Use GridQubit when targeting real hardware, since Google’s quantum processors arrange their qubits in a grid.
  • cirq.Circuit(ops): A container for quantum operations. Cirq organizes operations into parallel Moments (time steps) automatically, grouping independent gates so they execute simultaneously.
  • cirq.Simulator(): A local statevector simulator. It computes exact results with no noise, which makes it ideal for learning and debugging circuits before running on hardware.
  • simulator.run(circuit, repetitions=N): Runs the circuit N times and collects measurement results. Each repetition simulates a full execution, including the probabilistic collapse at measurement.
  • result.histogram(key): Counts how often each measurement outcome occurred across all repetitions. Returns a Counter dictionary where keys are integers encoding the measured bitstrings.

Running on Google Quantum Hardware

Cirq integrates directly with Google’s quantum processors through the cirq-google package. This package includes the hardware client for submitting circuits, along with Google-specific gates (like the Sycamore gate) and device definitions that describe each processor’s qubit layout and connectivity.

Install it alongside the core package:

pip install cirq-google

To run circuits on actual hardware, you need a Google Cloud project with Quantum Computing Service access enabled. This access is currently limited to approved research partners through Google’s quantum computing programs. If you have access, the workflow looks like this:

import cirq
import cirq_google

# Connect to the Quantum Engine with your Google Cloud project
engine = cirq_google.Engine(project_id="your-gcp-project")

# List available quantum processors
processors = engine.list_processors()
print("Available processors:", processors)

# Select a processor and get its device specification
processor = engine.get_processor("processor-name")
device = processor.get_device()

# Build a circuit using GridQubits that match the device topology
q0 = cirq.GridQubit(5, 3)
q1 = cirq.GridQubit(5, 4)

circuit = cirq.Circuit([
    cirq.H(q0),
    cirq.CNOT(q0, q1),
    cirq.measure(q0, q1, key='result'),
])

# Submit the circuit to the hardware
hardware_result = processor.run(circuit, repetitions=1000)
print(hardware_result.histogram(key='result'))

Notice that the code uses GridQubit with specific row and column coordinates instead of LineQubit. These coordinates must correspond to actual qubit positions on the target processor. The device specification from processor.get_device() tells you which qubits are available and which pairs are connected, so you can design circuits that match the hardware topology.

Even without hardware access, you can use cirq-google to simulate Google-specific gate sets and validate that your circuits are compatible with a particular processor before submitting them.

What to Learn Next

This tutorial covered the basics: installing Cirq, building simple entangled circuits, and running them on the local simulator. For a deeper introduction that covers custom gates, noise simulation, parameterized circuits, and more advanced patterns, continue with our Getting Started with Cirq tutorial.

Was this tutorial helpful?