Skip to content

Quantum Computing Basics ​

This tutorial introduces the fundamental building blocks of quantum computing: qubits, quantum gates, and measurement. You will learn the mathematical foundations and how to apply them using pyqpanda3.

Prerequisites: Getting Started -- ensure pyqpanda3 is installed and working.


Table of Contents ​


1. What is a Qubit? ​

1.1 Classical Bit vs Qubit ​

A classical bit can be in one of two states: 0 or 1. A quantum bit (qubit) also has two basis states, written in Dirac notation as |0⟩ and |1⟩, but it can also exist in a linear combination of both.

PropertyClassical BitQubit
States0 or 1|0⟩, |1⟩, or any superposition
NotationBinary digitKet vector |ψ⟩
Simultaneous statesOne at a timeBoth at once (superposition)
MeasurementDoes not change stateCollapses to basis state
RepresentationVoltage levelVector in Hilbert space

1.2 Superposition ​

A qubit in an arbitrary state is described by:

|ψ⟩=α|0⟩+β|1⟩

where α and β are complex numbers called amplitudes that satisfy the normalization condition:

|α|2+|β|2=1

The probability of measuring the qubit in state |0⟩ is |α|2, and the probability of measuring |1⟩ is |β|2.

In column vector form, the basis states are:

|0⟩=(10),|1⟩=(01)

So a general qubit state can be written as:

|ψ⟩=(αβ)

The key insight is that the qubit holds both possibilities simultaneously until measured. This is not the same as "being in an unknown state" -- the amplitudes α and β carry phase information that enables quantum interference.

python
from pyqpanda3 import core

# The |0> state is the default when a qubit is allocated
# Let's verify by measuring a fresh qubit
prog = core.QProg()
prog << core.measure(0, 0)

machine = core.CPUQVM()
machine.run(prog, shots=1000)
counts = machine.result().get_counts()
print(counts)
# Output: {'0': 1000}  -- always |0> since no gates were applied

运行结果:

{'0': 1000}

1.3 The Bloch Sphere ​

Any single-qubit pure state can be parameterized by two angles θ and ϕ on the Bloch sphere:

|ψ⟩=cos⁡θ2|0⟩+eiϕsin⁡θ2|1⟩

where 0≤θ≤π and 0≤ϕ<2π. Every point on the surface of the unit sphere corresponds to a unique qubit state.

Key points on the Bloch sphere:

  • North pole (θ=0): |0⟩
  • South pole (θ=π): |1⟩
  • Positive X (θ=π/2,ϕ=0): |+⟩=12(|0⟩+|1⟩)
  • Negative X (θ=π/2,ϕ=π): |−⟩=12(|0⟩−|1⟩)
  • Positive Y (θ=π/2,ϕ=π/2): |+i⟩=12(|0⟩+i|1⟩)
  • Negative Y (θ=π/2,ϕ=3π/2): |−i⟩=12(|0⟩−i|1⟩)
mermaid
graph TB
    subgraph "Bloch Sphere Concept"
        B["Bloch Sphere<br/>Unit sphere in 3D"]
        N["North Pole: |0⟩<br/>(θ = 0)"]
        S["South Pole: |1⟩<br/>(θ = π)"]
        PX["+X axis: |+⟩<br/>(θ = π/2, φ = 0)"]
        NX["-X axis: |-⟩<br/>(θ = π/2, φ = π)"]
        PY["+Y axis: |+i⟩<br/>(θ = π/2, φ = π/2)"]
        NY["-Y axis: |-i⟩<br/>(θ = π/2, φ = 3π/2)"]
        P["Any point on surface<br/>represents a pure qubit state"]

        B --- N
        B --- S
        B --- PX
        B --- NX
        B --- PY
        B --- NY
        B --- P
    end

The Bloch vector r→=(sin⁡θcos⁡ϕ,sin⁡θsin⁡ϕ,cos⁡θ) points from the origin to the state on the sphere. Quantum gates rotate this vector.

pyqpanda3 provides Bloch sphere visualization through the visualization module:

python
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
from unittest.mock import patch
# pyqpanda3's bloch_plot module calls plt.switch_backend('TKAgg') at import time,
# which requires an interactive display. We patch it to a no-op since Agg is sufficient.
# Alternatively, set the MPLBACKEND environment variable before running:
#   import os; os.environ['MPLBACKEND'] = 'Agg'
with patch('matplotlib.pyplot.switch_backend'):
    from pyqpanda3.visualization import plot_bloch_vector

# Plot the |+> state (pointing along +X axis)
# Bloch vector: [sin(pi/2)*cos(0), sin(pi/2)*sin(0), cos(pi/2)] = [1, 0, 0]
fig = plot_bloch_vector([1, 0, 0], title="|+> state")
print('Bloch sphere figure created successfully')
print(f'Figure type: {type(fig).__name__}')
plt.close(fig)

运行结果:

Bloch sphere figure created successfully
Figure type: Figure

2. Quantum Gates ​

2.1 Unitary Transformations ​

Quantum gates are unitary transformations that evolve qubit states. A matrix U is unitary if:

U†U=UU†=I

where U† is the conjugate transpose of U. This condition ensures that:

  • The total probability is preserved (|α′|2+|β′|2=1)
  • The gate is reversible (every gate has an inverse)

When a gate U acts on a state |ψ⟩, the new state is:

|ψ′⟩=U|ψ⟩

For multi-qubit systems, gates acting on specific qubits are represented by the tensor product of the gate matrix with identity matrices on the other qubits.

2.2 Single-Qubit Gates ​

pyqpanda3 provides the following single-qubit gates with no parameters:

Pauli X Gate (NOT Gate) ​

The X gate flips the computational basis states, analogous to a classical NOT gate.

X=(0110)X|0⟩=|1⟩,X|1⟩=|0⟩

On the Bloch sphere, X is a π-rotation around the X axis.

Pauli Y Gate ​

Y=(0−ii0)Y|0⟩=i|1⟩,Y|1⟩=−i|0⟩

On the Bloch sphere, Y is a π-rotation around the Y axis.

Pauli Z Gate ​

Z=(100−1)Z|0⟩=|0⟩,Z|1⟩=−|1⟩

The Z gate applies a phase flip to |1⟩. It is a π-rotation around the Z axis.

Hadamard Gate (H) ​

The Hadamard gate creates equal superpositions:

H=12(111−1)H|0⟩=12(|0⟩+|1⟩)=|+⟩,H|1⟩=12(|0⟩−|1⟩)=|−⟩

This is the most commonly used gate for creating superposition. Applying H twice returns to the original state: HH=I.

S Gate (Phase Gate) ​

S=(100i)=Z1/2S|0⟩=|0⟩,S|1⟩=i|1⟩

The S gate is the square root of Z. It applies a 90∘ phase to |1⟩.

T Gate (π/8 Gate) ​

T=(100eiπ/4)=S1/2=Z1/4T|0⟩=|0⟩,T|1⟩=eiπ/4|1⟩

The T gate is the fourth root of Z. It is non-Clifford and essential for universal quantum computation.

I Gate (Identity) ​

I=(1001)

The identity gate leaves the state unchanged. It is useful for padding circuits or as a placeholder.

python
from pyqpanda3 import core

# Apply single-qubit gates to qubit 0
prog = core.QProg()
prog << core.H(0)       # Hadamard on qubit 0
prog << core.X(0)       # Pauli-X on qubit 0
prog << core.Y(0)       # Pauli-Y on qubit 0
prog << core.Z(0)       # Pauli-Z on qubit 0
prog << core.S(0)       # S gate on qubit 0
prog << core.T(0)       # T gate on qubit 0
prog << core.I(0)       # Identity on qubit 0

print(prog)

运行结果:

          ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ 
q_0:  |0>─┤H├ ┤X├ ┤Y├ ┤Z├ ┤S├ ┤T├ ┤I├ 
          └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ 
 c :   / ════════════════════════════

Summary of Non-Parameterized Single-Qubit Gates ​

GateMatrixEffect on |0⟩Effect on |1⟩
X(0110)|1⟩|0⟩
Y(0−ii0)i|1⟩−i|0⟩
Z(100−1)|0⟩−|1⟩
H12(111−1)|+⟩|−⟩
S(100i)|0⟩i|1⟩
T(100eiπ/4)|0⟩eiπ/4|1⟩
I(1001)|0⟩|1⟩

2.3 Rotation Gates ​

Rotation gates are parameterized by an angle θ and rotate the state around a specific axis of the Bloch sphere.

RX Gate (Rotation around X axis) ​

RX(θ)=(cos⁡θ2−isin⁡θ2−isin⁡θ2cos⁡θ2)=e−iθX/2

RY Gate (Rotation around Y axis) ​

RY(θ)=(cos⁡θ2−sin⁡θ2sin⁡θ2cos⁡θ2)=e−iθY/2

RZ Gate (Rotation around Z axis) ​

RZ(θ)=(e−iθ/200eiθ/2)=e−iθZ/2

P Gate (Phase Gate) ​

P(θ)=(100eiθ)

Note that P(π/2)=S and P(π/4)=T, so P generalizes the S and T gates. Also note that P(θ)=RZ(θ) up to a global phase of e−iθ/2.

python
import math
from pyqpanda3 import core

# Rotation gates take (qubit_index, angle_in_radians)
prog = core.QProg()
prog << core.RX(0, math.pi / 4)    # Rotate pi/4 around X
prog << core.RY(1, math.pi / 2)    # Rotate pi/2 around Y
prog << core.RZ(2, math.pi)        # Rotate pi around Z (= Z gate up to phase)
prog << core.P(0, math.pi / 4)     # Phase gate with angle pi/4 (= T gate)

# Verify that RX(pi) behaves like X (up to global phase)
# RX(pi) = [[0, -i], [-i, 0]] -- multiplies by -i relative to X
prog_rx = core.QProg()
prog_rx << core.RX(0, math.pi)
prog_rx << core.measure(0, 0)

machine = core.CPUQVM()
machine.run(prog_rx, shots=1000)
print(machine.result().get_counts())
# Output: {'1': 1000}  -- same measurement statistics as X|0>

运行结果:

{'1': 1000}

2.4 Two-Qubit Gates ​

Two-qubit gates act on pairs of qubits and can create entanglement, a uniquely quantum phenomenon where the states of two qubits become correlated in a way that cannot be described classically.

CNOT Gate (Controlled-NOT) ​

The most fundamental two-qubit gate. It flips the target qubit if and only if the control qubit is |1⟩.

CNOT=(1000010000010010)

Basis state action (first qubit is control, second is target):

|00⟩→|00⟩,|01⟩→|01⟩,|10⟩→|11⟩,|11⟩→|10⟩

In pyqpanda3: core.CNOT(control, target).

CZ Gate (Controlled-Z) ​

Applies a Z gate to the target qubit if the control is |1⟩. The CZ gate is symmetric -- both qubits play the same role.

CZ=(100001000010000−1)|11⟩→−|11⟩,others unchanged

In pyqpanda3: core.CZ(qubit1, qubit2).

SWAP Gate ​

Exchanges the states of two qubits.

SWAP=(1000001001000001)|01⟩→|10⟩,|10⟩→|01⟩,|00⟩→|00⟩,|11⟩→|11⟩

In pyqpanda3: core.SWAP(qubit1, qubit2).

Parameterized Two-Qubit Gates ​

pyqpanda3 also provides parameterized two-qubit gates:

GateSyntaxDescription
CRXcore.CRX(control, target, theta)Controlled RX rotation
CRYcore.CRY(control, target, theta)Controlled RY rotation
CRZcore.CRZ(control, target, theta)Controlled RZ rotation
CPcore.CP(control, target, theta)Controlled phase
CUcore.CU(control, target, theta, phi, lam, gamma)General controlled unitary
RXXcore.RXX(q1, q2, theta)XX interaction
RYYcore.RYY(q1, q2, theta)YY interaction
RZZcore.RZZ(q1, q2, theta)ZZ interaction
RZXcore.RZX(q1, q2, theta)ZX interaction
python
from pyqpanda3 import core

# Two-qubit gate examples
prog = core.QProg()
prog << core.CNOT(0, 1)    # CNOT: control=0, target=1
prog << core.CZ(1, 2)      # CZ between qubits 1 and 2
prog << core.SWAP(0, 1)    # SWAP qubits 0 and 1

# Parameterized two-qubit gates
import math
prog << core.CRX(0, 1, math.pi / 4)   # Controlled-RX with angle pi/4
prog << core.RZZ(0, 1, math.pi / 2)   # ZZ rotation with angle pi/2

print(prog)

运行结果:

          ┌───────────────────┐ 
q_0:  |0>────*── ──── X ────────*─────── ┤0                  ├ 
          ┌──┴─┐      │ ┌───────┴──────┐ │  RZZ(1.57079633)  │ 
q_1:  |0>─┤CNOT├ ──*─ X ┤RX(0.78539816)├ ┤1                  ├ 
          └────┘ ┌─┴┐   └──────────────┘ └───────────────────┘ 
q_2:  |0>─────── ┤CZ├ ─ ──────────────── ───────────────────── 
                 └──┘                                          
 c :   / ═════════════════════════════════════════════════════

2.5 Multi-Qubit Gates ​

TOFFOLI Gate (CCNOT) ​

The TOFFOLI gate is a three-qubit gate with two control qubits and one target. It flips the target if and only if both controls are |1⟩.

TOFFOLI|a,b,c⟩=|a,b,c⊕(a⋅b)⟩

In matrix form (8x8), it acts as identity except for swapping the last two rows/columns:

TOFFOLI=(1000000001000000001000000001000000001000000001000000000100000010)

In pyqpanda3: core.TOFFOLI(control1, control2, target).

python
from pyqpanda3 import core

# TOFFOLI: flips qubit 2 only when qubits 0 and 1 are both |1>
prog = core.QProg()
prog << core.X(0)                  # Set control qubit 0 to |1>
prog << core.X(1)                  # Set control qubit 1 to |1>
prog << core.TOFFOLI(0, 1, 2)     # Target qubit 2 flips to |1>
prog << core.measure([0, 1, 2], [0, 1, 2])

machine = core.CPUQVM()
machine.run(prog, shots=1000)
print(machine.result().get_counts())
# Output: {'111': 1000}  -- all three qubits are |1>

运行结果:

{'111': 1000}

Gate Taxonomy ​

mermaid
graph TD
    QG["Quantum Gates"]
    QG --> SQ["Single-Qubit Gates"]
    QG --> TQ["Two-Qubit Gates"]
    QG --> MQ["Multi-Qubit Gates"]

    SQ --> NP1["Non-Parameterized"]
    SQ --> P1["Parameterized"]

    NP1 --> X["X (NOT)"]
    NP1 --> Y["Y"]
    NP1 --> Z["Z"]
    NP1 --> H["H (Hadamard)"]
    NP1 --> S["S (Phase)"]
    NP1 --> T["T (π/8)"]
    NP1 --> I["I (Identity)"]
    NP1 --> X1["X1"]
    NP1 --> Y1["Y1"]
    NP1 --> Z1["Z1"]

    P1 --> RX["RX(theta)"]
    P1 --> RY["RY(theta)"]
    P1 --> RZ["RZ(theta)"]
    P1 --> P["P(theta)"]
    P1 --> U1["U1(theta)"]
    P1 --> U2["U2(theta, phi)"]
    P1 --> U3["U3(theta, phi, lambda)"]
    P1 --> U4["U4(theta, phi, lambda, gamma)"]
    P1 --> RPHI["RPHI(theta, phi)"]

    TQ --> NP2["Non-Parameterized"]
    TQ --> P2["Parameterized"]

    NP2 --> CNOT["CNOT"]
    NP2 --> CZ["CZ"]
    NP2 --> SWAP["SWAP"]
    NP2 --> ISWAP["ISWAP"]
    NP2 --> SQISWAP["SQISWAP"]
    NP2 --> MS["MS"]

    P2 --> CRX["CRX(theta)"]
    P2 --> CRY["CRY(theta)"]
    P2 --> CRZ["CRZ(theta)"]
    P2 --> CP["CP(theta)"]
    P2 --> CU["CU(theta, phi, lambda, gamma)"]
    P2 --> RXX["RXX(theta)"]
    P2 --> RYY["RYY(theta)"]
    P2 --> RZZ["RZZ(theta)"]
    P2 --> RZX["RZX(theta)"]

    MQ --> TOFFOLI["TOFFOLI (CCNOT)"]

    style QG fill:#e1f5fe
    style SQ fill:#fff3e0
    style TQ fill:#e8f5e9
    style MQ fill:#fce4ec

3. Gate Operations in pyqpanda3 ​

pyqpanda3 gates support four powerful operations: adjoint, control, power, and matrix extraction. These operations allow you to construct complex circuits from simple building blocks.

3.1 Adjoint (.dagger()) ​

The .dagger() method returns the adjoint (conjugate transpose) of a gate. For unitary gates, the adjoint is the inverse. This is useful for:

  • Uncomputing intermediate results
  • Implementing quantum algorithms that require backward steps
  • Constructing reflection operators
U†=(U∗)T
python
from pyqpanda3 import core
import numpy as np

# The dagger of H is H itself (H is self-adjoint)
h_gate = core.H(0)
h_dagger = h_gate.dagger()

# Verify: H.dagger() matrix should equal H matrix
h_mat = np.array(h_gate.matrix())
hd_mat = np.array(h_dagger.matrix())
print("H == H.dagger():", np.allclose(h_mat, hd_mat))
# Output: H == H.dagger(): True

# Verify: H·H = I (applying H twice returns to original state)
h_h = np.array(h_gate.matrix()) @ np.array(h_gate.matrix())
print("H·H == I:", np.allclose(h_h, np.eye(2)))
# Output: H·H == I: True

# Practical use: apply S then uncompute with S.dagger()
prog = core.QProg()
prog << core.H(0)           # Create superposition |+>
prog << core.S(0)            # Apply S gate
prog << core.S(0).dagger()   # Undo S gate (returns to |+>)
prog << core.H(0)            # Return to |0>
prog << core.measure(0, 0)

machine = core.CPUQVM()
machine.run(prog, shots=1000)
print(machine.result().get_counts())
# Output: {'0': 1000}  -- S and S.dagger() cancel out

运行结果:

H == H.dagger(): True
H·H == I: True
{'0': 1000}

3.2 Controlled Gates (.control()) ​

The .control(qubit) method transforms any gate into its controlled version. The original gate is applied to its target qubits only if the specified control qubit is in state |1⟩.

This is extremely powerful: you can create controlled versions of any gate, including gates that already have controls.

python
from pyqpanda3 import core

# Create a controlled-X (equivalent to CNOT) from X
x_gate = core.X(1)
controlled_x = x_gate.control(0)  # Control on qubit 0

# Use in a circuit
prog = core.QProg()
prog << core.X(0)              # Set control to |1>
prog << controlled_x           # X on qubit 1 is activated
prog << core.measure([0, 1], [0, 1])

machine = core.CPUQVM()
machine.run(prog, shots=1000)
print(machine.result().get_counts())
# Output: {'11': 1000}

# Create a controlled-Hadamard
h_gate = core.H(1)
controlled_h = h_gate.control(0)

# Create a controlled-SWAP (Fredkin gate)
swap_gate = core.SWAP(1, 2)
fredkin = swap_gate.control(0)  # SWAP qubits 1,2 only if qubit 0 is |1>

# Create a doubly-controlled gate (like TOFFOLI from X)
x_gate = core.X(2)
toffoli = x_gate.control(0).control(1)  # X on qubit 2 if qubits 0 AND 1 are |1>

# Verify the doubly-controlled gate
prog2 = core.QProg()
prog2 << core.X(0)             # Set first control to |1>
prog2 << core.X(1)             # Set second control to |1>
prog2 << toffoli                # X on qubit 2 activated
prog2 << core.measure([0, 1, 2], [0, 1, 2])

machine2 = core.CPUQVM()
machine2.run(prog2, shots=1000)
print(machine2.result().get_counts())
# Output: {'111': 1000}

运行结果:

{'11': 1000}
{'111': 1000}

3.3 Power (.power()) ​

The .power(k) method raises a gate to the k-th power: Uk=U⋅U⋯U (k times). For k<0, it computes (U†)|k|.

This is especially useful for fractional powers of gates:

python
from pyqpanda3 import core
import numpy as np

# X^2 = I (applying NOT twice returns to original)
x_gate = core.X(0)
x_squared = x_gate.power(2)

# Verify: X^2 should equal the identity matrix I
identity = np.eye(2, dtype=complex)
print("X^2 == I:", np.allclose(np.array(x_squared.matrix()), identity))
# Output: X^2 == I: True

# Z^{1/2} = S gate
z_gate = core.Z(0)
z_half = z_gate.power(0.5)

# Verify: Z^{1/2} should match S gate matrix
z_half_mat = np.array(z_half.matrix())
s_mat = np.array(core.S(0).matrix())
print("Z^{1/2} == S:", np.allclose(z_half_mat, s_mat))
# Output: Z^{1/2} == S: True

# Z^{1/4} = T gate
z_quarter = z_gate.power(0.25)
z_quarter_mat = np.array(z_quarter.matrix())
t_mat = np.array(core.T(0).matrix())
print("Z^{1/4} == T:", np.allclose(z_quarter_mat, t_mat))
# Output: Z^{1/4} == T: True

运行结果:

X^2 == I: True
Z^{1/2} == S: True
Z^{1/4} == T: True

3.4 Matrix Representation (.matrix()) ​

The .matrix() method returns the unitary matrix of a gate as a 2D array. This is useful for debugging, verification, and educational purposes.

python
from pyqpanda3 import core
import numpy as np

# Get the matrix of any gate
h_matrix = core.H(0).matrix()
print("H matrix:")
print(np.array(h_matrix))
# [[ 0.707  0.707]
#  [ 0.707 -0.707]]

x_matrix = core.X(0).matrix()
print("\nX matrix:")
print(np.array(x_matrix))
# [[0 1]
#  [1 0]]

# Two-qubit gate matrices are 4x4
cnot_matrix = core.CNOT(0, 1).matrix()
print("\nCNOT matrix:")
print(np.array(cnot_matrix))
# [[1 0 0 0]
#  [0 1 0 0]
#  [0 0 0 1]
#  [0 0 1 0]]

# Verify unitarity: U^\dagger U = I
h_arr = np.array(h_matrix)
should_be_identity = h_arr.conj().T @ h_arr
print("\nH^\dagger H (should be I):")
print(np.round(should_be_identity, 10))

# The matrix of a controlled gate
controlled_h = core.H(0).control(2)
ch_matrix = np.array(controlled_h.matrix())
print("\nControlled-H matrix:")
print(np.round(ch_matrix, 3))
# Note: .control().matrix() returns the base gate matrix without
# expanding for control qubits (2x2 for a single-qubit gate).
# [[ 0.707+0.j  0.707+0.j]
#  [ 0.707+0.j -0.707+0.j]]

运行结果:

H matrix:
[[ 0.70710678+0.j  0.70710678+0.j]
 [ 0.70710678+0.j -0.70710678+0.j]]

X matrix:
[[0.+0.j 1.+0.j]
 [1.+0.j 0.+0.j]]

CNOT matrix:
[[1.+0.j 0.+0.j 0.+0.j 0.+0.j]
 [0.+0.j 1.+0.j 0.+0.j 0.+0.j]
 [0.+0.j 0.+0.j 0.+0.j 1.+0.j]
 [0.+0.j 0.+0.j 1.+0.j 0.+0.j]]

H^\dagger H (should be I):
[[1.+0.j 0.+0.j]
 [0.+0.j 1.+0.j]]

Controlled-H matrix:
[[ 0.707+0.j  0.707+0.j]
 [ 0.707+0.j -0.707+0.j]]

4. Measurement ​

4.1 Projective Measurement ​

Measurement is the process of observing a quantum state, which collapses it from a superposition into a definite classical outcome. In the computational basis, measuring a qubit in state |ψ⟩=α|0⟩+β|1⟩ produces:

  • Outcome 0 with probability |α|2
  • Outcome 1 with probability |β|2

After measurement, the qubit is in the measured basis state. This collapse is irreversible -- the superposition information is lost.

For an n-qubit system in state:

|ψ⟩=∑i=02n−1ci|i⟩

measuring all qubits yields the bitstring |i⟩ with probability |ci|2.

4.2 Measuring in pyqpanda3 ​

pyqpanda3 provides two forms of measurement:

Single qubit measurement:

python
from pyqpanda3 import core

# Syntax: core.measure(qubit_index, classical_bit_index)
# Minimal runnable example: measure qubit 0 after H gate
p = core.QProg()
p << core.H(0) << core.measure(0, 0)
m = core.CPUQVM()
m.run(p, shots=100)
print(m.result().get_counts())

运行结果:

{'0': 54, '1': 46}

Note: Quantum measurement results are probabilistic. The exact counts shown above are example values from one run. Your actual output will differ each time you run the code.

Multi-qubit measurement:

python
from pyqpanda3 import core

# Syntax: core.measure([qubit_0, qubit_1, ...], [cbit_0, cbit_1, ...])
# Minimal runnable example: Bell state measurement
p = core.QProg()
p << core.H(0) << core.CNOT(0, 1)
p << core.measure(0, 0) << core.measure(1, 1)
m = core.CPUQVM()
m.run(p, shots=100)
print(m.result().get_counts())

运行结果:

{'00': 58, '11': 42}

Each qubit measurement result is stored in a corresponding classical bit (cbit).

python
from pyqpanda3 import core

# Single qubit measurement
prog1 = core.QProg()
prog1 << core.H(0)                 # Create superposition
prog1 << core.measure(0, 0)        # Measure qubit 0 into cbit 0

machine = core.CPUQVM()
machine.run(prog1, shots=1000)
print("Single qubit:", machine.result().get_counts())
# Output: {'0': 498, '1': 502}

# Multi-qubit measurement
prog2 = core.QProg()
prog2 << core.H(0)                 # Superposition on qubit 0
prog2 << core.X(1)                 # Qubit 1 in |1>
prog2 << core.measure([0, 1], [0, 1])  # Measure both

machine.run(prog2, shots=1000)
print("Two qubits:", machine.result().get_counts())
# Output: {'10': ~500, '11': ~500}
# Qubit 0 is random, qubit 1 is always 1

运行结果:

Single qubit: {'0': 496, '1': 504}
Two qubits: {'10': 490, '11': 510}

4.3 Shot-Based Measurement ​

Quantum measurement is inherently probabilistic. To build up statistics, we run the same circuit many times (called "shots"). The law of large numbers ensures that the observed frequencies converge to the true probabilities as the number of shots increases.

python
from pyqpanda3 import core

# Demonstrate shot-based measurement convergence
prog = core.QProg()
prog << core.H(0)       # Creates |+> = (|0> + |1>)/sqrt(2)
prog << core.measure(0, 0)

machine = core.CPUQVM()

# Few shots: high variance
machine.run(prog, shots=10)
counts_10 = machine.result().get_counts()
print(f"10 shots:   {counts_10}")

# Moderate shots
machine.run(prog, shots=100)
counts_100 = machine.result().get_counts()
print(f"100 shots:  {counts_100}")

# Many shots: closer to 50/50
machine.run(prog, shots=10000)
counts_10000 = machine.result().get_counts()
print(f"10000 shots: {counts_10000}")

# The probabilities approach 0.5 for each outcome
total = sum(counts_10000.values())
for key, val in sorted(counts_10000.items()):
    print(f"  P({key}) = {val/total:.4f}")

运行结果:

10 shots:   {'0': 5, '1': 5}
100 shots:  {'0': 46, '1': 54}
10000 shots: {'0': 4876, '1': 5124}
  P(0) = 0.4876
  P(1) = 0.5124

The following diagram illustrates the measurement process:

mermaid
flowchart TD
    A["Quantum Circuit"] --> B["Run on Simulator<br/>shots=N"]
    B --> C["Execute N times"]

    C --> D["Shot 1:<br/>collapse to bitstring"]
    C --> E["Shot 2:<br/>collapse to bitstring"]
    C --> F["Shot ..."]
    C --> G["Shot N:<br/>collapse to bitstring"]

    D --> H["Aggregate Results<br/>get_counts()"]
    E --> H
    F --> H
    G --> H

    H --> I["Output: dict<br/>{'00': 248, '01': 253,<br/>'10': 251, '11': 248}"]

    style A fill:#e1f5fe
    style B fill:#fff3e0
    style H fill:#e8f5e9
    style I fill:#fce4ec

4.4 Complete Example: Bell State ​

Let us put everything together to create a Bell state -- one of the simplest entangled states:

|Φ+⟩=12(|00⟩+|11⟩)

The circuit is: H on qubit 0, then CNOT with control=0 and target=1.

python
from pyqpanda3 import core

# Step 1: Build the Bell state circuit
prog = core.QProg()
prog << core.H(0)                    # Hadamard creates superposition on qubit 0
prog << core.CNOT(0, 1)              # Entangle qubits 0 and 1
prog << core.measure([0, 1], [0, 1]) # Measure both qubits

# Step 2: Run on the CPU simulator
machine = core.CPUQVM()
machine.run(prog, shots=10000)

# Step 3: Get the measurement results
counts = machine.result().get_counts()
print("Bell state results:")
print(counts)
# Expected output: {'00': ~5000, '11': ~5000}
# Note: '01' and '10' should not appear (or very rarely due to numerical precision)

# Step 4: Analyze the results
total = sum(counts.values())
for bitstring in ['00', '01', '10', '11']:
    count = counts.get(bitstring, 0)
    probability = count / total
    print(f"  |{bitstring}>: {count} counts ({probability:.4f})")

运行结果:

Bell state results:
{'00': 4961, '11': 5039}
  |00>: 4961 counts (0.4961)
  |01>: 0 counts (0.0000)
  |10>: 0 counts (0.0000)
  |11>: 5039 counts (0.5039)

Why only 00 and 11? The H gate puts qubit 0 in |+⟩=12(|0⟩+|1⟩). The CNOT copies the state of qubit 0 onto qubit 1:

CNOT(H|0⟩⊗|0⟩)=12(|00⟩+|11⟩)

The two qubits are now entangled: measuring one immediately determines the other, regardless of the physical distance between them. This is the resource that powers quantum teleportation, superdense coding, and quantum error correction.


5. Summary ​

This tutorial covered the three foundational concepts of quantum computing:

ConceptKey Ideapyqpanda3 API
QubitSuperposition of |0⟩ and |1⟩Default state when allocated
Quantum GateUnitary transformation of qubit statecore.H(0), core.X(0), core.CNOT(0,1), etc.
MeasurementCollapses superposition to classical bitcore.measure(qubit, cbit)

Gate operations extend the gate library:

OperationMethodDescription
Adjoint.dagger()Returns the inverse gate U†
Control.control(q)Adds a control qubit
Power.power(k)Computes Uk (supports fractional k)
Matrix.matrix()Returns the unitary matrix

Next steps:


Quick Reference ​

python
from pyqpanda3 import core
import math

# ===================
# Single-Qubit Gates
# ===================
core.H(0)           # Hadamard
core.X(0)           # Pauli-X (NOT)
core.Y(0)           # Pauli-Y
core.Z(0)           # Pauli-Z
core.S(0)           # S gate (sqrt of Z)
core.T(0)           # T gate (4th root of Z)
core.I(0)           # Identity

# ===================
# Rotation Gates
# ===================
core.RX(0, math.pi / 4)   # Rotate around X
core.RY(0, math.pi / 2)   # Rotate around Y
core.RZ(0, math.pi)       # Rotate around Z
core.P(0, math.pi / 4)    # Phase gate

# ===================
# Two-Qubit Gates
# ===================
core.CNOT(0, 1)            # Controlled-NOT
core.CZ(0, 1)              # Controlled-Z
core.SWAP(0, 1)            # SWAP

# ===================
# Multi-Qubit Gates
# ===================
core.TOFFOLI(0, 1, 2)     # Doubly-controlled NOT

# ===================
# Gate Operations
# ===================
gate = core.H(0)
gate.dagger()               # Adjoint (inverse)
gate.control(2)             # Controlled version (control on qubit 2)
gate.power(0.5)             # Fractional power
gate.matrix()               # Unitary matrix

# ===================
# Measurement
# ===================
core.measure(0, 0)                       # Single qubit
core.measure([0, 1], [0, 1])             # Multiple qubits

# ===================
# Run Circuit
# ===================
prog = core.QProg()
prog << core.H(0) << core.CNOT(0, 1)
prog << core.measure([0, 1], [0, 1])

machine = core.CPUQVM()
machine.run(prog, shots=1000)
counts = machine.result().get_counts()
print(counts)

运行结果:

{'00': 490, '11': 510}

Knowledge Check ​

Test your understanding of quantum computing basics with pyqpanda3.

Q1: What is the normalization constraint on a qubit state |ψ⟩=α|0⟩+β|1⟩?

A1: The amplitudes must satisfy |α|2+|β|2=1. This ensures the total probability of all measurement outcomes equals 1, a fundamental requirement of quantum mechanics.

Q2: What does the Hadamard gate do to the basis states |0⟩ and |1⟩?

A2: H|0⟩=12(|0⟩+|1⟩)=|+⟩ and H|1⟩=12(|0⟩−|1⟩)=|−⟩. It creates equal superpositions from computational basis states, mapping between the Z-basis and X-basis.

Q3: State the Born rule. If a qubit is in state |ψ⟩=12|0⟩+32|1⟩, what are the measurement probabilities?

A3: The Born rule states P(x)=|αx|2. Here, P(0)=|1/2|2=1/4 and P(1)=|3/2|2=3/4.

Q4: What is the difference between a product state and an entangled state?

A4: A product state can be factored as |ψ⟩=|ϕ1⟩⊗|ϕ2⟩, meaning each qubit has an independent state. An entangled state cannot be factored -- the qubits exhibit correlations that cannot be described by independent states. The Bell state |Φ+⟩=12(|00⟩+|11⟩) is entangled.

Q5: What is the relationship between the S gate, T gate, and Z gate?

A5: S2=Z and T2=S, so T4=S2=Z and T8=I. The S gate is the square root of Z, and the T gate is the fourth root of Z.

Q6: Write the matrix for RX(π/2) and explain what it does to |0⟩.

A6: RX(θ)=(cos⁡(θ/2)−isin⁡(θ/2)−isin⁡(θ/2)cos⁡(θ/2)). For θ=π/2: RX(π/2)=12(1−i−i1). Applied to |0⟩, it produces 12(|0⟩−i|1⟩), which is the |−i⟩ eigenstate on the Bloch sphere.

Q7: Explain quantum interference in the context of applying two Hadamard gates in sequence.

A7: HH|0⟩=|0⟩ and HH|1⟩=|1⟩. The first H creates 12(|0⟩+|1⟩), then the second H produces 12(|0⟩+|1⟩+|0⟩−|1⟩)=|0⟩. The |1⟩ amplitudes cancel (destructive interference) while |0⟩ amplitudes add (constructive interference).


Exercise 1: State Preparation

Write a pyqpanda3 program that prepares the state |ψ⟩=cos⁡(π/6)|0⟩+sin⁡(π/6)|1⟩. Verify the measurement probabilities match the Born rule predictions: P(0)=cos2⁡(π/6)=3/4 and P(1)=sin2⁡(π/6)=1/4.

Solution:

python
import numpy as np
from pyqpanda3 import core

qvm = core.CPUQVM()

# The state cos(θ/2)|0⟩ + sin(θ/2)|1⟩ is prepared by RY(θ)
# We want cos(π/6)|0⟩ + sin(π/6)|1⟩
# So θ/2 = π/6 → θ = π/3
theta = np.pi / 3

prog = core.QProg()
prog << core.RY(0, theta)
prog << core.measure([0], [0])

qvm.run(prog, shots=10000)
result = qvm.result()
counts = result.get_counts()

p0_measured = counts.get("0", 0) / 10000
p1_measured = counts.get("1", 0) / 10000
p0_expected = np.cos(np.pi/6)**2  # 0.75
p1_expected = np.sin(np.pi/6)**2  # 0.25

print(f"P(|0⟩) measured: {p0_measured:.4f}, expected: {p0_expected:.4f}")
print(f"P(|1⟩) measured: {p1_measured:.4f}, expected: {p1_expected:.4f}")
assert abs(p0_measured - p0_expected) < 0.03
assert abs(p1_measured - p1_expected) < 0.03
print("Verification passed!")

运行结果:

P(|0⟩) measured: 0.7503, expected: 0.7500
P(|1⟩) measured: 0.2497, expected: 0.2500
Verification passed!

Exercise 2: Entanglement Verification

Prepare all four Bell states and verify their measurement statistics. The four Bell states are:

|Φ+⟩=12(|00⟩+|11⟩),|Φ−⟩=12(|00⟩−|11⟩)|Ψ+⟩=12(|01⟩+|10⟩),|Ψ−⟩=12(|01⟩−|10⟩)

Solution:

python
from pyqpanda3 import core

qvm = core.CPUQVM()
shots = 5000

def run_and_print(name, prog):
    prog << core.measure([0, 1], [0, 1])
    qvm.run(prog, shots=shots)
    counts = qvm.result().get_counts()
    print(f"{name}: {counts}")
    return counts

# |Φ+⟩ = (|00⟩ + |11⟩) / √2
prog_pp = core.QProg()
prog_pp << core.H(0) << core.CNOT(0, 1)
c1 = run_and_print("|Φ+⟩", prog_pp)
assert c1.get("01", 0) < 100 and c1.get("10", 0) < 100

# |Φ-⟩ = (|00⟩ - |11⟩) / √2
prog_pm = core.QProg()
prog_pm << core.H(0) << core.Z(0) << core.CNOT(0, 1)
c2 = run_and_print("|Φ-⟩", prog_pm)
assert c2.get("01", 0) < 100 and c2.get("10", 0) < 100

# |Ψ+⟩ = (|01⟩ + |10⟩) / √2
prog_mp = core.QProg()
prog_mp << core.H(0) << core.X(1) << core.CNOT(0, 1)
c3 = run_and_print("|Ψ+⟩", prog_mp)
assert c3.get("00", 0) < 100 and c3.get("11", 0) < 100

# |Ψ-⟩ = (|01⟩ - |10⟩) / √2
prog_mm = core.QProg()
prog_mm << core.X(0) << core.H(0) << core.X(1) << core.CNOT(0, 1)
c4 = run_and_print("|Ψ-⟩", prog_mm)
assert c4.get("00", 0) < 100 and c4.get("11", 0) < 100

print("\nAll four Bell states verified!")

运行结果:

|Φ+⟩: {'00': 2519, '11': 2481}
|Φ-⟩: {'00': 2529, '11': 2471}
|Ψ+⟩: {'01': 2463, '10': 2537}
|Ψ-⟩: {'01': 2474, '10': 2526}

All four Bell states verified!

Exercise 3: Custom Gate Matrix Verification

Create a custom unitary gate from a 2×2 matrix and verify its action on basis states matches the expected matrix multiplication.

Solution:

python
import numpy as np
from pyqpanda3 import core

# Define a custom unitary: RY(π/4) matrix
theta = np.pi / 4
matrix = np.array([
    [np.cos(theta/2), -np.sin(theta/2)],
    [np.sin(theta/2),  np.cos(theta/2)]
], dtype=complex)

# Create oracle from matrix and verify
qvm = core.CPUQVM()

# Apply to |0⟩: expect cos(π/8)|0⟩ + sin(π/8)|1⟩
prog = core.QProg()
oracle = core.Oracle([0], matrix)
prog << oracle << core.measure([0], [0])
qvm.run(prog, shots=10000)
counts = qvm.result().get_counts()
p0 = counts.get("0", 0) / 10000
expected_p0 = np.cos(np.pi/8)**2
print(f"P(|0⟩) measured: {p0:.4f}, expected: {expected_p0:.4f}")
assert abs(p0 - expected_p0) < 0.03
print("Custom gate verified!")

运行结果:

P(|0⟩) measured: 0.8566, expected: 0.8536
Custom gate verified!

Released under the MIT License.