线路构件

量子线路由基本构件(QFT、Oracle、纠缠态等)拼装而成。本节列出官方提供的 线路片段示例,它们都可以通过 Circuit.add_circuit() 自由组合。

Quantum Fourier Transform (QFT) — complete example.

Source: examples/2_advanced/circuits/qft.py
Status: pass

Demonstrates:

  • Building a QFT circuit using qft_circuit

  • Preparing a computational basis state as input

  • Verifying QFT output via state-vector inspection

  • Running with Simulator for shot-based sampling

Usage: python qft.py [–n-qubits N] [–input-state STATE] [–shots N]

References: Nielsen, M. A. & Chuang, I. L. (2010). “Quantum Computation and Quantum Information.” Cambridge University Press, Section 5.1.

Source code

#!/usr/bin/env python
"""Quantum Fourier Transform (QFT) — complete example.

Demonstrates:
  * Building a QFT circuit using qft_circuit
  * Preparing a computational basis state as input
  * Verifying QFT output via state-vector inspection
  * Running with Simulator for shot-based sampling

Usage:
    python qft.py [--n-qubits N] [--input-state STATE] [--shots N]

References:
    Nielsen, M. A. & Chuang, I. L. (2010). "Quantum Computation and
    Quantum Information." Cambridge University Press, Section 5.1.

[doc-require: ]
[doc-warning-ignore: DeprecationWarning]
"""

import argparse
import sys
import math

# Add parent directory to path so we can import uniqc when running as a script
sys.path.insert(0, str(__file__.rsplit("/", 2)[0]))

from uniqc import Circuit
from uniqc.simulator import Simulator
from uniqc import basis_state
from uniqc import qft_circuit


def run_qft(n_qubits: int, input_state: int, shots: int = 4096) -> dict:
    """Run QFT on a computational basis state and return measurement frequencies.

    Args:
        n_qubits: Number of qubits.
        input_state: Integer encoding the input basis state.
        shots: Number of measurement shots.

    Returns:
        Dictionary mapping bit-strings to frequencies.
    """
    c = Circuit(n_qubits)

    # Prepare input state
    basis_state(c, state=input_state, qubits=list(range(n_qubits)))

    # Apply QFT
    qft_circuit(c, qubits=list(range(n_qubits)), swaps=True)

    # Measure all qubits
    c.measure(*list(range(n_qubits)))

    # Simulate
    sim = Simulator(least_qubit_remapping=False)
    result = sim.simulate_shots(c.qasm, shots=shots)
    total = sum(result.values())
    return {f"{int(k):0{n_qubits}b}": v / total for k, v in result.items()}


def main():
    parser = argparse.ArgumentParser(description="Quantum Fourier Transform (QFT)")
    parser.add_argument("--n-qubits", type=int, default=3, help="Number of qubits")
    parser.add_argument(
        "--input-state",
        type=int,
        default=5,
        help="Input computational basis state (integer, default 5)",
    )
    parser.add_argument("--shots", type=int, default=4096, help="Number of shots")
    args = parser.parse_args()

    n = args.n_qubits
    state = args.input_state
    if state >= 2**n:
        print(f"Error: input_state {state} out of range for {n} qubits (max {2**n - 1})")
        sys.exit(1)

    print(f" Quantum Fourier Transform — {n} qubits")
    print(f" Input state: |{state}⟩ = |{state:0{n}b}⟩")
    print()

    result = run_qft(n, state, shots=args.shots)

    # QFT of |j⟩ should produce equal superposition with phase encoding
    # For ideal QFT of |j⟩, all outcomes have equal probability 1/N
    n_outcomes = min(8, len(result))
    sorted_results = sorted(result.items(), key=lambda x: x[1], reverse=True)

    print(f" Results (top {n_outcomes}):")
    for bitstr, freq in sorted_results[:n_outcomes]:
        print(f"   |{bitstr}{freq * 100:5.1f}%")

    ideal_prob = 100.0 / (2**n)
    print()
    print(f" Ideal: each basis state has probability {ideal_prob:.2f}%")
    print(f" (QFT of |j⟩ produces equal-amplitude superposition with phase encoding)")
    print()
    print(f"  ✓ Run complete.")


if __name__ == "__main__":
    main()

Stdout

 Quantum Fourier Transform — 3 qubits
 Input state: |5⟩ = |101⟩

 Results (top 8):
   |010⟩   13.2%
   |001⟩   13.0%
   |111⟩   12.8%
   |101⟩   12.3%
   |011⟩   12.3%
   |110⟩   12.3%
   |100⟩   12.2%
   |000⟩   11.9%

 Ideal: each basis state has probability 12.50%
 (QFT of |j⟩ produces equal-amplitude superposition with phase encoding)

  ✓ Run complete.

Grover’s search using the public uniqc API.

Source: examples/2_advanced/circuits/grover_oracle.py
Status: pass

Demonstrates the full Grover search pipeline using root-level imports.

Usage: python examples/circuits/grover_oracle.py [–n-qubits N] [–marked-state STATE] [–shots N]

Source code

#!/usr/bin/env python
"""Grover's search using the public uniqc API.

Demonstrates the full Grover search pipeline using root-level imports.

Usage:
    python examples/circuits/grover_oracle.py [--n-qubits N] [--marked-state STATE] [--shots N]

[doc-require: ]
[doc-warning-ignore: DeprecationWarning]
"""

import argparse
import math
import sys

sys.path.insert(0, str(__file__.rsplit("/", 2)[0]))

from uniqc import Circuit
from uniqc.simulator import Simulator
from uniqc import grover_diffusion, grover_oracle


def run_grover(n_qubits: int, marked_state: int, shots: int = 4096):
    """Run Grover's search and return measurement frequencies."""
    c = Circuit()

    # Uniform superposition on data qubits
    data_qubits = list(range(n_qubits))
    for q in data_qubits:
        c.h(q)

    # Optimal iterations
    n_iter = max(1, min(int(math.pi / 4 * math.sqrt(2**n_qubits)), 10))

    ancilla = None
    for _ in range(n_iter):
        ancilla = grover_oracle(c, marked_state=marked_state, qubits=data_qubits, ancilla=ancilla)
        grover_diffusion(c, qubits=data_qubits, ancilla=ancilla)

    c.measure(*data_qubits)

    sim = Simulator(least_qubit_remapping=False)
    result = sim.simulate_shots(c.qasm, shots=shots)
    total = sum(result.values())
    return {f"{k:0{n_qubits}b}": v / total for k, v in result.items()}, n_iter


def main():
    parser = argparse.ArgumentParser(description="Grover's Search (circuits module)")
    parser.add_argument("--n-qubits", type=int, default=3, help="Number of data qubits")
    parser.add_argument("--marked-state", type=int, default=5, help="Marked state index")
    parser.add_argument("--shots", type=int, default=4096, help="Measurement shots")
    args = parser.parse_args()

    n = args.n_qubits
    marked = args.marked_state
    if marked >= 2**n:
        print(f"Error: marked_state {marked} out of range for {n} qubits")
        sys.exit(1)

    print(f"  Grover's Search — {n} data qubits")
    print(f"  Marked state: {marked} ({marked:0{n}b})")
    print(f"  Search space: {2**n} states")
    print()

    result, n_iter = run_grover(n, marked, shots=args.shots)
    marked_str = f"{marked:0{n}b}"

    print(f"  Iterations: {n_iter}")
    print(f"  Results (top 5):")
    for state, prob in sorted(result.items(), key=lambda x: -x[1])[:5]:
        tag = " ← TARGET" if state == marked_str else ""
        print(f"    |{state}{prob*100:5.1f}%{tag}")

    print(f"\n  Target probability: {result.get(marked_str, 0)*100:.1f}%")
    print(f"  ✓ Done.")


if __name__ == "__main__":
    main()

Stdout

  Grover's Search — 3 data qubits
  Marked state: 5 (101)
  Search space: 8 states

  Iterations: 2
  Results (top 5):
    |101⟩   94.8% ← TARGET
    |100⟩    1.0%
    |010⟩    1.0%
    |110⟩    0.8%
    |011⟩    0.7%

  Target probability: 94.8%
  ✓ Done.

Deutsch-Jozsa algorithm — complete example.

Source: examples/2_advanced/circuits/deutsch-jozsa.py
Status: pass

Demonstrates:

  • Building constant and balanced oracles

  • Running the Deutsch-Jozsa algorithm

  • Distinguishing constant from balanced functions with a single query

Usage: python deutsch-jozsa.py [–n-qubits N] [–oracle-type TYPE] [–shots N]

References: Deutsch, D. & Jozsa, R. (1992). “Rapid solutions of problems by quantum computation.” Proceedings of the Royal Society of London A.

Source code

#!/usr/bin/env python
"""Deutsch-Jozsa algorithm — complete example.

Demonstrates:
  * Building constant and balanced oracles
  * Running the Deutsch-Jozsa algorithm
  * Distinguishing constant from balanced functions with a single query

Usage:
    python deutsch-jozsa.py [--n-qubits N] [--oracle-type TYPE] [--shots N]

References:
    Deutsch, D. & Jozsa, R. (1992). "Rapid solutions of problems by
    quantum computation." Proceedings of the Royal Society of London A.

[doc-require: ]
[doc-warning-ignore: DeprecationWarning]
"""

import argparse
import sys

# Add parent directory to path so we can import uniqc when running as a script
sys.path.insert(0, str(__file__.rsplit("/", 2)[0]))

from uniqc import Circuit
from uniqc.simulator import Simulator
from uniqc import deutsch_jozsa_circuit, deutsch_jozsa_oracle


def run_deutsch_jozsa(
    n_qubits: int,
    oracle_type: str = "balanced",
    shots: int = 4096,
) -> dict:
    """Run the Deutsch-Jozsa algorithm.

    Args:
        n_qubits: Number of data qubits.
        oracle_type: "constant" or "balanced".
        shots: Number of measurement shots.

    Returns:
        Dictionary mapping bit-strings to frequencies.
    """
    balanced = oracle_type == "balanced"
    data_qubits = list(range(n_qubits))
    oracle = deutsch_jozsa_oracle(qubits=data_qubits, balanced=balanced)

    c = Circuit()
    deutsch_jozsa_circuit(c, oracle, qubits=data_qubits, ancilla=n_qubits)

    sim = Simulator(least_qubit_remapping=False)
    result = sim.simulate_shots(c.qasm, shots=shots)
    total = sum(result.values())
    return {f"{int(k):0{n_qubits}b}": v / total for k, v in result.items()}


def main():
    parser = argparse.ArgumentParser(description="Deutsch-Jozsa Algorithm")
    parser.add_argument("--n-qubits", type=int, default=3, help="Number of data qubits")
    parser.add_argument(
        "--oracle-type",
        choices=["constant", "balanced"],
        default="balanced",
        help="Oracle type (default: balanced)",
    )
    parser.add_argument("--shots", type=int, default=4096, help="Number of shots")
    args = parser.parse_args()

    n = args.n_qubits
    otype = args.oracle_type

    print(f" Deutsch-Jozsa Algorithm — {n} data qubits")
    print(f" Oracle type: {otype}")
    print()

    result = run_deutsch_jozsa(n, oracle_type=otype, shots=args.shots)

    all_zero = "0" * n
    zero_prob = result.get(all_zero, 0.0)

    sorted_results = sorted(result.items(), key=lambda x: x[1], reverse=True)
    print(f" Results (top outcomes):")
    for bitstr, freq in sorted_results[:5]:
        marker = " ← all zeros" if bitstr == all_zero else ""
        print(f"   |{bitstr}{freq * 100:5.1f}%{marker}")

    print()
    if zero_prob > 0.9:
        print(f"  → CONSTANT function (all measurements = |{all_zero}⟩)")
    else:
        print(f"  → BALANCED function (non-zero measurements detected)")

    print()
    print(f"  ✓ Run complete.")


if __name__ == "__main__":
    main()

Stdout

 Deutsch-Jozsa Algorithm — 3 data qubits
 Oracle type: balanced

 Results (top outcomes):
   |000⟩  100.0% ← all zeros

  → CONSTANT function (all measurements = |000⟩)

  ✓ Run complete.

Entangled State Preparation — GHZ, W, and Cluster states.

Source: examples/2_advanced/circuits/entangled_states.py
Status: pass

Demonstrates:

  • Preparing GHZ, W, and Cluster entangled states

  • Measuring and displaying probability distributions

  • Using the entangled_states module from uniqc

Usage: python entangled_states.py –state [ghz|w|cluster] [–n-qubits N] [–shots N]

References: * GHZ: Greenberger, D. M., Horne, M. A. & Zeilinger, A. (1989). “Going Beyond Bell’s Theorem.” In Bell’s Theorem, Quantum Theory and Conceptions of the Universe, 69–72. * W state: Dür, W., Vidal, G. & Cirac, J. I. (2000). “Three qubits can be entangled in two inequivalent ways.” Physical Review A, 62(6), 062314. * Cluster: Briegel, H. J. & Raussendorf, R. (2001). “Persistent Entanglement in Arrays of Interacting Particles.” Physical Review Letters, 86(5), 910.

Source code

#!/usr/bin/env python
"""Entangled State Preparation — GHZ, W, and Cluster states.

Demonstrates:
  * Preparing GHZ, W, and Cluster entangled states
  * Measuring and displaying probability distributions
  * Using the entangled_states module from uniqc

Usage:
    python entangled_states.py --state [ghz|w|cluster] [--n-qubits N] [--shots N]

References:
    * GHZ: Greenberger, D. M., Horne, M. A. & Zeilinger, A. (1989).
      "Going Beyond Bell's Theorem." In Bell's Theorem, Quantum Theory
      and Conceptions of the Universe, 69–72.
    * W state: Dür, W., Vidal, G. & Cirac, J. I. (2000).
      "Three qubits can be entangled in two inequivalent ways."
      Physical Review A, 62(6), 062314.
    * Cluster: Briegel, H. J. & Raussendorf, R. (2001).
      "Persistent Entanglement in Arrays of Interacting Particles."
      Physical Review Letters, 86(5), 910.

[doc-require: ]
[doc-warning-ignore: DeprecationWarning]
"""

import argparse
import sys

# Add parent directory to path so we can import uniqc when running as a script
sys.path.insert(0, str(__file__.rsplit("/", 2)[0]))

from uniqc import Circuit
from uniqc.simulator import Simulator
from uniqc import ghz_state, w_state, cluster_state


def run_state(state_type: str, n_qubits: int, shots: int = 4096) -> dict:
    """Prepare an entangled state and measure.

    Args:
        state_type: One of 'ghz', 'w', 'cluster'.
        n_qubits: Number of qubits.
        shots: Number of measurement shots.

    Returns:
        Dictionary with probability distribution.
    """
    c = Circuit(n_qubits)

    if state_type == "ghz":
        ghz_state(c)
    elif state_type == "w":
        w_state(c)
    elif state_type == "cluster":
        cluster_state(c)
    else:
        raise ValueError(f"Unknown state type: {state_type}")

    # Measure all qubits
    c.measure(*list(range(n_qubits)))

    # Simulate
    sim = Simulator(least_qubit_remapping=False)
    result = sim.simulate_shots(c.qasm, shots=shots)
    total = sum(result.values())
    probs = {f"{int(k):0{n_qubits}b}": v / total for k, v in result.items()}

    return dict(sorted(probs.items()))


def main():
    parser = argparse.ArgumentParser(description="Entangled State Preparation")
    parser.add_argument(
        "--state",
        type=str,
        default="ghz",
        choices=["ghz", "w", "cluster"],
        help="Type of entangled state",
    )
    parser.add_argument("--n-qubits", type=int, default=4, help="Number of qubits")
    parser.add_argument("--shots", type=int, default=4096, help="Number of shots")
    args = parser.parse_args()

    n = args.n_qubits
    state = args.state

    print(f" {state.upper()} State — {n} qubits")
    print()

    probs = run_state(state, n, args.shots)

    # Show only non-zero probabilities
    print(" Probability distribution:")
    for basis, p in probs.items():
        if p > 0.001:
            bar = "█" * int(p * 50)
            print(f"   |{basis}⟩: {p:.4f} {bar}")

    # Entanglement verification: show only dominant basis states
    dominant = {k: v for k, v in probs.items() if v > 0.01}
    print(f"\n Dominant basis states ({len(dominant)}):")
    for basis, p in sorted(dominant.items(), key=lambda x: -x[1]):
        print(f"   |{basis}⟩: {p:.4f}")


if __name__ == "__main__":
    main()

Stdout

 GHZ State — 4 qubits

 Probability distribution:
   |0000⟩: 0.5012 █████████████████████████
   |1111⟩: 0.4988 ████████████████████████

 Dominant basis states (2):
   |0000⟩: 0.5012
   |1111⟩: 0.4988

Dicke state preparation circuit — example.

Source: examples/2_advanced/circuits/dicke_state.py
Status: pass

Demonstrates the dicke_state_circuit building block for preparing Dicke states |D(n,k)⟩ — equal superpositions of all n-bit strings with exactly k ones.

Usage: python dicke_state.py [–n-qubits N] [–k K] [–shots N]

Source code

#!/usr/bin/env python
"""Dicke state preparation circuit — example.

Demonstrates the dicke_state_circuit building block for preparing
Dicke states |D(n,k)⟩ — equal superpositions of all n-bit strings
with exactly k ones.

Usage:
    python dicke_state.py [--n-qubits N] [--k K] [--shots N]

[doc-require: ]
[doc-warning-ignore: DeprecationWarning]
"""

import argparse
import sys
import math
from collections import Counter

# Add parent directory to path so we can import uniqc when running as a script
sys.path.insert(0, __file__.rsplit("/", 2)[0])

import numpy as np

from uniqc import Circuit
from uniqc.simulator import Simulator
from uniqc import dicke_state_circuit


def run_dicke(n_qubits, k, shots):
    """Run Dicke state preparation and verify probability distribution."""
    c = Circuit(n_qubits)
    dicke_state_circuit(c, k=k)
    c.measure(list(range(n_qubits)))

    sim = Simulator()
    raw = sim.simulate_shots(c.qasm, shots=shots)
    # simulate_shots returns int-keyed counts; render as bitstrings.
    result = {f"{int(k):0{n_qubits}b}": v for k, v in raw.items()}

    # Expected number of basis states with exactly k ones
    from math import comb
    n_expected = comb(n_qubits, k)
    expected_prob = 1.0 / n_expected

    total = sum(result.values())
    probs = {state: count / total for state, count in sorted(result.items())}

    print(f"Dicke State |D({n_qubits},{k})⟩ Preparation")
    print(f"Expected: {n_expected} basis states, each with probability {expected_prob:.6f}")
    print(f"\nMeasured probability distribution (shots={shots}):")
    print(f"  {'State':<12s} {'Measured':>10s} {'Weight':>8s} {'Theory':>10s}")
    print(f"  {'-'*12} {'-'*10} {'-'*8} {'-'*10}")

    correct_weight = 0
    for state, prob in probs.items():
        n_ones = bin(int(state, 2)).count("1")
        mark = "✓" if n_ones == k else "✗"
        if n_ones == k:
            correct_weight += prob
        print(f"  |{state}{prob:10.6f} {n_ones:>6d}{mark}  {expected_prob if n_ones == k else 0:10.6f}")

    print(f"\nTotal weight on Hamming-weight-{k} subspace: {correct_weight:.6f} (expected: 1.0)")


def main():
    parser = argparse.ArgumentParser(description="Dicke state preparation example")
    parser.add_argument("--n-qubits", type=int, default=4, help="Number of qubits (default: 4)")
    parser.add_argument("--k", type=int, default=2, help="Number of excitations (default: 2)")
    parser.add_argument("--shots", type=int, default=8192, help="Number of measurement shots (default: 8192)")
    args = parser.parse_args()

    if args.k < 1 or args.k > args.n_qubits:
        print(f"Error: k must satisfy 1 <= k <= n_qubits (got k={args.k}, n={args.n_qubits})")
        sys.exit(1)

    run_dicke(args.n_qubits, args.k, args.shots)


if __name__ == "__main__":
    main()

Stdout

Dicke State |D(4,2)⟩ Preparation
Expected: 6 basis states, each with probability 0.166667

Measured probability distribution (shots=8192):
  State          Measured   Weight     Theory
  ------------ ---------- -------- ----------
  |0011⟩    0.169189      2✓    0.166667
  |0101⟩    0.164795      2✓    0.166667
  |0110⟩    0.161133      2✓    0.166667
  |1001⟩    0.172974      2✓    0.166667
  |1010⟩    0.166992      2✓    0.166667
  |1100⟩    0.164917      2✓    0.166667

Total weight on Hamming-weight-2 subspace: 1.000000 (expected: 1.0)

Thermal state preparation circuit — example.

Source: examples/2_advanced/circuits/thermal_state.py
Status: pass

Demonstrates the thermal_state_circuit building block for preparing thermal (Gibbs) states of H = Σ Z_i at various inverse temperatures β.

Usage: python thermal_state.py [–n-qubits N] [–beta BETA] [–shots N]

Source code

#!/usr/bin/env python
"""Thermal state preparation circuit — example.

Demonstrates the thermal_state_circuit building block for preparing
thermal (Gibbs) states of H = Σ Z_i at various inverse temperatures β.

Usage:
    python thermal_state.py [--n-qubits N] [--beta BETA] [--shots N]

[doc-require: ]
[doc-warning-ignore: DeprecationWarning]
"""

import argparse
import sys
import math
import numpy as np

# Add parent directory to path so we can import uniqc when running as a script
sys.path.insert(0, __file__.rsplit("/", 2)[0])

from uniqc import Circuit
from uniqc.simulator import Simulator
from uniqc import thermal_state_circuit


def run_thermal(n_qubits, beta, shots):
    """Run thermal state preparation and print probability distribution."""
    c = Circuit(n_qubits)
    thermal_state_circuit(c, beta=beta)
    c.measure(list(range(n_qubits)))

    sim = Simulator()
    raw = sim.simulate_shots(c.qasm, shots=shots)
    result = {f"{int(k):0{n_qubits}b}": v for k, v in raw.items()}

    # Aggregate counts into probability distribution
    total = sum(result.values())
    probs = {state: count / total for state, count in sorted(result.items())}

    # Theoretical distribution
    exp_b = math.exp(beta)
    exp_nb = math.exp(-beta)
    p0 = exp_b / (exp_b + exp_nb)
    p1 = 1 - p0

    print(f"Thermal State Preparation — {n_qubits} qubits, β = {beta}")
    print(f"Single-qubit probabilities: p₀ = {p0:.6f}, p₁ = {p1:.6f}")
    print(f"\nMeasured probability distribution (shots={shots}):")
    print(f"  {'State':<12s} {'Measured':>10s} {'Theory':>10s}")
    print(f"  {'-'*12} {'-'*10} {'-'*10}")

    for state, prob in probs.items():
        # Compute theoretical probability for this basis state
        n_ones = bin(int(state, 2)).count("1") if state else 0
        n_zeros = n_qubits - n_ones
        theory = p0 ** n_zeros * p1 ** n_ones
        print(f"  |{state}{prob:10.6f} {theory:10.6f}")


def main():
    parser = argparse.ArgumentParser(description="Thermal state preparation example")
    parser.add_argument("--n-qubits", type=int, default=3, help="Number of qubits (default: 3)")
    parser.add_argument("--beta", type=float, default=1.0, help="Inverse temperature β (default: 1.0)")
    parser.add_argument("--shots", type=int, default=8192, help="Number of measurement shots (default: 8192)")
    args = parser.parse_args()

    run_thermal(args.n_qubits, args.beta, args.shots)


if __name__ == "__main__":
    main()

Stdout

Thermal State Preparation — 3 qubits, β = 1.0
Single-qubit probabilities: p₀ = 0.880797, p₁ = 0.119203

Measured probability distribution (shots=8192):
  State          Measured     Theory
  ------------ ---------- ----------
  |000⟩    0.685059   0.683325
  |001⟩    0.089355   0.092478
  |010⟩    0.090698   0.092478
  |011⟩    0.013184   0.012516
  |100⟩    0.093628   0.092478
  |101⟩    0.013428   0.012516
  |110⟩    0.012939   0.012516
  |111⟩    0.001709   0.001694