你好AHS:运行你的第一个模拟哈密顿仿真 - Amazon Braket

本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。

你好AHS:运行你的第一个模拟哈密顿仿真

本节提供有关运行第一个模拟哈密顿仿真的信息。

交互式旋转链

举一个由许多相互作用的粒子组成的系统的典型示例,让我们考虑一个由八个旋转组成的环(每个旋转都可以处于 “向上” ^↑ε和 “向下” 的状态)。尽管规模很小,但该模型系统已经表现出一些自然存在的磁性材料的有趣现象。在这个例子中,我们将展示如何准备一个所谓的反铁磁阶数,即连续的自旋指向相反的方向。

连接 8 个包含向上和向下反向箭头的圆形节点的示意图。

安排

我们将使用一个中性原子来代表每次自旋,“向上” 和 “向下” 的自旋态将分别以激发的里德伯格态和原子的基态编码。首先,我们创建二维排列。我们可以用以下代码对上面的旋转圈进行编程。

先决条件:你需要 pip 安装 Bra SDK ket。(如果您使用的是 Braket 托管的笔记本实例,则该实例已预SDK先安装在笔记本中。) 要重现绘图,你还需要使用 shell 命令单独安装 matplotlib。pip install matplotlib

import numpy as np import matplotlib.pyplot as plt # required for plotting from braket.ahs.atom_arrangement import AtomArrangement a = 5.7e-6 # nearest-neighbor separation (in meters) register = AtomArrangement() register.add(np.array([0.5, 0.5 + 1/np.sqrt(2)]) * a) register.add(np.array([0.5 + 1/np.sqrt(2), 0.5]) * a) register.add(np.array([0.5 + 1/np.sqrt(2), - 0.5]) * a) register.add(np.array([0.5, - 0.5 - 1/np.sqrt(2)]) * a) register.add(np.array([-0.5, - 0.5 - 1/np.sqrt(2)]) * a) register.add(np.array([-0.5 - 1/np.sqrt(2), - 0.5]) * a) register.add(np.array([-0.5 - 1/np.sqrt(2), 0.5]) * a) register.add(np.array([-0.5, 0.5 + 1/np.sqrt(2)]) * a)

我们也可以用它来绘图

fig, ax = plt.subplots(1, 1, figsize=(7,7)) xs, ys = [register.coordinate_list(dim) for dim in (0, 1)] ax.plot(xs, ys, 'r.', ms=15) for idx, (x, y) in enumerate(zip(xs, ys)): ax.text(x, y, f" {idx}", fontsize=12) plt.show() # this will show the plot below in an ipython or jupyter session
散点图显示了在两个轴上的正值和负值上分布的点。

交互

为了准备反铁磁相,我们需要诱导相邻自旋之间的相互作用。为此,我们使用 van der Waals 交互作用,该交互是由中性原子器件原生实现的(例如 Aquila 设备来自 QuEra)。 使用自旋表示,这种相互作用的哈密顿项可以表示为所有自旋对 (j, k) 的总和。

哈密顿相互作用方程显示了这种相互作用,表示为所有自旋对 (j, k) 的总和。

这里,nj=^↑ ↑↑ 是一个运算符,仅当 j s j pin j 处于 “向上” 状态时才取值 1,否则取值 0。强度为 V j,k =C6/(dj,k​) 6,其中 C 6 是固定系数,d j,k 是自旋 j 和 k 之间的欧几里得距离。这个相互作用项的直接影响是,任何自旋 j 和自旋 k 都是 “向上” 的状态的能量都会升高(按量 Vj,k)。通过精心设计AHS程序的其余部分,这种交互将防止相邻的旋转都处于 “向上” 状态,这种效果通常被称为 “里德伯格封锁”。

驾驶场

在AHS程序开始时,所有旋转(默认情况下)都以 “向下” 状态开始,它们处于所谓的铁磁阶段。着眼于准备反铁磁相位的目标,我们指定了一个随时间变化的相干驱动场,该驱动场可以平稳地将自旋从这种状态过渡到首选 “向上” 状态的多体状态。相应的哈密顿量可以写成

描述哈密顿驱动函数计算的数学方程。

其中 Ω (t)、(t)、Δ( t) 是随时间变化的全局振幅(又名 Rabi 频率)、相位和失谐均匀地影响所有自旋的驱动场。这里 S −,k =^↓ k​ 和 S = +,k (S−,k) =↑↑ k ^^ 分别是 k​ s k pin k 的降低和升高运算符,n k =↑↑↑ 和以前是相同的运算符。k k驱动场的 Ω 部分同时连贯地耦合所有旋转的 “向下” 和 “向上” 状态,而 Δ部分控制 “向上” 状态的能量奖励。

为了编程从铁磁相向到反铁磁相的平滑过渡,我们使用以下代码指定驱动场。

from braket.timings.time_series import TimeSeries from braket.ahs.driving_field import DrivingField # smooth transition from "down" to "up" state time_max = 4e-6 # seconds time_ramp = 1e-7 # seconds omega_max = 6300000.0 # rad / sec delta_start = -5 * omega_max delta_end = 5 * omega_max omega = TimeSeries() omega.put(0.0, 0.0) omega.put(time_ramp, omega_max) omega.put(time_max - time_ramp, omega_max) omega.put(time_max, 0.0) delta = TimeSeries() delta.put(0.0, delta_start) delta.put(time_ramp, delta_start) delta.put(time_max - time_ramp, delta_end) delta.put(time_max, delta_end) phi = TimeSeries().put(0.0, 0.0).put(time_max, 0.0) drive = DrivingField( amplitude=omega, phase=phi, detuning=delta )

我们可以使用以下脚本可视化驾驶场的时间序列。

fig, axes = plt.subplots(3, 1, figsize=(12, 7), sharex=True) ax = axes[0] time_series = drive.amplitude.time_series ax.plot(time_series.times(), time_series.values(), '.-'); ax.grid() ax.set_ylabel('Omega [rad/s]') ax = axes[1] time_series = drive.detuning.time_series ax.plot(time_series.times(), time_series.values(), '.-'); ax.grid() ax.set_ylabel('Delta [rad/s]') ax = axes[2] time_series = drive.phase.time_series # Note: time series of phase is understood as a piecewise constant function ax.step(time_series.times(), time_series.values(), '.-', where='post'); ax.set_ylabel('phi [rad]') ax.grid() ax.set_xlabel('time [s]') plt.show() # this will show the plot below in an ipython or jupyter session
三张图表显示了一段时间内的 phi、delta 和 omega。顶部的子图显示了增长到略高于 6 rads/s,在那里它保持 4 秒钟,直到回落到 0。中间的子图描绘了导数的相关线性增长,底部的子图描绘了一条接近零的平线。

AHS节目

寄存器、驱动场(以及隐式的范德华相互作用)构成了模拟哈密顿仿真程序。ahs_program

from braket.ahs.analog_hamiltonian_simulation import AnalogHamiltonianSimulation ahs_program = AnalogHamiltonianSimulation( register=register, hamiltonian=drive )

在本地模拟器上运行

由于此示例很小(少于 15 次旋转),因此在AHS兼容版本上运行之前QPU,我们可以在 Bra SDK ket 附带的本地AHS模拟器上运行它。由于 Braket 可以免费使用本地模拟器SDK,因此这是确保我们的代码能够正确执行的最佳实践。

在这里,我们可以将镜头数量设置为较高的值(比如100万),因为本地模拟器会跟踪量子态的时间演变并从最终状态中抽取样本;因此,可以增加镜头数量,而总运行时间仅略有增加。

from braket.devices import LocalSimulator device = LocalSimulator("braket_ahs") result_simulator = device.run( ahs_program, shots=1_000_000 ).result() # takes about 5 seconds

分析模拟器结果

我们可以使用以下函数聚合镜头结果,该函数可以推断每次旋转的状态(可以是 “d” 代表 “向下”,“u” 表示 “向上”,“e” 代表空场地),并计算每种配置在镜头中发生的次数。

from collections import Counter def get_counts(result): """Aggregate state counts from AHS shot results A count of strings (of length = # of spins) are returned, where each character denotes the state of a spin (site): e: empty site u: up state spin d: down state spin Args: result (braket.tasks.analog_hamiltonian_simulation_quantum_task_result.AnalogHamiltonianSimulationQuantumTaskResult) Returns dict: number of times each state configuration is measured """ state_counts = Counter() states = ['e', 'u', 'd'] for shot in result.measurements: pre = shot.pre_sequence post = shot.post_sequence state_idx = np.array(pre) * (1 + np.array(post)) state = "".join(map(lambda s_idx: states[s_idx], state_idx)) state_counts.update((state,)) return dict(state_counts) counts_simulator = get_counts(result_simulator) # takes about 5 seconds print(counts_simulator)
{'udududud': 330944, 'dudududu': 329576, 'dududdud': 38033, ...}

counts这是一本字典,它计算了在镜头中观察到每种状态配置的次数。我们还可以使用以下代码将它们可视化。

from collections import Counter def has_neighboring_up_states(state): if 'uu' in state: return True if state[0] == 'u' and state[-1] == 'u': return True return False def number_of_up_states(state): return Counter(state)['u'] def plot_counts(counts): non_blockaded = [] blockaded = [] for state, count in counts.items(): if not has_neighboring_up_states(state): collection = non_blockaded else: collection = blockaded collection.append((state, count, number_of_up_states(state))) blockaded.sort(key=lambda _: _[1], reverse=True) non_blockaded.sort(key=lambda _: _[1], reverse=True) for configurations, name in zip((non_blockaded, blockaded), ('no neighboring "up" states', 'some neighboring "up" states')): plt.figure(figsize=(14, 3)) plt.bar(range(len(configurations)), [item[1] for item in configurations]) plt.xticks(range(len(configurations))) plt.gca().set_xticklabels([item[0] for item in configurations], rotation=90) plt.ylabel('shots') plt.grid(axis='y') plt.title(f'{name} configurations') plt.show() plot_counts(counts_simulator)
条形图显示了大量没有相邻的 “向上” 状态配置的镜头。
条形图显示了一些相邻的 “向上” 状态配置的镜头,状态从高到低的值降低。

从图中我们可以读出以下观测结果,以验证我们成功制备了反铁磁相。

  1. 通常,非阻塞状态(没有两个相邻的旋转处于 “向上” 状态)比至少有一对相邻旋转都处于 “向上” 状态的状态更为常见。

  2. 通常,除非配置被阻止,否则会优先选择激励更多 “向上” 的状态。

  3. 最常见的状态确实是完美的反铁磁态和. "dudududu" "udududud"

  4. 第二常见的状态是只有 3 个 “向上” 激励,连续间隔为 1、2、2 的状态。这表明范德华的交互作用也会对最近的邻居产生影响(尽管要小得多)。

Run QuEra ning on 的天鹰座 QPU

先决条件:除了 pip 安装 Braket 之外 SDK,如果您不熟悉 Amazon Braket,请确保您已完成必要的入门步骤。

注意

如果您使用的是 Braket 托管的笔记本实例,则该实例预SDK装了 Braket。

安装完所有依赖项后,我们可以连接到 Aquila QPU.

from braket.aws import AwsDevice aquila_qpu = AwsDevice("arn:aws:braket:us-east-1::device/qpu/quera/Aquila")

为了使我们的AHS计划适合 QuEra 机器,我们需要对所有值进行四舍五入以符合允许的精度级别 Aquila QPU。 (这些要求受名称中带有 “分辨率” 的设备参数的约束。 我们可以通过在笔记本aquila_qpu.properties.dict()中执行来看到它们。 有关 Aquila 功能和要求的更多详细信息,请参阅 Aq uila 笔记本简介。) 我们可以通过调用discretize方法来做到这一点。

discretized_ahs_program = ahs_program.discretize(aquila_qpu)

现在我们可以在上面运行该程序(目前只运行 100 张照片) Aquila QPU.

注意

在上运行这个程序 Aquila 处理器将产生成本。Amazon Braket SDK 包括成本追踪器,使客户能够设置成本限额并近乎实时地跟踪成本。

task = aquila_qpu.run(discretized_ahs_program, shots=100) metadata = task.metadata() task_arn = metadata['quantumTaskArn'] task_status = metadata['status'] print(f"ARN: {task_arn}") print(f"status: {task_status}")
task ARN: arn:aws:braket:us-east-1:123456789012:quantum-task/12345678-90ab-cdef-1234-567890abcdef task status: CREATED

由于量子任务的运行时间差异很大(取决于可用性窗口和QPU利用率),因此记下量子任务是个好主意ARN,因此我们可以稍后使用以下代码片段检查其状态。

# Optionally, in a new python session from braket.aws import AwsQuantumTask SAVED_TASK_ARN = "arn:aws:braket:us-east-1:123456789012:quantum-task/12345678-90ab-cdef-1234-567890abcdef" task = AwsQuantumTask(arn=SAVED_TASK_ARN) metadata = task.metadata() task_arn = metadata['quantumTaskArn'] task_status = metadata['status'] print(f"ARN: {task_arn}") print(f"status: {task_status}")
*[Output]* task ARN: arn:aws:braket:us-east-1:123456789012:quantum-task/12345678-90ab-cdef-1234-567890abcdef task status: COMPLETED

状态变为COMPLETED(也可以从 Amazon Braket 控制台的量子任务页面进行检查)后,我们可以通过以下方式查询结果:

result_aquila = task.result()

分析QPU结果

使用与以前相同的get_counts函数,我们可以计算计数:

counts_aquila = get_counts(result_aquila) print(counts_aquila)
*[Output]* {'udududud': 24, 'dudududu': 17, 'dududdud': 3, ...}

然后用以下方式绘制它们plot_counts

plot_counts(counts_aquila)
条形图显示了有和没有相邻 “向上” 状态的拍摄速度。

请注意,一小部分镜头的场地为空(标有 “e”)。这是由于每个原子的制备缺陷为 1-2% Aquila QPU。 除此之外,由于射门数量少,结果在预期的统计波动范围内与仿真相符。

后续步骤

恭喜,你现在已经使用本地AHS模拟器在 Amazon Braket 上运行了你的第一个AHS工作负载 Aquila QPU.

要了解有关 Rydberg 物理学、模拟哈密顿仿真和 Aquila 设备,请参阅我们的示例笔记本电脑