薛定谔化方法
概述
unitarylab_algorithms.schrodingerization 包实现了通过薛定谔化(Schrödingerization)技术将偏微分方程(PDE)求解转化为量子模拟的算法——将非厄米(非酉)动力学嵌入到满足薛定谔方程的更大量子系统中,从而在量子计算机上进行酉模拟。
核心思想:将经典偏微分方程 ( 不一定是反厄米算符)通过坐标变换嵌入到等价薛定谔方程所描述的量子系统中。
| 方程 | 模块 | 算法类 | 描述 |
|---|---|---|---|
| 一维对流方程 | equation_advection | AdvectionEquationAlgorithm | 线性输运方程 |
| 一维热方程 | equation_heat | HeatEquationAlgorithm | 扩散方程 |
| 二维热方程 | equation_heat2d | Heat2dEquationAlgorithm | 二维热扩散 |
本模块使用独立的 PDE 算法接口和 setup.json 配置。返回值中的 circuit 是线路图信息列表,plot 是解的可视化信息。对流方程支持 classical、trotter;热方程的 block 选项当前按经典方法计算。各方法支持的参数和输出结构见对应小节。
基类:unitarylab_algorithms.schrodingerization.base
所有薛定谔化算法均继承自 unitarylab_algorithms.schrodingerization.base.BaseAlgorithm。
抽象接口
class BaseAlgorithm(ABC):
def __init__(self):
self.color = "#DBB924"
self.algo_dir = None
self.logger = None
@abstractmethod
def run(self, params: str) -> Dict[str, Any]:
"""执行算法逻辑。params 为 JSON 字符串格式。"""
...
def parse_params(self, params) -> Any:
"""解析参数:优先按 json.loads 解析,失败则回退到 ast.literal_eval,
兼容 JSON 字符串、Python 字面量字符串和已解析的 dict/list。"""
...抽象基类声明的
run(self, params: str)签名只是一个占位声明——Python 不检查子类重写方法的签名兼容性。三个具体子类实际实现(且被__main__与外部调用方实际使用)的签名是:def run(self, params=None, algo_dir: str = None, backend='torch', device='cpu', dtype=np.complex128) -> Dict[str, Any]:
params=None时会自动从该算法模块目录下的setup.json加载默认参数;传入 dict/list 会直接使用;传入 JSON 字符串会被parse_equation内部解析(先json.loads,若结果含"params"键则取["params"])。
日志工具
create_algorithm_logger 函数为每个算法创建独立的滚动文件日志记录器,写入 algo_dir/algorithm.log(及单独的 algorithm_error.log):
from unitarylab_algorithms.schrodingerization.base import create_algorithm_logger
logger = create_algorithm_logger(__file__)
logger.info("算法开始执行")参数:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
algorithm_file | str | — | 通常传入算法模块的 __file__;用于确定默认日志目录 |
log_name | str | None | None | 日志记录器名称(默认使用算法文件夹名) |
log_dir | str | None | None | 日志目录(默认使用算法文件所在目录) |
console_output | bool | True | 是否同时输出到控制台 |
max_bytes | int | 50 * 1024 * 1024(50 MB) | 单个日志文件最大字节数 |
backup_count | int | 5 | 保留的备份日志文件数量 |
force_reconfigure | bool | False | 强制重新初始化(热重载时使用) |
该函数会检测沙箱环境(同时存在
TASK_ID与ALGO_PARAMS环境变量时判定为沙箱),此时即使console_output=True也会跳过控制台StreamHandler,仅写入文件,以避免宿主进程重复采集日志。
绘图辅助方法
BaseAlgorithm 还提供了 set_plt(color='white')(统一设置 matplotlib 文字/坐标轴配色)、_generate_solution_plot_1d(...)(一维解曲线图)、_generate_circuit_plots(name, qc, H1=None, H2=None, format='svg')(生成量子电路图,qc 对应的完整电路图始终生成,H1/H2 非 None 时各追加一张分解电路图,因此返回列表长度在 1~3 之间)等受保护的辅助方法,供子类在 _solve_* 方法内部调用。其中 _generate_solution_plot_1d 并非每个子类都会经由自身的 _generate_solution_plot 包装调用——一维对流方程与一维热方程直接继承基类的 _generate_solution_plot(内部调用 _generate_solution_plot_1d),而二维热方程则完全覆盖了 _generate_solution_plot,改用独立实现的 3D 曲面绘图(ax.plot_surface(...)),从不调用 _generate_solution_plot_1d,详见下文各算法小节。
一维对流方程
背景
线性对流方程描述了标量场 以常速度 的输运过程:
薛定谔化方法将 编码为量子态,并在等价薛定谔方程 (,)下演化,从而实现对该非酉经典偏微分方程的量子酉模拟。
导入
from unitarylab_algorithms import AdvectionEquationAlgorithm.run() 参数
def run(self, params=None, algo_dir: str = None,
backend='torch', device='cpu', dtype=np.complex128) -> Dict[str, Any]| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
params | None | str | dict | list | None | None 时自动加载模块内 setup.json;字符串既可以是 JSON 内容,也可以是指向 JSON 文件的路径(AdvectionEquationAlgorithm 独有的文件路径分支);也可直接传入已解析的 dict/list |
algo_dir | str | None | None | 结果与日志输出目录;为 None 时自动创建 ./results/schrodingerization/equation_advection/ |
backend | str | 'torch' | 仅在 method='trotter' 时生效,完整转发给底层 schro_trotter |
device | str | 'cpu' | 同上 |
dtype | numpy dtype | np.complex128 | 同上 |
setup.json 中默认方程配置(equation_advection 块)的关键固定参数:
| 参数 | 默认值 | 取值范围 | 说明 |
|---|---|---|---|
a | 0.1 | [-100, 100] | 对流速度;符号决定迎风格式(upwind)的方向 |
L | 16 | (0, 100] | 计算域长度,区间为 |
T | 1 | (0, 100] | 终止时间 |
nx | 4 | [1, 10] | 空间量子比特数 |
求解方法配置(solutionMethod_classical 块):
| 参数 | 默认值 | 说明 |
|---|---|---|
na | 8 | 辅助量子比特数,控制薛定谔化参数 的离散精度 |
R | 4 | 的截断区间为 |
p(point) | 1 | 薛定谔化后在该点恢复原方程的解 |
边界条件默认使用 boundaryCondition_periodic(周期边界),初值默认使用 initialCondition_discontinuous(阶跃初值: 处为 0,其余为 1);离散格式默认 discreteFormat_upwind(迎风格式,scheme='upwind' 时 _solve_classical 会依据 a 的符号自动切换为 'forward'/'backward')。
返回值
_solve_classical / _solve_trotter 均返回:
{
"status": "ok",
"message": "Advection equation solved",
"grid": {"n_points": 2**nx, "dx": dx}, # trotter 分支额外含 "dt", "nt"
"x": [...], # 空间网格坐标(list)
"u": [...], # 终止时刻的解(list)
"circuit": [{"format": "svg", "filename": "..."}], # 始终只有 1 张完整电路图,两个 `_solve_*` 分支均未向 `_generate_circuit_plots` 传入 H1/H2
"plot": {"format": "svg", "filename": "..."}, # 解的可视化图(单个 dict)
}示例
from unitarylab_algorithms import AdvectionEquationAlgorithm
algo = AdvectionEquationAlgorithm()
result = algo.run() # params=None,使用 setup.json 默认参数(classical 方法)
print(result["status"], result["message"])
print("电路图数量:", len(result["circuit"]))自定义参数(以 dict 形式传入,直接对应 setup.json 的 params 数组结构)时,请参照 setup.json 的完整 schema 构造 equation 与 solutionMethod_* 两个块;也可以先 json.load 读取默认 setup.json,修改其中的 par_fix/value 字段后再传入。
一维热方程
背景
一维热方程描述标量场的扩散过程:
其中 是热扩散系数,要求 。算符 是负半定的非哈密顿量类型,需要通过薛定谔化嵌入(,)才能进行酉模拟。
导入
from unitarylab_algorithms import HeatEquationAlgorithm.run() 参数
def run(self, params=None, algo_dir: str = None,
backend='torch', device='cpu', dtype=np.complex128) -> Dict[str, Any]参数含义与对流方程一致,但不支持文件路径形式的 params 字符串,仅接受 None、已解析对象或可直接解析的配置字符串。当前版本的 Trotter 路径使用默认执行后端配置。
setup.json 中默认方程配置(equation_heat 块):
| 参数 | 默认值 | 取值范围 | 说明 |
|---|---|---|---|
a | 1 | (0, 100] | 扩散系数,要求 a > 0 |
L | 17 | (0, 100] | 计算域长度 |
T | 1 | (0, 100] | 终止时间 |
nx | 5 | [1, 10] | 空间量子比特数 |
f(x)(源项) | "a+x" | — | 由 sympy 解析,可用变量 x 及常量 a、L |
边界条件默认 boundaryCondition_dirichlet(),初值默认 initialCondition_custom(需通过 par_func 提供自定义 )。
method='block'目前等价于method='classical':_solve_block(self, eq)的完整实现是:def _solve_block(self, eq): self.logger.info('Block encoding will be supported soon! Now falling back to classical method!') return self._solve_classical(eq)而
setup.json的method_list中列出了"solutionMethod_block",容易让人误以为块编码方法已经实现。选择该方法实际得到的是经典矩阵指数方法的结果,请勿用其性能或电路结构代表真正的块编码算法。
返回值
字段形状与对流方程一致(见上),message 字段为 "Heat equation solved",但 circuit 列表的长度取决于求解方法:method='classical' 时只生成 1 张完整线路图;method='trotter' 时会把非空的 H1、H2 一并传给 _generate_circuit_plots(...),因此生成 3 张线路图(完整线路、H1、H2);method='block' 当前回退到 classical,所以也是 1 张。
示例
from unitarylab_algorithms import HeatEquationAlgorithm
algo = HeatEquationAlgorithm()
result = algo.run() # 默认 classical 方法
print(result["status"], result["grid"])二维热方程
背景
二维热方程将标量扩散推广到两个空间维度:
量子模拟需要 个空间量子比特(、 方向各 个),薛定谔化嵌入方式与一维情形类似(,)。
导入
from unitarylab_algorithms import Heat2dEquationAlgorithm注意类名大小写为
Heat2d(非Heat2D),__init__.py中from .algorithm import Heat2dEquationAlgorithm与包级ALGORITHM_NAME = "heat2d"均沿用此拼写。
.run() 参数
def run(self, params=None, algo_dir: str = None,
backend='torch', device='cpu', dtype=np.complex128) -> Dict[str, Any]同样不支持文件路径形式的 params。method='trotter' 时可通过 device 选择执行设备,后端与数值精度使用默认配置。
setup.json 中默认方程配置(equation_heat2d 块):
| 参数 | 默认值 | 取值范围 | 说明 |
|---|---|---|---|
a1 | 1 | (0, 100] | 方向扩散系数 |
a2 | 1 | (0, 100] | 方向扩散系数 |
L | 17 | (0, 100] | 计算域长度(、 共用) |
T | 1 | (0, 100] | 终止时间 |
nx | 4 | [1, 10] | 每个方向的空间量子比特数(总空间比特数为 2*nx) |
边界条件默认 boundaryCondition_dirichlet,初值默认 initialCondition_custom,默认 。method_list 仅列出 ["solutionMethod_classical", "solutionMethod_trotter"](不含 block)。
尽管
setup.json未声明block方法,Heat2dEquationAlgorithm.run()的代码依然会对method == 'block'分派到_solve_block(self, eq),其实现与一维热方程完全相同——记录"Block encoding will be supported soon!..."后直接调用_solve_classical(eq)。因此通过自定义params(而非默认setup.json)显式指定"solutionMethod_block"时,同样只会得到经典方法的结果。
返回值
{
"status": "ok",
"message": "2D Heat equation solved",
"grid": {"n_points": 2**nx, "dx": dx}, # trotter 分支额外含 "dt", "nt"
"x": [...],
"y": [...], # 二维热方程独有:额外的 y 方向网格坐标
"u": [[...], ...], # 形状为 (2**nx, 2**nx) 的二维解,按 list of list 序列化
"circuit": [{"format": "svg", "filename": "..."}, ...],
"plot": {"format": "svg", "filename": "..."}, # 3D 曲面图(plot_surface),非一维折线图
}示例
from unitarylab_algorithms import Heat2dEquationAlgorithm
algo = Heat2dEquationAlgorithm()
result = algo.run()
print(result["status"], "grid:", result["grid"])
print("y 方向网格点数:", len(result["y"]))通用注意事项
- 三个算法均没有使用
unitarylab_algorithms.algo_base.BaseAlgorithm,因此不具备_build_return_dict()、self.output、self.status等其他包共有的机制;不要假设返回字典的字段与其他章节一致。 params=None时会自动加载算法自身目录下的setup.json求解一次默认算例,这也是每个algorithm.py文件末尾if __name__ == "__main__": result = XxxAlgorithm().run()的行为。method由setup.json(或传入参数)中solver块的type字段决定(对应solutionMethod_classical/solutionMethod_trotter/solutionMethod_block等type值去除前缀后的部分,如'classical'/'trotter'/'block');三个算法支持的取值不完全相同,详见各自小节。_solve_block目前在equation_heat与equation_heat2d中均是”回退到经典方法”的占位实现,equation_advection则根本不接受'block';三者均没有真正的块编码(block-encoding)电路实现。- 在处理外部输入前,可使用
algo.parse_params(params)安全反序列化参数(先尝试json.loads,失败则回退ast.literal_eval)。 - 这些算法对于细密空间网格计算量较大(矩阵维度随
2**nx增长,二维情形为2**(2*nx))。验证环境配置时,建议从较小的nx(如 4–6)开始,再逐步扩大规模。 - 每个算法内部使用
create_algorithm_logger(algo_dir)配置日志记录,日志文件写入algo_dir/algorithm.log(及algorithm_error.log),沙箱环境下会自动跳过控制台输出以避免日志重复。