翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。
Hello AHS: 最初のアナログハミルトニアンシミュレーションを実行する
このセクションでは、最初のアナログハミルトニアンシミュレーションの実行について説明します。
このセクションの内容:
インタラクションスピンチェーン
多くの相互作用するパーティクルのシステムの正規例については、8 つのスピンのリング (それぞれが「上」∣↑⟩ および「下」∣↓⟩ 状態になる可能性があります) を考えてみましょう。このモデルシステムは、小さくても、自然に発生する磁気マテリアルの興味深い現象をすでにいくつか示しています。この例では、連続する回転が反対方向を向く、いわゆる抗強炭素順序を準備する方法を示します。

配置
1 つの中立アトムを使用して各スピンを待機し、「上」と「下」のスピン状態は、それぞれアトムの勾配 Rydberg 状態と地面状態でエンコードされます。まず、2 次元配置を作成します。上記のスピンリングは、次のコードでプログラムできます。
前提条件: Braket SDKpip 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 インタラクション

ここで、nj =jj∣↑⟩⟨↑∣ は、スピン j が「up」状態である場合にのみ 1 の値を、それ以外の場合は 0 の値を取る演算子です。強度は Vj,k=C6/(dj,k)6 で、C 6は固定係数、d j,kはスピン j と k の間のユークリッド距離です。この相互作用項の即時効果は、スピン j とスピン k の両方が「上」になっている状態がエネルギーを (V の量で) 増加させることですj,k。AHS プログラムの残りの部分を慎重に設計することで、この相互作用により、隣接するスピンが両方とも「アップ」状態になるのを防ぐことができます。これは、一般的に「Rydberg ブロック」と呼ばれる効果です。
運転フィールド
AHS プログラムの開始時、すべてのスピン (デフォルトでは) は「ダウン」状態で開始され、いわゆる強分解フェーズにあります。強炭素対策フェーズを準備するという目標を念頭に置いて、スピンをこの状態から「アップ」状態が優先される多体状態にスムーズに移行する時間依存のコヒーレント駆動フィールドを指定します。対応するハミルトニアンは次のように記述できます。

ここで、""(t)、""(t)、Δ(t) は、すべてのスピンに均一に影響を与える駆動フィールドの時間依存、グローバル振幅 (Rabi 周波数
強分解フェーズから抗強分解フェーズへのスムーズな移行をプログラムするには、次のコードで駆動フィールドを指定します。
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

AHS プログラム
レジスター、運転フィールド (および暗黙的な van der Waals インタラクション) は、アナログハミルトンシミュレーションプログラム を構成しますahs_program
。
from braket.ahs.analog_hamiltonian_simulation import AnalogHamiltonianSimulation ahs_program = AnalogHamiltonianSimulation( register=register, hamiltonian=drive )
ローカルシミュレーターでの実行
この例は小さい (15 回未満のスピン) ため、AHS 互換 QPU で実行する前に、Braket SDK に付属するローカル 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)


プロットから、次の観測値を読み、強分解防止フェーズを正常に準備したことを確認できます。
-
一般に、ブロックされていない状態 (2 つの隣接するスピンが「アップ」状態ではない状態) は、少なくとも 1 つの隣接するスピンのペアが両方とも「アップ」状態である状態よりも一般的です。
-
一般的に、設定がブロックされない限り、引用符が「アップ」が多い状態が優先されます。
-
最も一般的な状態は、実際には完全なアンチ強炭素状態
"dudududu"
と です"udududud"
。 -
2 番目によくある状態は、連続して 1、2、2 の分離で 3 つの「アップ」な興奮しか存在しない状態です。これは、van der Waals のインタラクションが、最近傍にも影響する (ただし、はるかに小さい) ことを示しています。
QuEra の Aquila QPU での実行
前提条件: Braket SDK
注記
Braket がホストするノートブックインスタンスを使用している場合、Braket SDK にはインスタンスがプリインストールされています。
すべての依存関係がインストールされると、AquilaQPU に接続できます。
from braket.aws import AwsDevice aquila_qpu = AwsDevice("arn:aws:braket:us-east-1::device/qpu/quera/Aquila")
AHS プログラムをQuEraマシンに適したものにするには、すべての値を四捨五入して、AquilaQPU で許可されている精度レベルに準拠する必要があります。(これらの要件は、名前に「Resolution」が付いたデバイスパラメータによって管理されます。 ノートブックaquila_qpu.properties.dict()
で を実行することで確認できます。 Aquila の機能と要件の詳細については、「Aquila の概要ノートブックdiscretize
メソッドを呼び出します。
discretized_ahs_program = ahs_program.discretize(aquila_qpu)
これで、AquilaQPU でプログラム (現在 100 ショットのみを実行) を実行できます。
注記
プロセッサでこのプログラムを実行すると、コストAquilaが発生します。Amazon Braket SDK には、お客様がコスト制限を設定し、ほぼリアルタイムでコストを追跡できる Cost Tracker
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
ステータスが完了すると (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」でマークされています)。これは、AquilaQPU の原子ごとの準備の不完全性が 1~2% であるためです。これとは別に、ショット数が少ないため、結果は予想される統計的変動内でシミュレーションと一致します。
次のステップ
これで、ローカル AHS シミュレーターと Aquila QPU を使用して Amazon Braket で最初の AHS ワークロードを実行できました。
Rydberg の物理、アナログハミルトニアンシミュレーション、および Aquila デバイスの詳細については、サンプルノートブック