qalgora-Q Docs Hub量子文档 ✦ Ask AI✦ 问问文档

Building Quantum Kernels

A kernel is the unit of quantum computation. This page walks through every building block: defining kernels, allocating and initializing qubits, applying gates, control and adjoint modifiers, custom operations, composing kernels, and parameterization.

Defining a kernel

Decorate a Python function with @qalgora.kernel (in C++, mark it __qpu__). Allocate a single qubit with qalgora.qubit() or a register with qalgora.qvector(n); index it like a list, including q[-1] for the last.

import qalgora

@qalgora.kernel
def kernel(n: int):
    a = qalgora.qubit()          # single qubit
    reg = qalgora.qvector(n)     # register of n qubits
    first, last = reg[0], reg[-1]

Initializing states

Qubits start in |0…0⟩. Allocating a register and applying gates is the runnable way to prepare a state on the reference build:

import qalgora

@qalgora.kernel
def prepare():
    q = qalgora.qvector(2)   # starts in |00⟩
    h(q[0])
    x.ctrl(q[0], q[1])       # now a Bell state
Specification API — not implemented yet
Initializing directly from an amplitude vector (qalgora.qvector(vec), qalgora.amplitudes, or handing off a prepared State) is a specification interface; the snippet below is illustrative and is not yet runnable on the open reference build.
import numpy as np

# pass a normalized amplitude vector as a kernel argument
@qalgora.kernel
def from_vector(vec: list[complex]):
    q = qalgora.qvector(vec)

# precision-agnostic amplitudes (match the simulator's float width)
data = np.array([1, 0, 0, 1], dtype=np.complex128) / np.sqrt(2)

# amplitude preparation inside a kernel
@qalgora.kernel
def from_amplitudes():
    q = qalgora.qvector(2)
    qalgora.amplitudes(q, [0.5, 0.5, 0.5, 0.5])

# hand off a prepared state from one kernel to another
# `bell` is the predefined Bell-state kernel from the examples
state = qalgora.get_state(bell)
@qalgora.kernel
def continue_from(s: qalgora.State):
    q = qalgora.qvector(s)
Specification API — not in the open reference build yet
This example shows a qalgora-Q specification API (or a third-party library) that the open reference build does not bundle today. It documents the intended interface; to run code now, use the reference build’s supported core API.

Applying gates

The standard library currently provides single-qubit gates h, x, y, z, s, t, r1, rx, ry, rz and the two-qubit swap; u3 is a specification interface that can be decomposed into rotation gates. Apply a gate to one qubit or broadcast across a whole register.

@qalgora.kernel
def gates():
    q = qalgora.qvector(3)
    h(q)                 # broadcast Hadamard to every qubit
    x(q[0])              # single qubit
    rx(0.5, q[1])        # parameterized rotation
    # u3(0.1, 0.2, 0.3, q[2])   # specification interface — decompose into rz/ry/rz
    swap(q[0], q[2])

Controlled operations

Any gate takes a .ctrl modifier. One control gives a standard controlled gate (e.g. CNOT from x.ctrl); multiple controls give a multi-controlled gate. Pass the controls as an explicit list [q[0], q[1]] to stay runnable. A qview slice such as q[0:k] denotes the same set of control qubits, but that form depends on slice support in the reference build (see the note below) — prefer the explicit list.

@qalgora.kernel
def controls():
    q = qalgora.qvector(3)
    x.ctrl(q[0], q[1])              # CNOT
    x.ctrl([q[0], q[1]], q[2])     # Toffoli — controls as an explicit list
    rz.ctrl(0.5, q[0], q[1])       # controlled rotation

Adjoint operations

Append .adj to invert a single gate, or qalgora.adjoint to invert a whole sub-kernel — the basis of compute–uncompute patterns.

@qalgora.kernel
def prep(q: qalgora.qview):
    h(q[0]); x.ctrl(q[0], q[1])

@qalgora.kernel
def compute_uncompute():
    q = qalgora.qvector(2)
    prep(q)
    t.adj(q[0])                # inverse of a single gate
    qalgora.adjoint(prep, q)   # inverse of the whole kernel (uncompute)

Custom operations

Specification API — not implemented yet
register_operation and custom-gate registration are a specification interface; the open reference build does not register custom unitaries yet, so the snippet below is illustrative.

Register your own unitary from its matrix (given as a flat row-major array), then use it like any built-in gate — including a .ctrl form.

import numpy as np
qalgora.register_operation("custom_x", np.array([0, 1, 1, 0]))   # row-major 2x2

@qalgora.kernel
def use_custom():
    q = qalgora.qvector(2)
    custom_x(q[0])
    custom_x.ctrl(q[0], q[1])
Specification API — not in the open reference build yet
This example shows a qalgora-Q specification API (or a third-party library) that the open reference build does not bundle today. It documents the intended interface; to run code now, use the reference build’s supported core API.

The .ctrl and .adj modifiers currently apply to the built-in gates supported by the reference build; .ctrl/.adj on custom gates is supported in the specification, but is unavailable in the reference build until custom-gate registration is built in.

Building kernels with kernels

Kernels compose: pass qubits as a qalgora.qview (a non-owning reference) and call one kernel from another to build modular circuits.

qview slices
Passing a register slice such as q[0:k] as a qview into a sub-kernel depends on slice support in the reference build; if slicing is unavailable, pass the whole register or an explicit list of qubits.
@qalgora.kernel
def entangle(q0: qalgora.qubit, q1: qalgora.qubit):
    x.ctrl(q0, q1)

@qalgora.kernel
def chain():
    reg = qalgora.qvector(10)
    h(reg[0])
    for i in range(9):
        entangle(reg[i], reg[i + 1])

Parameterized kernels

Accept a list of classical parameters to drive rotation angles — the foundation of every variational algorithm.

@qalgora.kernel
def ansatz(thetas: list[float]):
    q = qalgora.qvector(2)
    ry(thetas[0], q[0])
    ry(thetas[1], q[1])
    x.ctrl(q[0], q[1])
Restrictions
Kernel arguments must be typed; only quantum intrinsics and a restricted classical subset are allowed inside a kernel. Keep classical pre/post-processing in ordinary Python around the kernel.

构建量子内核

内核是量子计算的基本单元。本页逐一讲解各个构建模块:定义内核、分配并初始化量子比特、施加门、加受控与伴随修饰符、自定义操作、内核之间的组合,以及内核参数化。

定义内核

使用 @qalgora.kernel 装饰 Python 函数(C++ 中标记为 __qpu__)。 用 qalgora.qubit() 分配单个量子比特,用 qalgora.qvector(n) 分配含 n 个量子比特的寄存器;寄存器像列表一样索引,也能用 q[-1] 取最后一个。

import qalgora

@qalgora.kernel
def kernel(n: int):
    a = qalgora.qubit()          # single qubit
    reg = qalgora.qvector(n)     # register of n qubits
    first, last = reg[0], reg[-1]

初始化量子态

量子比特初始处于 |0…0⟩ 态。在参考实现上,分配寄存器并施加门是可运行的初态制备方式:

import qalgora

@qalgora.kernel
def prepare():
    q = qalgora.qvector(2)   # 初始为 |00⟩
    h(q[0])
    x.ctrl(q[0], q[1])       # 现在是 Bell 态
规范接口 · 暂未实现
直接以振幅向量初始化(qalgora.qvector(vec)qalgora.amplitudes 或传入已制备的 State)属规范接口;下面的片段仅作示意,开放参考实现暂未支持运行。
import numpy as np

# 以归一化振幅向量作为内核参数传入
@qalgora.kernel
def from_vector(vec: list[complex]):
    q = qalgora.qvector(vec)

# 与精度无关的振幅(匹配模拟器的浮点宽度)
data = np.array([1, 0, 0, 1], dtype=np.complex128) / np.sqrt(2)

# 在内核内部进行振幅制备
@qalgora.kernel
def from_amplitudes():
    q = qalgora.qvector(2)
    qalgora.amplitudes(q, [0.5, 0.5, 0.5, 0.5])

# 把已制备的态从一个内核交给另一个内核
# bell 是示例中预定义的 Bell 态内核
state = qalgora.get_state(bell)
@qalgora.kernel
def continue_from(s: qalgora.State):
    q = qalgora.qvector(s)
规范接口 · 参考实现暂未包含
此示例展示的是 qalgora-Q 规范中的接口(或第三方库),开放参考实现目前尚未内置,仅用于说明预期用法;如需立即运行,请使用参考实现已支持的核心 API。

施加门

标准库当前提供单比特门 h, x, y, z, s, t, r1, rx, ry, rz 和双比特门 swapu3 属规范接口,可用旋转门分解。门既可作用在单个量子比特上,也可广播到整个寄存器。

@qalgora.kernel
def gates():
    q = qalgora.qvector(3)
    h(q)                 # 把 Hadamard 广播到每个量子比特
    x(q[0])              # 单个量子比特
    rx(0.5, q[1])        # 带参数的旋转
    # u3(0.1, 0.2, 0.3, q[2])   # 规范接口——可分解为 rz/ry/rz
    swap(q[0], q[2])

受控操作

任意门都能加 .ctrl 修饰符。一个控制比特得到标准受控门 (如 x.ctrl 就是 CNOT),多个控制比特则得到多控门。控制比特请写成显式列表 [q[0], q[1]]以保证可运行。qview 切片(如 q[0:k])表示同一组控制比特, 但该写法取决于参考实现的切片支持(见下方提示)——优先使用显式列表。

@qalgora.kernel
def controls():
    q = qalgora.qvector(3)
    x.ctrl(q[0], q[1])              # CNOT
    x.ctrl([q[0], q[1]], q[2])     # Toffoli——控制位用显式列表
    rz.ctrl(0.5, q[0], q[1])       # 受控旋转

伴随操作

在单个门后加 .adj 取它的逆,或用 qalgora.adjoint 对整个子内核取逆——这是计算-反计算(uncompute)模式的基础。

@qalgora.kernel
def prep(q: qalgora.qview):
    h(q[0]); x.ctrl(q[0], q[1])

@qalgora.kernel
def compute_uncompute():
    q = qalgora.qvector(2)
    prep(q)
    t.adj(q[0])                # inverse of a single gate
    qalgora.adjoint(prep, q)   # inverse of the whole kernel (uncompute)

自定义操作

规范接口 · 暂未实现
register_operation 与自定义门注册属规范接口;开放参考实现尚未内置自定义酉矩阵注册,因此下面的片段仅作示意。

用一个按行优先展开的矩阵数组注册自定义幺正算符,注册后就能像内建门那样使用,也包括 .ctrl 形式。

import numpy as np
qalgora.register_operation("custom_x", np.array([0, 1, 1, 0]))   # row-major 2x2

@qalgora.kernel
def use_custom():
    q = qalgora.qvector(2)
    custom_x(q[0])
    custom_x.ctrl(q[0], q[1])
规范接口 · 参考实现暂未包含
此示例展示的是 qalgora-Q 规范中的接口(或第三方库),开放参考实现目前尚未内置,仅用于说明预期用法;如需立即运行,请使用参考实现已支持的核心 API。

.ctrl.adj 修饰符当前适用于参考实现支持的内建门;自定义门的 .ctrl/.adj 在规范上支持,但参考实现若未内置自定义门注册则暂不可用。

以内核构建内核

内核之间可以组合:把量子比特以 qalgora.qview(非拥有引用)的形式传入,在一个内核里调用另一个内核,搭出模块化的电路。

qview 切片
把寄存器切片(如 q[0:k])以 qview 传入子内核,取决于参考实现的切片支持;若不支持切片,请传入整个寄存器或显式的量子比特列表。
@qalgora.kernel
def entangle(q0: qalgora.qubit, q1: qalgora.qubit):
    x.ctrl(q0, q1)

@qalgora.kernel
def chain():
    reg = qalgora.qvector(10)
    h(reg[0])
    for i in range(9):
        entangle(reg[i], reg[i + 1])

带参数的内核

内核可以接受一组经典参数来驱动旋转角度——这是所有变分算法的基础。

@qalgora.kernel
def ansatz(thetas: list[float]):
    q = qalgora.qvector(2)
    ry(thetas[0], q[0])
    ry(thetas[1], q[1])
    x.ctrl(q[0], q[1])
限制
内核参数必须带类型注解;内核内部只能用量子内建指令和受限的经典语法子集。经典的前后处理逻辑请放在内核外的普通 Python 代码里。