Skip to content

Your first Bell circuit

This experiment prepares two qubits, measures them and reads the result. You will see why measurement frequencies vary even when the circuit stays the same.

Complete installation first. Run the commands from the repository root. The circuit uses two qubits and 32 shots; it runs on your local CPU.

Predict the outcome

Both qubits start in state 0. An H gate on qubit 0 creates a superposition. The following CX gate flips qubit 1 when qubit 0 is 1. Together they prepare the Bell state:

(|00⟩ + |11⟩) / √2

An ideal measurement in this basis gives 00 or 11, each with probability 1/2. Predict whether a run with 32 shots must return 16 of each before you run the script.

Build and run the circuit

The source below is the same file used by the executable course checks. measure_all(key="readout") names the measurement register. A shot is one sample from the output distribution; seed controls the pseudo-random sampling.

"""Build a Bell-style circuit and interpret its sampled result.

This beginner lesson introduces the fluent ``Circuit`` builder, terminal
measurement, deterministic local execution, and bit-order metadata. Always
read the bit order before assigning physical meaning to a bitstring.
"""

from __future__ import annotations

import json

from cascaqit import Circuit


def main() -> None:
    """Execute a two-qubit entangling circuit with a fixed seed."""
    # H creates a superposition; CX correlates q1 with q0.
    circuit = Circuit(2, program_id="lesson.digital.beginner")
    circuit.h(0).cx(0, 1).measure_all(key="readout")

    # Circuit.run is the shortest local Digital path for a first experiment.
    result = circuit.run(shots=32, seed=201, return_probabilities=True)
    program = circuit.to_program()

    payload = {
        "track": "digital_developer",
        "level": "beginner",
        "lesson": "bell_circuit",
        "facts": {
            "gate_names": [
                operation.definition.name
                for operation in program.circuit.operations
                if operation.definition.name != "measure"
            ],
            "counts_total": sum(result.counts.values()),
            "probability_states": sorted((result.probabilities or {}).keys()),
            "bit_order": result.metadata["bitstring_ordering"]["qubit_order"],
            "measurement_key": program.circuit.classical_registers[0].register_id,
        },
        "boundaries": {
            "hardware_execution": False,
            "cloud_execution": False,
            "network_accessed": False,
            "credentials_loaded": False,
        },
    }
    print(json.dumps(payload, sort_keys=True))


if __name__ == "__main__":
    main()

Download the full script

python3 examples/user/tracks/digital_developer/01_beginner_bell_circuit_en.py

The script prints a JSON object. Read facts first:

{
  "boundaries": {
    "cloud_execution": false,
    "credentials_loaded": false,
    "hardware_execution": false,
    "network_accessed": false
  },
  "facts": {
    "bit_order": [
      "q0",
      "q1"
    ],
    "counts_total": 32,
    "gate_names": [
      "h",
      "x"
    ],
    "measurement_key": "readout",
    "probability_states": [
      "00",
      "01",
      "10",
      "11"
    ]
  },
  "lesson": "bell_circuit",
  "level": "beginner",
  "track": "digital_developer"
}
Field What to check
gate_names Is ["h", "x"]: the controlled-X operation stores x as its gate name, with control information on the operation
counts_total Equals the requested 32 shots
probability_states Identifies the states represented by the probability result; use their values to judge probability, not just whether a key exists
bit_order Tells you which qubit each bit position refers to
measurement_key Is readout, the register name you chose

The payload's boundaries describe a local simulation. They are not an error message or an instruction to configure a cloud account.

Inspect the actual counts

The lesson script prints a compact summary. To inspect the samples, add print(result.counts) after result = circuit.run(...) in your local copy. Add print(result.probabilities) to compare sample frequencies with ideal probabilities.

The counts must sum to 32, but they need not split 16/16. Repeating a measurement does not change the ideal probability distribution. It gives a new sample from it. A fixed seed helps repeat the same experiment in the same environment; exact sample counts are not a cross-version guarantee.

The 00 and 11 counts show correlation in this measurement basis. Those counts alone do not distinguish the Bell state from a classical mixture. Measurements in other bases are needed to investigate coherence. Also, this symmetric example cannot by itself reveal a reversed bit order: always read the metadata.

Try two changes

  1. Change shots from 32 to 1,000, then compare the measured frequencies with 1/2. Is the difference smaller? Repeat with several seeds before drawing a conclusion.
  2. Remove .cx(0, 1) but keep H and measurement. Which qubit can now vary? Interpret the bitstrings using bit_order.
Check your reasoning

More shots generally reduce relative sampling fluctuations, although one particular pair of runs need not show a smaller error. Without CX, only qubit 0 is in a superposition; qubit 1 stays in state 0. Use the recorded ordering to identify its position in the printed strings.

Continue with parameter binding. To save an interactive view of a result, see experiment reports.

中文版

SDK 1.0.8a · `8b227bff`