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

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(|0i|1)

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
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]
plot_bloch_vector([1, 0, 0], title="|+> state")

2. Quantum Gates

2.1 Unitary Transformations

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

UU=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=(0ii0)Y|0=i|1,Y|1=i|0

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

Pauli Z Gate

Z=(1001)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(1111)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)

Summary of Non-Parameterized Single-Qubit Gates

GateMatrixEffect on |0Effect on |1
X(0110)|1|0
Y(0ii0)i|1i|0
Z(1001)|0|1
H12(1111)|+|
S(100i)|0i|1
T(100eiπ/4)|0eiπ/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θ2isinθ2isinθ2cosθ2)=eiθX/2

RY Gate (Rotation around Y axis)

RY(θ)=(cosθ2sinθ2sinθ2cosθ2)=eiθY/2

RZ Gate (Rotation around Z axis)

RZ(θ)=(eiθ/200eiθ/2)=eiθ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 eiθ/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>

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=(1000010000100001)|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)

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(ab)

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>

Gate Taxonomy


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 math
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

# The dagger of S is S^\dagger (which is S^3 or equivalently Z*S)
s_gate = core.S(0)
s_dagger = s_gate.dagger()
s_mat = np.array(s_gate.matrix())
sd_mat = np.array(s_dagger.matrix())
print("S:\n", s_mat)
print("S.dagger():\n", sd_mat)
# S = [[1,0],[0,i]], S.dagger() = [[1,0],[0,-i]]

# 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

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}

3.3 Power (.power())

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

This is especially useful for fractional powers of gates:

python
from pyqpanda3 import core
import math
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

# Negative power: U^{-1} = U.dagger()
s_inv = core.S(0).power(-1)
s_dag = core.S(0).dagger()
print("S^{-1} == S.dagger():", np.allclose(
    np.array(s_inv.matrix()),
    np.array(s_dag.matrix())
))
# Output: S^{-1} == S.dagger(): 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 (4x4):")
print(np.round(ch_matrix, 3))
# [[ 0.707  0.     0.707  0.   ]
#  [ 0.     0.707  0.     0.707]
#  [ 0.707  0.    -0.707  0.   ]
#  [ 0.     0.707  0.    -0.707]]

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=02n1ci|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
core.measure(qubit_index, classical_bit_index)

Multi-qubit measurement:

python
core.measure([qubit_0, qubit_1, ...], [cbit_0, cbit_1, ...])

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: {'01': 502, '11': 498}
# Qubit 0 is random, qubit 1 is always 1

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
import math

# 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}")

The following diagram illustrates the measurement process:

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})")

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 |1Default 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:

  • Circuit Construction -- learn how to compose gates into complex circuits using QProg, QCircuit, and the << operator
  • Simulation -- explore the different simulators (CPUQVM, DensityMatrixSimulator, Stabilizer)
  • Visualization -- learn to draw circuits and plot quantum states on the Bloch sphere

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)

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(1ii1). Applied to |0, it produces 12(|0i|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.core import CPUQVM, QProg, RY, measure

qvm = 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 = QProg()
prog << RY(0, theta)
prog << 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!")

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.core import CPUQVM, QProg, H, X, Z, CNOT, measure

qvm = CPUQVM()
shots = 5000

def run_and_print(name, prog):
    prog << 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 = QProg()
prog_pp << H(0) << 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 = QProg()
prog_pm << H(0) << Z(0) << 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 = QProg()
prog_mp << H(0) << X(1) << 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 = QProg()
prog_mm << X(0) << H(0) << X(1) << 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!")

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.core import CPUQVM, QProg, Oracle, measure

# 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 = CPUQVM()

# Apply to |0⟩: expect cos(π/8)|0⟩ + sin(π/8)|1⟩
prog = QProg()
oracle = Oracle([0], matrix)
prog << oracle << 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!")

Released under the MIT License.