Skip to content

自定义量子门(Custom Quantum Gates)

使用 pyqpanda3 从酉矩阵创建自定义量子门、构建 Oracle 以及组合多控操作。


问题

pyqpanda3 内置了 37+ 种标准门——包括 Pauli 门、旋转门、CNOT、SWAP、TOFFOLI 等。然而,一些重要场景需要标准门集之外的门:

  1. 问题特定酉操作(Problem-Specific Unitaries)。 算法可能需要一个没有标准名称的酉操作,例如用于量子行走的自定义硬币算子(Coin Operator)或用于 QAOA 变体的结构化混合算子(Mixer Operator)。

  2. Oracle 构造(Oracle Construction)。 Grover 搜索、Deutsch-Jozsa 和其他基于 Oracle 的算法需要从经典函数的真值表导出的相位翻转(Phase Flip)或比特翻转(Bit Flip) Oracle。

  3. 非标准门集(Non-Standard Gate Sets)。 编译到具有有限原生门集的特定硬件时,可能需要定义自定义分解构建块。

  4. 子程序复用(Subroutine Re-Use)。 你可能希望将常用门序列打包为单个对象,以便求逆(.dagger())、受控(.control())或嵌入多个程序。

在所有这些情况下,你需要从酉矩阵定义门或从现有原语组合门的能力。


方案

pyqpanda3 提供两种创建自定义门的主要机制,以及用于从简单部分构建复杂操作的组合工具:

步骤 1:定义酉矩阵

每个量子门由满足 UU=I 的酉矩阵 U 描述。对于 n 量子比特门,矩阵维度为 2n×2n。使用 numpy 构造复值数组。

步骤 2:创建门

使用 core.Oracle(qubits, matrix) 从任意酉矩阵实例化门。该函数验证矩阵是否为酉矩阵以及其维度是否与目标量子比特数匹配。

对于具有标准参数的命名门,使用 core.create_gate(name, qubits, params)

步骤 3:组合和控制

应用 .control(qubit) 添加控制量子比特,.dagger() 获取逆操作,并使用 << 运算符将结果嵌入 QCircuitQProg

步骤 4:验证和执行

使用 .matrix() 获取门的矩阵表示并验证正确性。然后在 CPUQVM 或其他模拟器后端上执行。


代码

示例 1:从 2x2 酉矩阵创建单量子比特门

创建一个绕 X-Z 平面中某轴的自定义单量子比特旋转。该门应用旋转

Rn^(θ)=eiθn^σ/2

其中 n^=(sinα,0,cosα) 是 X-Z 平面中的单位向量。

python
import numpy as np
from pyqpanda3 import core

# Define a custom rotation axis and angle
alpha = np.pi / 6   # 30 degrees from Z toward X
theta = np.pi / 3   # rotation angle

# Build the 2x2 unitary matrix
# R_{hat_n}(theta) = cos(theta/2)*I - i*sin(theta/2)*(sin(alpha)*X + cos(alpha)*Z)
cos_half = np.cos(theta / 2)
sin_half = np.sin(theta / 2)

custom_matrix = np.array([
    [cos_half - 1j * sin_half * np.cos(alpha),
     -1j * sin_half * np.sin(alpha)],
    [-1j * sin_half * np.sin(alpha),
     cos_half + 1j * sin_half * np.cos(alpha)]
], dtype=complex)

# Create the custom gate on qubit 0
qubits = [0]
custom_gate = core.Oracle(qubits, custom_matrix)

# Verify unitarity
mat = custom_gate.matrix()
product = mat @ mat.conj().T
is_unitary = np.allclose(product, np.eye(2))
print(f"Gate is unitary: {is_unitary}")  # True

# Use in a circuit
prog = core.QProg()
prog << custom_gate
prog << core.measure([0], [0])

# Execute
machine = core.CPUQVM()
machine.run(prog, 1000)
print(f"Results: {machine.result().get_counts()}")

示例 2:从 4x4 酉矩阵创建双量子比特门

实现平方根 SWAP 门(Square-Root-of-SWAP Gate),这是量子计算中的标准门,但不总是作为原语可用:

SWAP=(100001+i21i2001i21+i200001)
python
import numpy as np
from pyqpanda3 import core

# Define the sqrt(SWAP) matrix
a = (1 + 1j) / 2   # (1+i)/2
b = (1 - 1j) / 2   # (1-i)/2

sqrt_swap_matrix = np.array([
    [1, 0, 0, 0],
    [0, a, b, 0],
    [0, b, a, 0],
    [0, 0, 0, 1]
], dtype=complex)

# Create the gate acting on qubits 1 and 2
sqrt_swap_gate = core.Oracle([1, 2], sqrt_swap_matrix)

# Verify: applying it twice should give a full SWAP
mat = sqrt_swap_gate.matrix()
double_mat = mat @ mat
swap_matrix = np.array([
    [1, 0, 0, 0],
    [0, 0, 1, 0],
    [0, 1, 0, 0],
    [0, 0, 0, 1]
], dtype=complex)
print(f"sqrt(SWAP)^2 == SWAP: {np.allclose(double_mat, swap_matrix)}")  # True

# Use in a program
prog = core.QProg()
prog << core.X(1)              # prepare |10>
prog << sqrt_swap_gate         # apply sqrt(SWAP)
prog << core.measure([1, 2], [0, 1])

machine = core.CPUQVM()
machine.run(prog, 1000)
print(f"Results: {machine.result().get_counts()}")

示例 3:使用 .control() 构建多控门

通过对 Z 门链式调用 .control() 来构建多控 Z 门(CCZ)。CCZ 门仅当所有控制量子比特为 |1 时才施加相位翻转:

CCZ|x0,x1,x2=(1)x0x1x2|x0,x1,x2
python
import numpy as np
from pyqpanda3 import core

# Method 1: Chain .control() calls
z_gate = core.Z(2)          # Z on target qubit 2
cz_gate = z_gate.control(1)  # add control qubit 1
ccz_gate = cz_gate.control(0)  # add second control qubit 0

# Verify the 8x8 matrix
mat = ccz_gate.matrix()
# CCZ should have -1 at position [7,7] (all qubits |111>)
# and +1 on all other diagonal entries
expected = np.eye(8, dtype=complex)
expected[7, 7] = -1
print(f"CCZ matrix correct: {np.allclose(mat, expected)}")  # True

# Method 2: Use the vector form of control()
ccz_gate2 = core.Z(2).control([0, 1])

# Use in a program: prepare |111> and apply CCZ
prog = core.QProg()
prog << core.X(0) << core.X(1) << core.X(2)  # |111>
prog << ccz_gate
prog << core.measure([0, 1, 2], [0, 1, 2])

machine = core.CPUQVM()
machine.run(prog, 1000)
print(f"Results: {machine.result().get_counts()}")
# Always measures 111 (CCZ only changes phase, not computational basis)

示例 4:为 Grover 算法构建自定义 Oracle

构建一个相位 Oracle(Phase Oracle),通过翻转特定计算基态的相位来标记它。这是 Grover 搜索中的核心子程序。

python
import numpy as np
from pyqpanda3 import core

def phase_oracle(n_qubits: int, target_state: int) -> core.QGate:
    """Create a phase oracle that marks |target_state> with a -1 phase.

    Args:
        n_qubits: Number of qubits in the search space.
        target_state: Integer index of the state to mark (0 to 2^n - 1).

    Returns:
        A QGate implementing the phase oracle.
    """
    dim = 2 ** n_qubits
    matrix = np.eye(dim, dtype=complex)
    matrix[target_state, target_state] = -1
    qubits = list(range(n_qubits))
    return core.Oracle(qubits, matrix)


def grover_diffusion(n_qubits: int) -> core.QCircuit:
    """Build the Grover diffusion operator (2|s><s| - I).

    This amplifies the amplitude of the marked state.
    """
    dim = 2 ** n_qubits
    # |s> = uniform superposition, so |s><s| = (1/dim) * ones matrix
    matrix = (2.0 / dim) * np.ones((dim, dim), dtype=complex) - np.eye(dim, dtype=complex)
    qubits = list(range(n_qubits))

    circ = core.QCircuit()
    oracle_as_diffusion = core.Oracle(qubits, matrix)
    circ << oracle_as_diffusion
    return circ


# --- Run Grover's search for |101> (state 5) on 3 qubits ---
n = 3
target = 5  # binary 101

# Build the oracle and diffusion operator
oracle = phase_oracle(n, target)
diffusion = grover_diffusion(n)

# Number of Grover iterations (optimal for unstructured search)
iterations = int(np.round(np.pi / 4 * np.sqrt(2 ** n)))
print(f"Grover iterations: {iterations}")

# Construct the full program
prog = core.QProg()

# Step 1: Initialize uniform superposition
for q in range(n):
    prog << core.H(q)

# Step 2: Apply Grover iterations
for _ in range(iterations):
    prog << oracle
    prog << diffusion

# Step 3: Measure
prog << core.measure(list(range(n)), list(range(n)))

# Execute
machine = core.CPUQVM()
machine.run(prog, 1000)
counts = machine.result().get_counts()
print(f"Grover search results: {counts}")
# Should heavily favor the target state 101 (5)

单次 Grover 迭代的电路结构如下:

示例 5:使用 .dagger() 获取逆门

.dagger() 方法返回门的埃尔米特共轭(Hermitian Conjugate/Adjoint),即酉操作的逆。这对逆计算(Uncomputation)模式至关重要。

python
import numpy as np
from pyqpanda3 import core

# Create a custom gate
theta = 1.234
custom_matrix = np.array([
    [np.cos(theta / 2), -1j * np.sin(theta / 2)],
    [-1j * np.sin(theta / 2), np.cos(theta / 2)]
], dtype=complex)

gate = core.Oracle([0], custom_matrix)
gate_inv = gate.dagger()

# Verify that gate * dagger == identity
mat = gate.matrix()
mat_inv = gate_inv.matrix()
product = mat @ mat_inv
print(f"gate * dagger == I: {np.allclose(product, np.eye(2))}")  # True

# --- Uncomputation pattern ---
# Use an auxiliary qubit to compute XOR, then uncompute
prog = core.QProg()
prog << core.H(0)                       # superposition on qubit 0
prog << core.X(1)                       # qubit 1 = |1>

# Compute: XOR of qubits 0 and 1 onto auxiliary qubit 2
compute = core.QCircuit()
compute << core.CNOT(0, 2) << core.CNOT(1, 2)
prog << compute

# Use the auxiliary qubit (apply a phase based on it)
prog << core.Z(2)

# Uncompute: restore auxiliary qubit to |0>
prog << compute.dagger()

prog << core.measure([0, 1, 2], [0, 1, 2])

machine = core.CPUQVM()
machine.run(prog, 1000)
counts = machine.result().get_counts()
print(f"Results: {counts}")
# Qubit 2 (auxiliary) should always measure 0

示例 6:验证门的酉性

在使用自定义矩阵创建 Oracle 之前,验证其满足酉性条件 UU=I

python
import numpy as np
from pyqpanda3 import core


def is_unitary(matrix: np.ndarray, atol: float = 1e-10) -> bool:
    """Check whether a matrix is unitary within tolerance.

    A matrix U is unitary if U^dagger * U = I.
    """
    n = matrix.shape[0]
    if matrix.shape != (n, n):
        return False
    product = matrix.conj().T @ matrix
    return np.allclose(product, np.eye(n), atol=atol)


def random_unitary(n: int) -> np.ndarray:
    """Generate a random n x n unitary matrix using QR decomposition."""
    # Generate a random complex matrix
    z = (np.random.randn(n, n) + 1j * np.random.randn(n, n)) / np.sqrt(2)
    # QR decomposition: Q is unitary
    q, r = np.linalg.qr(z)
    # Ensure consistent phase (diagonal of R is real-positive)
    d = np.diag(r)
    ph = d / np.abs(d)
    q = q @ np.diag(ph)
    return q


# Generate and verify a random single-qubit unitary
U1 = random_unitary(2)
print(f"Random 2x2 is unitary: {is_unitary(U1)}")  # True

# Create a gate from it
gate = core.Oracle([0], U1)
mat = gate.matrix()
print(f"Gate matrix matches input: {np.allclose(mat, U1)}")  # True

# Generate and verify a random two-qubit unitary
U2 = random_unitary(4)
print(f"Random 4x4 is unitary: {is_unitary(U2)}")  # True

gate2 = core.Oracle([0, 1], U2)
mat2 = gate2.matrix()
print(f"Gate matrix matches input: {np.allclose(mat2, U2)}")  # True

# The Oracle constructor itself validates unitarity and raises on failure
try:
    bad_matrix = np.array([[1, 0], [1, 0]], dtype=complex)
    core.Oracle([0], bad_matrix)
except (ValueError, RuntimeError) as e:
    print(f"Oracle rejected non-unitary matrix: {e}")

示例 7:从基本门构建 Toffoli 门

Toffoli 门(Toffoli Gate/CCX)是一个双重受控 X 门。虽然 pyqpanda3 直接提供 core.TOFFOLI(),但从更简单的门构建它演示了适用于任何多控操作的分解模式。

Toffoli(a,b,c)=|a|b|c(ab)
python
import numpy as np
from pyqpanda3 import core

def toffoli_decomposed(ctrl1: int, ctrl2: int, target: int) -> core.QCircuit:
    """Build a Toffoli gate from H, T, Tdg, CNOT gates.

    This uses the standard decomposition with 6 CNOT gates.
    """
    circ = core.QCircuit()
    # Step 1: H on target
    circ << core.H(target)
    # Step 2: CNOT(ctrl2, target)
    circ << core.CNOT(ctrl2, target)
    # Step 3: Tdg on target
    circ << core.T(target).dagger()
    # Step 4: CNOT(ctrl1, target)
    circ << core.CNOT(ctrl1, target)
    # Step 5: T on target
    circ << core.T(target)
    # Step 6: CNOT(ctrl2, target)
    circ << core.CNOT(ctrl2, target)
    # Step 7: Tdg on target
    circ << core.T(target).dagger()
    # Step 8: CNOT(ctrl1, target)
    circ << core.CNOT(ctrl1, target)
    # Step 9: T on ctrl2 and target
    circ << core.T(ctrl2)
    circ << core.T(target)
    # Step 10: H on target
    circ << core.H(target)
    # Step 11: CNOT(ctrl1, ctrl2)
    circ << core.CNOT(ctrl1, ctrl2)
    # Step 12: T on ctrl1, Tdg on ctrl2
    circ << core.T(ctrl1)
    circ << core.T(ctrl2).dagger()
    # Step 13: CNOT(ctrl1, ctrl2)
    circ << core.CNOT(ctrl1, ctrl2)

    return circ


# Build the decomposed Toffoli
decomposed = toffoli_decomposed(0, 1, 2)

# Compare with the native Toffoli
native_toffoli = core.TOFFOLI(0, 1, 2)

# Both should produce the same 8x8 matrix (up to global phase)
mat_decomp = decomposed.matrix()
mat_native = native_toffoli.matrix()

# Check equivalence (allow global phase difference)
phase = mat_decomp[0, 0] / mat_native[0, 0] if abs(mat_native[0, 0]) > 1e-10 else 1.0
equivalent = np.allclose(mat_decomp, phase * mat_native)
print(f"Decomposed Toffoli == native Toffoli (up to phase): {equivalent}")  # True

# Use in a program
prog = core.QProg()
prog << core.X(0) << core.X(1)  # controls = |11>
prog << decomposed              # target flips from |0> to |1>
prog << core.measure([0, 1, 2], [0, 1, 2])

machine = core.CPUQVM()
machine.run(prog, 1000)
print(f"Results: {machine.result().get_counts()}")
# Should always measure 111

分解结构:

示例 8:自定义旋转门

实现绕任意 Bloch 球轴 (nx,ny,nz) 的旋转门:

Rn^(θ)=cosθ2Iisinθ2(nxX+nyY+nzZ)
python
import numpy as np
from pyqpanda3 import core


def rotation_gate(axis: tuple, angle: float, qubit: int) -> core.QGate:
    """Create a rotation gate around an arbitrary axis.

    Args:
        axis: A unit vector (nx, ny, nz) specifying the rotation axis.
        angle: Rotation angle in radians.
        qubit: Target qubit index.

    Returns:
        A QGate implementing the rotation.
    """
    nx, ny, nz = axis
    norm = np.sqrt(nx**2 + ny**2 + nz**2)
    assert abs(norm - 1.0) < 1e-10, f"Axis must be a unit vector, got norm={norm}"

    cos_half = np.cos(angle / 2)
    sin_half = np.sin(angle / 2)

    # Pauli matrices
    I = np.eye(2, dtype=complex)
    X = np.array([[0, 1], [1, 0]], dtype=complex)
    Y = np.array([[0, -1j], [1j, 0]], dtype=complex)
    Z = np.array([[1, 0], [0, -1]], dtype=complex)

    # R_n(theta) = cos(theta/2)*I - i*sin(theta/2)*(nx*X + ny*Y + nz*Z)
    matrix = cos_half * I - 1j * sin_half * (nx * X + ny * Y + nz * Z)

    return core.Oracle([qubit], matrix)


# Rotate around axis (1/sqrt(3), 1/sqrt(3), 1/sqrt(3)) by pi/2
axis = (1/np.sqrt(3), 1/np.sqrt(3), 1/np.sqrt(3))
gate = rotation_gate(axis, np.pi / 2, 0)

# Verify: rotation by 2*pi should give -I (up to global phase)
full_rotation = rotation_gate(axis, 2 * np.pi, 0)
mat = full_rotation.matrix()
print(f"R(2pi) ≈ -I: {np.allclose(mat, -np.eye(2))}")  # True

# Use the custom rotation in a circuit
prog = core.QProg()
prog << core.H(0)                          # |+>
prog << rotation_gate(axis, np.pi / 4, 0)  # custom rotation
prog << core.measure([0], [0])

machine = core.CPUQVM()
machine.run(prog, 1000)
print(f"Results: {machine.result().get_counts()}")

# Chain with .control() to create a controlled version
controlled_rot = gate.control(1)
prog2 = core.QProg()
prog2 << core.H(1)          # control in superposition
prog2 << core.H(0)          # target in superposition
prog2 << controlled_rot     # controlled rotation
prog2 << core.measure([0, 1], [0, 1])

machine.run(prog2, 1000)
print(f"Controlled rotation results: {machine.result().get_counts()}")

示例 9:使用 create_gate() 进行命名门构造

core.create_gate() 函数通过名称、量子比特和参数构造门。这在门类型在运行时确定的动态门创建场景中很有用。

python
from pyqpanda3 import core

# Create gates by name (string matching the gate type)
h_gate = core.create_gate("H", [0], [])
rx_gate = core.create_gate("RX", [1], [1.5708])  # RX with pi/2
cnot_gate = core.create_gate("CNOT", [0, 1], [])

# Verify they match the factory-function versions
print(f"H matrix match: {len(h_gate.matrix()) == len(core.H(0).matrix())}")
print(f"Gate name: {h_gate.name()}")      # "H"
print(f"Gate name: {rx_gate.name()}")     # "RX"
print(f"Parameters: {rx_gate.parameters()}")  # [1.5708]

# Build a circuit using dynamically created gates
prog = core.QProg()
prog << h_gate
prog << cnot_gate
prog << rx_gate
prog << core.measure([0, 1], [0, 1])

machine = core.CPUQVM()
machine.run(prog, 1000)
print(f"Results: {machine.result().get_counts()}")

示例 10:完整工作流——带验证的自定义 Grover Oracle

本示例将所有内容整合在一起:定义自定义 Oracle、验证它、运行 Grover 算法并检查结果。

python
import numpy as np
from pyqpanda3 import core


def make_bitflip_oracle(n_qubits: int, marked_items: list[int]) -> core.QGate:
    """Create a bit-flip oracle that flips the target qubit for marked items.

    Unlike the phase oracle, this oracle applies X to an ancilla qubit.
    The matrix has the form diag(I_ancilla ⊗ U_f) where U_f flips for
    marked states.

    For simplicity, this returns the full (n+1)-qubit matrix as an Oracle.
    """
    total = n_qubits + 1  # n data qubits + 1 ancilla
    dim = 2 ** total
    matrix = np.eye(dim, dtype=complex)

    for item in marked_items:
        # For each marked computational-basis state, flip the ancilla
        # State |item>|0> maps to |item>|1> and vice versa
        idx0 = item * 2       # |item>|0>
        idx1 = item * 2 + 1   # |item>|1>
        matrix[idx0, idx0] = 0
        matrix[idx0, idx1] = 1
        matrix[idx1, idx0] = 1
        matrix[idx1, idx1] = 0

    qubits = list(range(total))
    return core.Oracle(qubits, matrix)


def grover_phase_oracle(n_qubits: int, marked_items: list[int]) -> core.QGate:
    """Create a phase oracle marking multiple items with a -1 phase."""
    dim = 2 ** n_qubits
    matrix = np.eye(dim, dtype=complex)
    for item in marked_items:
        matrix[item, item] = -1
    qubits = list(range(n_qubits))
    return core.Oracle(qubits, matrix)


def grover_diffusion_matrix(n_qubits: int) -> np.ndarray:
    """Build the Grover diffusion operator as a matrix."""
    dim = 2 ** n_qubits
    return np.eye(dim, dtype=complex) * (-1) + (2.0 / dim) * np.ones((dim, dim), dtype=complex)


# --- Full Grover example ---
n = 3
marked = [2, 5]  # mark states |010> and |101>

# Build oracle and diffusion
oracle = grover_phase_oracle(n, marked)
diff_matrix = grover_diffusion_matrix(n)
diffusion = core.Oracle(list(range(n)), diff_matrix)

# Calculate optimal number of iterations
theta = np.arcsin(len(marked) / 2**n)
iterations = max(1, int(np.round(np.pi / (2 * theta) - 0.5)))
print(f"Marked states: {marked}")
print(f"Theta: {theta:.4f} rad")
print(f"Optimal iterations: {iterations}")

# Build program
prog = core.QProg()

# Initialize uniform superposition
for q in range(n):
    prog << core.H(q)

# Grover iterations
for _ in range(iterations):
    prog << oracle
    prog << diffusion

# Measure
prog << core.measure(list(range(n)), list(range(n)))

# Execute
machine = core.CPUQVM()
machine.run(prog, 1000)
counts = machine.result().get_counts()

print(f"\nGrover results (marking states {marked}):")
for state, count in sorted(counts.items(), key=lambda x: -x[1]):
    print(f"  |{state}> : {count}")

解析

何时使用自定义门与内置门

场景推荐方法
标准门(H、X、RX、CNOT 等)使用内置工厂函数:core.H(0)core.RX(0, theta)
最一般的单量子比特门使用 core.U4(0, a, b, c, d) 配合四个参数
1-2 量子比特上的任意酉操作使用 core.Oracle(qubits, matrix) 配合 numpy 矩阵
运行时确定的门使用 core.create_gate(name, qubits, params)
多控标准门使用 gate.control(qubit) 链式调用
复杂子程序组合 QCircuit,然后使用 .dagger().control()

原则上,尽量使用内置门。它们在模拟器后端中经过优化,产生更干净的 OriginIR 输出。仅在无标准门匹配所需酉操作时使用 core.Oracle()

酉矩阵要求

core.Oracle() 函数强制执行两个约束:

  1. 酉性(Unitarity):矩阵 U 必须满足 UU=I。如果矩阵不是酉矩阵,构造函数会抛出异常。

  2. 维度匹配(Dimension Matching):对于 n 个目标量子比特,矩阵必须是 2n×2n。例如,2 量子比特上的门需要 4×4 矩阵。

  3. 无重复量子比特(No Duplicate Qubits):量子比特列表中的每个量子比特索引必须唯一。

要以编程方式生成有效的酉矩阵,使用随机复矩阵的 QR 分解:

python
def random_unitary(dim):
    z = (np.random.randn(dim, dim) + 1j * np.random.randn(dim, dim)) / np.sqrt(2)
    q, r = np.linalg.qr(z)
    d = np.diag(r)
    ph = d / np.abs(d)
    return q @ np.diag(ph)

或从已知分解(单量子比特门的欧拉角分解、双量子比特门的 KAK 分解)构造结构化酉操作。

大酉矩阵的分解策略

对于作用在 3 个或更多量子比特上的门,酉矩阵以 2n×2n 增长,直接指定变得不实际。改用以下策略:

  1. 解析分解(Analytical Decomposition)。 如果已知电路结构(例如 QFT),使用 QCircuit 从标准门组合,而非指定矩阵。

  2. 受控操作(Controlled Operations)。 通过在简单门上链式调用 .control() 构建多控门。例如,CCCCZ(4-受控 Z)就是 Z(target).control(c1).control(c2).control(c3).control(c4)

  3. Oracle 构造模式(Oracle Construction Patterns)。 对于相位 Oracle,构造恒等矩阵并在目标索引处翻转符号。对于比特翻转 Oracle,交换相应的行/列。

  4. 电路合成(Circuit Synthesis)。 对于 2 量子比特上的任意酉操作,KAK(Cartan)分解最多需要 3 个 CNOT 门。对于更大的酉操作,余弦-正弦分解(Cosine-Sine Decomposition, CSD)递归地分解问题。

Oracle 构造模式

量子算法中有两种常见的 Oracle 模式:

相位 Oracle(Phase Oracle)——用 1 相位标记目标态:

Of|x=(1)f(x)|x

其中标记项 f(x)=1,其他 f(x)=0。实现方式:

python
def phase_oracle(n, marked):
    dim = 2 ** n
    matrix = np.eye(dim, dtype=complex)
    for m in marked:
        matrix[m, m] = -1
    return core.Oracle(list(range(n)), matrix)

比特翻转 Oracle(Bit-Flip Oracle)——根据函数值翻转辅助量子比特:

Of|x|b=|x|bf(x)

通过交换矩阵中的行来实现对辅助量子比特与函数输出的异或操作。

性能考量

  1. 矩阵大小限制。 core.Oracle() 存储完整的 2n×2n 矩阵。对于 n>10,矩阵占用大量内存(n=10220 个复数 = 16 MB)。对于大量子比特,优先使用门级组合。

  2. 模拟器开销。 CPUQVM 模拟器通过状态向量上的直接矩阵乘法应用 Oracle 门。较大的 Oracle 矩阵导致较慢的状态演化。将大型 Oracle 分解为更小门的电路(CNOT + 单量子比特门)由于稀疏门应用可能更快。

  3. .dagger() 代价。QGate 调用 .dagger() 返回一个设置了标志的新门。矩阵在调用 .matrix() 时惰性计算。对 QCircuit 调用 .dagger() 反转门顺序并对每个门单独求逆,效率较高。

  4. .control() 代价。 添加控制量子比特将门矩阵从 2n×2n 扩展为 2n+1×2n+1。矩阵具有块结构:

Controlled-U=(I00U)

对于深度链式控制,考虑基于 Toffoli 的分解是否更高效。

  1. 矩阵检索。 .matrix() 方法按需计算矩阵表示。对于具有已知分解的门(如 HRX),这很快。对于 Oracle 门,直接返回存储的矩阵。对于电路,乘以所有组成门的矩阵,对大型电路代价较高。

API 参考摘要

API用途签名
core.Oracle()从酉矩阵创建门Oracle(qubits: list, matrix: np.ndarray) -> QGate
core.create_gate()按名称和参数创建门create_gate(name: str, qubits: list, params: list) -> QGate
gate.dagger()逆门返回新的 QGate
gate.control(qubit)添加一个控制量子比特返回新的 QGate
gate.control([q1, q2])添加多个控制量子比特返回新的 QGate
gate.matrix()获取酉矩阵matrix(expanded=False) -> np.ndarray
circuit.dagger()逆电路返回新的 QCircuit
circuit.control([qubits])受控电路返回新的 QCircuit
circuit.matrix()电路酉操作返回 np.ndarray

后续步骤:

Released under the MIT License.