新しく出た中性原子量子コンピュータをツールからさっそく使っていきます。今回はamazonの提供しているbraketから行います。blueqatSDKではいまのところサポート予定はないですのでbraketを使います。
中性原子はアナログ方式の量子プロセッサを採用していて、リュードベリブロッケードなどの知識を使います。また、ハミルトニアンと呼ばれる式をベースに計算をする方式で詳しくはblueqat.comから該当のさまざまな記事が出ていますので、ご参照ください。
まずはamazon braketを最新にします。実機を使うにはまたアカウント登録などが必要ですが、今回は割愛します。
例題はこちらから使っています。
時々オリジナルのコードも入れてます。
!pip install -U amazon-braket-sdk
Requirement already satisfied: amazon-braket-sdk in /home/ec2-user/anaconda3/envs/Braket/lib/python3.7/site-packages (1.31.0)
Collecting amazon-braket-sdk
Downloading amazon_braket_sdk-1.33.0-py3-none-any.whl (241 kB)
[K |████████████████████████████████| 241 kB 27.3 MB/s eta 0:00:01
[?25hRequirement already satisfied: boltons in /home/ec2-user/anaconda3/envs/Braket/lib/python3.7/site-packages (from amazon-braket-sdk) (20.2.1)
Requirement already satisfied: numpy in /home/ec2-user/anaconda3/envs/Braket/lib/python3.7/site-packages (from amazon-braket-sdk) (1.21.6)
Requirement already satisfied: sympy in /home/ec2-user/anaconda3/envs/Braket/lib/python3.7/site-packages (from amazon-braket-sdk) (1.7.1)
Requirement already satisfied: networkx in /home/ec2-user/anaconda3/envs/Braket/lib/python3.7/site-packages (from amazon-braket-sdk) (2.4)
Requirement already satisfied: backoff in /home/ec2-user/anaconda3/envs/Braket/lib/python3.7/site-packages (from amazon-braket-sdk) (1.10.0)
Requirement already satisfied: nest-asyncio in /home/ec2-user/anaconda3/envs/Braket/lib/python3.7/site-packages (from amazon-braket-sdk) (1.5.1)
Collecting oqpy==0.1.0
Downloading oqpy-0.1.0-py3-none-any.whl (26 kB)
Requirement already satisfied: typing-extensions<5.0.0,>=4.3.0 in /home/ec2-user/anaconda3/envs/Braket/lib/python3.7/site-packages (from oqpy==0.1.0->amazon-braket-sdk) (4.3.0)
Collecting openpulse
Downloading openpulse-0.4.0-py3-none-any.whl (376 kB)
[K |████████████████████████████████| 376 kB 72.9 MB/s eta 0:00:01
[?25hRequirement already satisfied: importlib-metadata in /home/ec2-user/anaconda3/envs/Braket/lib/python3.7/site-packages (from openpulse->amazon-braket-sdk) (2.0.0)
Requirement already satisfied: antlr4-python3-runtime<4.12,>=4.7 in /home/ec2-user/anaconda3/envs/Braket/lib/python3.7/site-packages (from openpulse->amazon-braket-sdk) (4.8)
Collecting openqasm3
Downloading openqasm3-0.4.0-py3-none-any.whl (385 kB)
[K |████████████████████████████████| 385 kB 40.0 MB/s eta 0:00:01
[?25hCollecting amazon-braket-default-simulator>=1.10.0
Downloading amazon_braket_default_simulator-1.10.0-py3-none-any.whl (206 kB)
[K |████████████████████████████████| 206 kB 71.9 MB/s eta 0:00:01
[?25hRequirement already satisfied: scipy in /home/ec2-user/anaconda3/envs/Braket/lib/python3.7/site-packages (from amazon-braket-default-simulator>=1.10.0->amazon-braket-sdk) (1.5.2)
Requirement already satisfied: opt-einsum in /home/ec2-user/anaconda3/envs/Braket/lib/python3.7/site-packages (from amazon-braket-default-simulator>=1.10.0->amazon-braket-sdk) (3.1.0)
Collecting antlr4-python3-runtime<4.12,>=4.7
Using cached antlr4-python3-runtime-4.9.2.tar.gz (117 kB)
Collecting pydantic==1.9.0
Using cached pydantic-1.9.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (10.9 MB)
Collecting amazon-braket-schemas>=1.12.0
Downloading amazon_braket_schemas-1.12.0-py3-none-any.whl (109 kB)
[K |████████████████████████████████| 109 kB 73.2 MB/s eta 0:00:01
[?25hCollecting boto3>=1.22.3
Downloading boto3-1.25.5-py3-none-any.whl (132 kB)
[K |████████████████████████████████| 132 kB 66.0 MB/s eta 0:00:01
[?25hRequirement already satisfied: jmespath<2.0.0,>=0.7.1 in /home/ec2-user/anaconda3/envs/Braket/lib/python3.7/site-packages (from boto3>=1.22.3->amazon-braket-sdk) (0.10.0)
Collecting botocore<1.29.0,>=1.28.5
Downloading botocore-1.28.5-py3-none-any.whl (9.3 MB)
[K |████████████████████████████████| 9.3 MB 63.0 MB/s eta 0:00:01
[?25hRequirement already satisfied: python-dateutil<3.0.0,>=2.1 in /home/ec2-user/anaconda3/envs/Braket/lib/python3.7/site-packages (from botocore<1.29.0,>=1.28.5->boto3>=1.22.3->amazon-braket-sdk) (2.8.1)
Requirement already satisfied: urllib3<1.27,>=1.25.4 in /home/ec2-user/anaconda3/envs/Braket/lib/python3.7/site-packages (from botocore<1.29.0,>=1.28.5->boto3>=1.22.3->amazon-braket-sdk) (1.25.11)
Collecting mypy-extensions<0.5.0,>=0.4.3
Downloading mypy_extensions-0.4.3-py2.py3-none-any.whl (4.5 kB)
Requirement already satisfied: six>=1.5 in /home/ec2-user/anaconda3/envs/Braket/lib/python3.7/site-packages (from python-dateutil<3.0.0,>=2.1->botocore<1.29.0,>=1.28.5->boto3>=1.22.3->amazon-braket-sdk) (1.15.0)
Collecting s3transfer<0.7.0,>=0.6.0
Downloading s3transfer-0.6.0-py3-none-any.whl (79 kB)
[K |████████████████████████████████| 79 kB 10.7 MB/s eta 0:00:01
[?25hRequirement already satisfied: zipp>=0.5 in /home/ec2-user/anaconda3/envs/Braket/lib/python3.7/site-packages (from importlib-metadata->openpulse->amazon-braket-sdk) (3.4.0)
Requirement already satisfied: decorator>=4.3.0 in /home/ec2-user/anaconda3/envs/Braket/lib/python3.7/site-packages (from networkx->amazon-braket-sdk) (4.4.2)
Requirement already satisfied: mpmath>=0.19 in /home/ec2-user/anaconda3/envs/Braket/lib/python3.7/site-packages (from sympy->amazon-braket-sdk) (1.2.1)
Building wheels for collected packages: antlr4-python3-runtime
Building wheel for antlr4-python3-runtime (setup.py) ... [?25ldone
[?25h Created wheel for antlr4-python3-runtime: filename=antlr4_python3_runtime-4.9.2-py3-none-any.whl size=144566 sha256=93a2d2ba99501db149d0bd31e57327f71039a9732da618116340f16db8a86422
Stored in directory: /home/ec2-user/.cache/pip/wheels/14/4c/18/1dbbc9875a2547d2063400ea9f404da4af3331965a71061029
Successfully built antlr4-python3-runtime
Installing collected packages: openqasm3, antlr4-python3-runtime, pydantic, botocore, s3transfer, openpulse, mypy-extensions, amazon-braket-schemas, oqpy, boto3, amazon-braket-default-simulator, amazon-braket-sdk
Attempting uninstall: antlr4-python3-runtime
Found existing installation: antlr4-python3-runtime 4.8
Uninstalling antlr4-python3-runtime-4.8:
Successfully uninstalled antlr4-python3-runtime-4.8
Attempting uninstall: pydantic
Found existing installation: pydantic 1.10.2
Uninstalling pydantic-1.10.2:
Successfully uninstalled pydantic-1.10.2
Attempting uninstall: botocore
Found existing installation: botocore 1.17.44
Uninstalling botocore-1.17.44:
Successfully uninstalled botocore-1.17.44
Attempting uninstall: s3transfer
Found existing installation: s3transfer 0.3.4
Uninstalling s3transfer-0.3.4:
Successfully uninstalled s3transfer-0.3.4
Attempting uninstall: amazon-braket-schemas
Found existing installation: amazon-braket-schemas 1.10.2
Uninstalling amazon-braket-schemas-1.10.2:
Successfully uninstalled amazon-braket-schemas-1.10.2
Attempting uninstall: boto3
Found existing installation: boto3 1.14.43
Uninstalling boto3-1.14.43:
Successfully uninstalled boto3-1.14.43
Attempting uninstall: amazon-braket-default-simulator
Found existing installation: amazon-braket-default-simulator 1.8.1
Uninstalling amazon-braket-default-simulator-1.8.1:
Successfully uninstalled amazon-braket-default-simulator-1.8.1
Attempting uninstall: amazon-braket-sdk
Found existing installation: amazon-braket-sdk 1.31.0
Uninstalling amazon-braket-sdk-1.31.0:
Successfully uninstalled amazon-braket-sdk-1.31.0
[31mERROR: pip's dependency resolver does not currently take into account all the packages that are installed. This behaviour is the source of the following dependency conflicts.
quantum-blackbird 0.4.0 requires antlr4-python3-runtime==4.8, but you have antlr4-python3-runtime 4.9.2 which is incompatible.
awscli 1.18.121 requires botocore==1.17.44, but you have botocore 1.28.5 which is incompatible.
awscli 1.18.121 requires s3transfer<0.4.0,>=0.3.0, but you have s3transfer 0.6.0 which is incompatible.[0m
Successfully installed amazon-braket-default-simulator-1.10.0 amazon-braket-schemas-1.12.0 amazon-braket-sdk-1.33.0 antlr4-python3-runtime-4.9.2 boto3-1.25.5 botocore-1.28.5 mypy-extensions-0.4.3 openpulse-0.4.0 openqasm3-0.4.0 oqpy-0.1.0 pydantic-1.9.0 s3transfer-0.6.0
始める前に、2022年11月6日時点ではまだライブラリがそろっていませんでした、こちらの下記のライブラリを手作業で導入しました。使う方はコピペして使ってください。
import numpy as np
import matplotlib.pyplot as plt
import networkx as nx
from braket.ahs.atom_arrangement import SiteType
from braket.timings.time_series import TimeSeries
from braket.ahs.driving_field import DrivingField
from braket.ahs.shifting_field import ShiftingField
from braket.ahs.field import Field
from braket.ahs.pattern import Pattern
from collections import Counter
from typing import Dict, List, Tuple
from braket.tasks.analog_hamiltonian_simulation_quantum_task_result import AnalogHamiltonianSimulationQuantumTaskResult
from braket.ahs.atom_arrangement import AtomArrangement
def show_register(
register: AtomArrangement,
blockade_radius: float=0.0,
what_to_draw: str="bond",
show_atom_index:bool=True
):
"""Plot the given register
Args:
register (AtomArrangement): A given register
blockade_radius (float): The blockade radius for the register. Default is 0
what_to_draw (str): Either "bond" or "circle" to indicate the blockade region.
Default is "bond"
show_atom_index (bool): Whether showing the indices of the atoms. Default is True
"""
filled_sites = [site.coordinate for site in register if site.site_type == SiteType.FILLED]
empty_sites = [site.coordinate for site in register if site.site_type == SiteType.VACANT]
fig = plt.figure(figsize=(7, 7))
if filled_sites:
plt.plot(np.array(filled_sites)[:, 0], np.array(filled_sites)[:, 1], 'r.', ms=15, label='filled')
if empty_sites:
plt.plot(np.array(empty_sites)[:, 0], np.array(empty_sites)[:, 1], 'k.', ms=5, label='empty')
plt.legend(bbox_to_anchor=(1.1, 1.05))
if show_atom_index:
for idx, site in enumerate(register):
plt.text(*site.coordinate, f" {idx}", fontsize=12)
if blockade_radius > 0 and what_to_draw=="bond":
for i in range(len(filled_sites)):
for j in range(i+1, len(filled_sites)):
dist = np.linalg.norm(np.array(filled_sites[i]) - np.array(filled_sites[j]))
if dist <= blockade_radius:
plt.plot([filled_sites[i][0], filled_sites[j][0]], [filled_sites[i][1], filled_sites[j][1]], 'b')
if blockade_radius > 0 and what_to_draw=="circle":
for site in filled_sites:
plt.gca().add_patch( plt.Circle((site[0],site[1]), blockade_radius/2, color="b", alpha=0.3) )
plt.gca().set_aspect(1)
plt.show()
def rabi_pulse(
rabi_pulse_area: float,
omega_max: float,
omega_slew_rate_max: float
) -> Tuple[List[float], List[float]]:
"""Get a time series for Rabi frequency with specified Rabi phase, maximum amplitude
and maximum slew rate
Args:
rabi_pulse_area (float): Total area under the Rabi frequency time series
omega_max (float): The maximum amplitude
omega_slew_rate_max (float): The maximum slew rate
Returns:
Tuple[List[float], List[float]]: A tuple containing the time points and values
of the time series for the time dependent Rabi frequency
Notes: By Rabi phase, it means the integral of the amplitude of a time-dependent
Rabi frequency, \int_0^T\Omega(t)dt, where T is the duration.
"""
phase_threshold = omega_max**2 / omega_slew_rate_max
if rabi_pulse_area <= phase_threshold:
t_ramp = np.sqrt(rabi_pulse_area / omega_slew_rate_max)
t_plateau = 0
else:
t_ramp = omega_max / omega_slew_rate_max
t_plateau = (rabi_pulse_area / omega_max) - t_ramp
t_pules = 2 * t_ramp + t_plateau
time_points = [0, t_ramp, t_ramp + t_plateau, t_pules]
amplitude_values = [0, t_ramp * omega_slew_rate_max, t_ramp * omega_slew_rate_max, 0]
return time_points, amplitude_values
def get_counts(result: AnalogHamiltonianSimulationQuantumTaskResult) -> Dict[str, int]:
"""Aggregate state counts from AHS shot results
Args:
result (AnalogHamiltonianSimulationQuantumTaskResult): The result
from which the aggregated state counts are obtained
Returns:
Dict[str, int]: number of times each state configuration is measured
Notes: We use the following convention to denote the state of an atom (site):
e: empty site
r: Rydberg state atom
g: ground state atom
"""
state_counts = Counter()
states = ['e', 'r', 'g']
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)
def get_drive(
times: List[float],
amplitude_values: List[float],
detuning_values: List[float],
phase_values: List[float]
) -> DrivingField:
"""Get the driving field from a set of time points and values of the fields
Args:
times (List[float]): The time points of the driving field
amplitude_values (List[float]): The values of the amplitude
detuning_values (List[float]): The values of the detuning
phase_values (List[float]): The values of the phase
Returns:
DrivingField: The driving field obtained
"""
assert len(times) == len(amplitude_values)
assert len(times) == len(detuning_values)
assert len(times) == len(phase_values)
amplitude = TimeSeries()
detuning = TimeSeries()
phase = TimeSeries()
for t, amplitude_value, detuning_value, phase_value in zip(times, amplitude_values, detuning_values, phase_values):
amplitude.put(t, amplitude_value)
detuning.put(t, detuning_value)
phase.put(t, phase_value)
drive = DrivingField(
amplitude=amplitude,
detuning=detuning,
phase=phase
)
return drive
def get_shift(times: List[float], values: List[float], pattern: List[float]) -> ShiftingField:
"""Get the shifting field from a set of time points, values and pattern
Args:
times (List[float]): The time points of the shifting field
values (List[float]): The values of the shifting field
pattern (List[float]): The pattern of the shifting field
Returns:
ShiftingField: The shifting field obtained
"""
assert len(times) == len(values)
magnitude = TimeSeries()
for t, v in zip(times, values):
magnitude.put(t, v)
shift = ShiftingField(Field(magnitude, Pattern(pattern)))
return shift
def show_global_drive(drive, axes=None, **plot_ops):
"""Plot the driving field
Args:
drive (DrivingField): The driving field to be plot
axes: matplotlib axis to draw on
**plot_ops: options passed to matplitlib.pyplot.plot
"""
data = {
'amplitude [rad/s]': drive.amplitude.time_series,
'detuning [rad/s]': drive.detuning.time_series,
'phase [rad]': drive.phase.time_series,
}
if axes is None:
fig, axes = plt.subplots(3, 1, figsize=(7, 7), sharex=True)
for ax, data_name in zip(axes, data.keys()):
if data_name == 'phase [rad]':
ax.step(data[data_name].times(), data[data_name].values(), '.-', where='post',**plot_ops)
else:
ax.plot(data[data_name].times(), data[data_name].values(), '.-',**plot_ops)
ax.set_ylabel(data_name)
ax.grid(ls=':')
axes[-1].set_xlabel('time [s]')
plt.tight_layout()
plt.show()
def show_local_shift(shift:ShiftingField):
"""Plot the shifting field
Args:
shift (ShiftingField): The shifting field to be plot
"""
data = shift.magnitude.time_series
pattern = shift.magnitude.pattern.series
plt.plot(data.times(), data.values(), '.-', label="pattern: " + str(pattern))
plt.xlabel('time [s]')
plt.ylabel('shift [rad/s]')
plt.legend()
plt.tight_layout()
plt.show()
def show_drive_and_shift(drive: DrivingField, shift: ShiftingField):
"""Plot the driving and shifting fields
Args:
drive (DrivingField): The driving field to be plot
shift (ShiftingField): The shifting field to be plot
"""
drive_data = {
'amplitude [rad/s]': drive.amplitude.time_series,
'detuning [rad/s]': drive.detuning.time_series,
'phase [rad]': drive.phase.time_series,
}
fig, axes = plt.subplots(4, 1, figsize=(7, 7), sharex=True)
for ax, data_name in zip(axes, drive_data.keys()):
if data_name == 'phase [rad]':
ax.step(drive_data[data_name].times(), drive_data[data_name].values(), '.-', where='post')
else:
ax.plot(drive_data[data_name].times(), drive_data[data_name].values(), '.-')
ax.set_ylabel(data_name)
ax.grid(ls=':')
shift_data = shift.magnitude.time_series
pattern = shift.magnitude.pattern.series
axes[-1].plot(shift_data.times(), shift_data.values(), '.-', label="pattern: " + str(pattern))
axes[-1].set_ylabel('shift [rad/s]')
axes[-1].set_xlabel('time [s]')
axes[-1].legend()
axes[-1].grid()
plt.tight_layout()
plt.show()
def get_avg_density(result: AnalogHamiltonianSimulationQuantumTaskResult) -> np.ndarray:
"""Get the average Rydberg densities from the result
Args:
result (AnalogHamiltonianSimulationQuantumTaskResult): The result
from which the aggregated state counts are obtained
Returns:
ndarray: The average densities from the result
"""
measurements = result.measurements
postSeqs = [measurement.post_sequence for measurement in measurements]
postSeqs = 1 - np.array(postSeqs) # change the notation such 1 for rydberg state, and 0 for ground state
avg_density = np.sum(postSeqs, axis=0)/len(postSeqs)
return avg_density
def show_final_avg_density(result: AnalogHamiltonianSimulationQuantumTaskResult):
"""Showing a bar plot for the average Rydberg densities from the result
Args:
result (AnalogHamiltonianSimulationQuantumTaskResult): The result
from which the aggregated state counts are obtained
"""
avg_density = get_avg_density(result)
plt.bar(range(len(avg_density)), avg_density)
plt.xlabel("Indices of atoms")
plt.ylabel("Average Rydberg density")
plt.show()
def constant_time_series(other_time_series: TimeSeries, constant: float=0.0) -> TimeSeries:
"""Obtain a constant time series with the same time points as the given time series
Args:
other_time_series (TimeSeries): The given time series
Returns:
TimeSeries: A constant time series with the same time points as the given time series
"""
ts = TimeSeries()
for t in other_time_series.times():
ts.put(t, constant)
return ts
def concatenate_time_series(time_series_1: TimeSeries, time_series_2: TimeSeries) -> TimeSeries:
"""Concatenate two time series to a single time series
Args:
time_series_1 (TimeSeries): The first time series to be concatenated
time_series_2 (TimeSeries): The second time series to be concatenated
Returns:
TimeSeries: The concatenated time series
"""
assert time_series_1.values()[-1] == time_series_2.values()[0]
duration_1 = time_series_1.times()[-1] - time_series_1.times()[0]
new_time_series = TimeSeries()
new_times = time_series_1.times() + [t + duration_1 - time_series_2.times()[0] for t in time_series_2.times()[1:]]
new_values = time_series_1.values() + time_series_2.values()[1:]
for t, v in zip(new_times, new_values):
new_time_series.put(t, v)
return new_time_series
def concatenate_drives(drive_1: DrivingField, drive_2: DrivingField) -> DrivingField:
"""Concatenate two driving fields to a single driving field
Args:
drive_1 (DrivingField): The first driving field to be concatenated
drive_2 (DrivingField): The second driving field to be concatenated
Returns:
DrivingField: The concatenated driving field
"""
return DrivingField(
amplitude=concatenate_time_series(drive_1.amplitude.time_series, drive_2.amplitude.time_series),
detuning=concatenate_time_series(drive_1.detuning.time_series, drive_2.detuning.time_series),
phase=concatenate_time_series(drive_1.phase.time_series, drive_2.phase.time_series)
)
def concatenate_shifts(shift_1: ShiftingField, shift_2: ShiftingField) -> ShiftingField:
"""Concatenate two driving fields to a single driving field
Args:
shift_1 (ShiftingField): The first shifting field to be concatenated
shift_2 (ShiftingField): The second shifting field to be concatenated
Returns:
ShiftingField: The concatenated shifting field
"""
assert shift_1.magnitude.pattern.series == shift_2.magnitude.pattern.series
new_magnitude = concatenate_time_series(shift_1.magnitude.time_series, shift_2.magnitude.time_series)
return ShiftingField(Field(new_magnitude, shift_1.magnitude.pattern))
def concatenate_drive_list(drive_list: List[DrivingField]) -> DrivingField:
"""Concatenate a list of driving fields to a single driving field
Args:
drive_list (List[DrivingField]): The list of driving fields to be concatenated
Returns:
DrivingField: The concatenated driving field
"""
drive = drive_list[0]
for dr in drive_list[1:]:
drive = concatenate_drives(drive, dr)
return drive
def concatenate_shift_list(shift_list: List[ShiftingField]) -> ShiftingField:
"""Concatenate a list of shifting fields to a single driving field
Args:
shift_list (List[ShiftingField]): The list of shifting fields to be concatenated
Returns:
ShiftingField: The concatenated shifting field
"""
shift = shift_list[0]
for sf in shift_list[1:]:
shift = concatenate_shifts(shift, sf)
return shift
def plot_avg_density_2D(densities, register, with_labels = True, batch_index = None, batch_mapping = None, custom_axes = None):
# get atom coordinates
atom_coords = list(zip(register.coordinate_list(0), register.coordinate_list(1)))
# convert all to micrometers
atom_coords = [(atom_coord[0] * 10**6, atom_coord[1] * 10**6) for atom_coord in atom_coords]
plot_avg_of_avgs = False
plot_single_batch = False
if batch_index is not None:
if batch_mapping is not None:
plot_single_batch = True
# provided both batch and batch_mapping, show averages of single batch
batch_subindices = batch_mapping[batch_index]
batch_labels = {i:label for i,label in enumerate(batch_subindices)}
# get proper positions
pos = {i:tuple(coord) for i,coord in enumerate(list(np.array(atom_coords)[batch_subindices]))}
# narrow down densities
densities = np.array(densities)[batch_subindices]
else:
raise Exception("batch_mapping required to index into")
else:
if batch_mapping is not None:
plot_avg_of_avgs = True
# just need the coordinates for first batch_mapping
subcoordinates = np.array(atom_coords)[batch_mapping[(0,0)]]
pos = {i:coord for i,coord in enumerate(subcoordinates)}
else:
# If both not provided do standard FOV
# handle 1D case
pos = {i:coord for i,coord in enumerate(atom_coords)}
# get colors
vmin = 0
vmax = 1
cmap = plt.cm.Blues
# construct graph
g = nx.Graph()
g.add_nodes_from(list(range(len(densities))))
# construct plot
if custom_axes is None:
fig, ax = plt.subplots()
else:
ax = custom_axes
nx.draw(g,
pos,
node_color=densities,
cmap=cmap,
node_shape="o",
vmin=vmin,
vmax=vmax,
font_size=9,
with_labels=with_labels,
labels= batch_labels if plot_single_batch else None,
ax = custom_axes if custom_axes is not None else ax)
## Set axes
ax.set_axis_on()
ax.tick_params(left=True,
bottom=True,
top=True,
right=True,
labelleft=True,
labelbottom=True,
# labeltop=True,
# labelright=True,
direction="in")
## Set colorbar
sm = plt.cm.ScalarMappable(cmap=cmap, norm=plt.Normalize(vmin=vmin, vmax=vmax))
sm.set_array([])
ax.ticklabel_format(style="sci", useOffset=False)
# set titles on x and y axes
plt.xlabel("x [μm]")
plt.ylabel("y [μm]")
if plot_avg_of_avgs:
cbar_label = "Averaged Rydberg Density"
else:
cbar_label = "Rydberg Density"
plt.colorbar(sm, ax=ax, label=cbar_label)
早速コードが入ってるか確認してみます。
from braket.aws import AwsDevice
device = AwsDevice("arn:aws:braket:us-east-1::device/qpu/quera/Aquila")
print(device.properties)
service=DeviceServiceProperties(braketSchemaHeader=BraketSchemaHeader(name='braket.device_schema.device_service_properties', version='1'), executionWindows=[DeviceExecutionWindow(executionDay=<ExecutionDay.TUESDAY: 'Tuesday'>, windowStartHour=datetime.time(16, 0), windowEndHour=datetime.time(20, 0)), DeviceExecutionWindow(executionDay=<ExecutionDay.WEDNESDAY: 'Wednesday'>, windowStartHour=datetime.time(16, 0), windowEndHour=datetime.time(20, 0)), DeviceExecutionWindow(executionDay=<ExecutionDay.THURSDAY: 'Thursday'>, windowStartHour=datetime.time(16, 0), windowEndHour=datetime.time(18, 0))], shotsRange=(1, 1000), deviceCost=DeviceCost(price=0.01, unit='shot'), deviceDocumentation=DeviceDocumentation(imageUrl='https://a.b.cdn.console.awsstatic.com/59534b58c709fc239521ef866db9ea3f1aba73ad3ebcf60c23914ad8c5c5c878/a6cfc6fca26cf1c2e1c6.png', summary='Analog quantum processor based on neutral atom arrays', externalDocumentationUrl='https://www.quera.com/aquila'), deviceLocation='Boston, USA', updatedAt=datetime.datetime(2022, 10, 31, 21, 30, tzinfo=datetime.timezone.utc)) action={<DeviceActionType.AHS: 'braket.ir.ahs.program'>: DeviceActionProperties(version=['1'], actionType=<DeviceActionType.AHS: 'braket.ir.ahs.program'>)} deviceParameters={} braketSchemaHeader=BraketSchemaHeader(name='braket.device_schema.quera.quera_device_capabilities', version='1') paradigm=QueraAhsParadigmProperties(braketSchemaHeader=BraketSchemaHeader(name='braket.device_schema.quera.quera_ahs_paradigm_properties', version='1'), qubitCount=256, lattice=Lattice(area=Area(width=Decimal('0.000075'), height=Decimal('0.000076')), geometry=Geometry(spacingRadialMin=Decimal('0.000004'), spacingVerticalMin=Decimal('0.000004'), positionResolution=Decimal('1E-7'), numberSitesMax=256)), rydberg=Rydberg(c6Coefficient=Decimal('5.42E-24'), rydbergGlobal=RydbergGlobal(rabiFrequencyRange=(Decimal('0.0'), Decimal('15800000.0')), rabiFrequencyResolution=Decimal('400.0'), rabiFrequencySlewRateMax=Decimal('250000000000000.0'), detuningRange=(Decimal('-125000000.0'), Decimal('125000000.0')), detuningResolution=Decimal('0.2'), detuningSlewRateMax=Decimal('2500000000000000.0'), phaseRange=(Decimal('-99.0'), Decimal('99.0')), phaseResolution=Decimal('5E-7'), timeResolution=Decimal('1E-9'), timeDeltaMin=Decimal('5E-8'), timeMin=Decimal('0.0'), timeMax=Decimal('0.000004'))), performance=Performance(lattice=PerformanceLattice(positionErrorAbs=Decimal('1E-7')), rydberg=PerformanceRydberg(rydbergGlobal=PerformanceRydbergGlobal(rabiFrequencyErrorRel=Decimal('0.02')))))
マシンは登録されているようです。マシンのプロパティが取れました。
原子の配置
ちょっと様子を見てみましょう。まずは原子を並べてみます。11量子ビット準備して6.1マイクロメートル間隔で並べてみます。
from braket.ahs.atom_arrangement import AtomArrangement
import numpy as np
#原子間距離
a = 6.1e-6
#量子ビット・原子数
N_atoms = 11
#並べる
register = AtomArrangement()
for i in range(N_atoms):
register.add([0.0, i*a])
vars(register)
{'_sites': [AtomArrangementItem(coordinate=(0.0, 0.0), site_type=<SiteType.FILLED: 'Filled'>),
AtomArrangementItem(coordinate=(0.0, 6.1e-06), site_type=<SiteType.FILLED: 'Filled'>),
AtomArrangementItem(coordinate=(0.0, 1.22e-05), site_type=<SiteType.FILLED: 'Filled'>),
AtomArrangementItem(coordinate=(0.0, 1.83e-05), site_type=<SiteType.FILLED: 'Filled'>),
AtomArrangementItem(coordinate=(0.0, 2.44e-05), site_type=<SiteType.FILLED: 'Filled'>),
AtomArrangementItem(coordinate=(0.0, 3.05e-05), site_type=<SiteType.FILLED: 'Filled'>),
AtomArrangementItem(coordinate=(0.0, 3.66e-05), site_type=<SiteType.FILLED: 'Filled'>),
AtomArrangementItem(coordinate=(0.0, 4.27e-05), site_type=<SiteType.FILLED: 'Filled'>),
AtomArrangementItem(coordinate=(0.0, 4.88e-05), site_type=<SiteType.FILLED: 'Filled'>),
AtomArrangementItem(coordinate=(0.0, 5.49e-05), site_type=<SiteType.FILLED: 'Filled'>),
AtomArrangementItem(coordinate=(0.0, 6.1e-05), site_type=<SiteType.FILLED: 'Filled'>)]}
取れましたね。原子を自分で位置を指定して並べるのが新しいですね。。。
show_register(register)
<Figure size 504x504 with 1 Axes>
次に三角形です。底辺を準備してから頂点を三角関数で指定します。
#三角形の一辺
a = 5.5e-6
#並べます
register = AtomArrangement()
register.add([0, 0])
register.add([a, 0.0])
register.add([0.5 * a, np.sqrt(3)/2 * a]);
show_register(register)
<Figure size 504x504 with 1 Axes>
次はもうちょい数を増やしてみます。原子三つのグループを25用意します。今回はリュードベリ半径の及ぶ原子同士の表示もします。
#小グループ
separation = 5e-6
#大グループ
block_separation = 15e-6
#縦横のグループ数
k_max = 5
m_max = 5
#配置
register = AtomArrangement()
for k in range(k_max):
for m in range(m_max):
register.add((block_separation*m, block_separation*k + separation/np.sqrt(3)))
register.add((block_separation*m-separation/2, block_separation*k - separation/(2*np.sqrt(3))))
register.add((block_separation*m+separation/2, block_separation*k - separation/(2*np.sqrt(3))))
#リュードベリブロッケード半径を指定しています
show_register(register, show_atom_index=False, blockade_radius= 1.5 * separation)
<Figure size 504x504 with 1 Axes>
時間発展
次に時間発展のハミルトニアンシミュレーションを見てみます。オメガやデルタでスケジュールを決めます。
from braket.timings.time_series import TimeSeries
from braket.ahs.driving_field import DrivingField
from pprint import pprint as pp
capabilities = device.properties.paradigm
pp(capabilities.dict())
rydberg = capabilities.rydberg
pp(rydberg.dict())
omega_const = 1.5e7 # rad / s
rabi_pulse_area = np.pi/np.sqrt(3) # rad
omega_slew_rate_max = float(rydberg.rydbergGlobal.rabiFrequencySlewRateMax) # rad/s^2
time_points, amplitude_values = rabi_pulse(rabi_pulse_area, omega_const, 0.99 * omega_slew_rate_max)
amplitude = TimeSeries()
for t, v in zip(time_points, amplitude_values):
amplitude.put(t, v)
detuning = constant_time_series(amplitude, 0.0)
phase = constant_time_series(amplitude, 0.0)
drive = DrivingField(
amplitude=amplitude,
detuning=detuning,
phase=phase
)
{'braketSchemaHeader': {'name': 'braket.device_schema.quera.quera_ahs_paradigm_properties',
'version': '1'},
'lattice': {'area': {'height': Decimal('0.000076'),
'width': Decimal('0.000075')},
'geometry': {'numberSitesMax': 256,
'positionResolution': Decimal('1E-7'),
'spacingRadialMin': Decimal('0.000004'),
'spacingVerticalMin': Decimal('0.000004')}},
'performance': {'lattice': {'positionErrorAbs': Decimal('1E-7')},
'rydberg': {'rydbergGlobal': {'rabiFrequencyErrorRel': Decimal('0.02')}}},
'qubitCount': 256,
'rydberg': {'c6Coefficient': Decimal('5.42E-24'),
'rydbergGlobal': {'detuningRange': (Decimal('-125000000.0'),
Decimal('125000000.0')),
'detuningResolution': Decimal('0.2'),
'detuningSlewRateMax': Decimal('2500000000000000.0'),
'phaseRange': (Decimal('-99.0'),
Decimal('99.0')),
'phaseResolution': Decimal('5E-7'),
'rabiFrequencyRange': (Decimal('0.0'),
Decimal('15800000.0')),
'rabiFrequencyResolution': Decimal('400.0'),
'rabiFrequencySlewRateMax': Decimal('250000000000000.0'),
'timeDeltaMin': Decimal('5E-8'),
'timeMax': Decimal('0.000004'),
'timeMin': Decimal('0.0'),
'timeResolution': Decimal('1E-9')}}}
{'c6Coefficient': Decimal('5.42E-24'),
'rydbergGlobal': {'detuningRange': (Decimal('-125000000.0'),
Decimal('125000000.0')),
'detuningResolution': Decimal('0.2'),
'detuningSlewRateMax': Decimal('2500000000000000.0'),
'phaseRange': (Decimal('-99.0'), Decimal('99.0')),
'phaseResolution': Decimal('5E-7'),
'rabiFrequencyRange': (Decimal('0.0'),
Decimal('15800000.0')),
'rabiFrequencyResolution': Decimal('400.0'),
'rabiFrequencySlewRateMax': Decimal('250000000000000.0'),
'timeDeltaMin': Decimal('5E-8'),
'timeMax': Decimal('0.000004'),
'timeMin': Decimal('0.0'),
'timeResolution': Decimal('1E-9')}}
show_global_drive(drive)
<Figure size 504x504 with 3 Axes>
実機実行!
早速実機へ投げる方法を見てみます。
まずは先ほどの配置と時間発展の情報を格納します。
from braket.ahs.hamiltonian import Hamiltonian
from braket.ahs.analog_hamiltonian_simulation import AnalogHamiltonianSimulation
ahs_program = AnalogHamiltonianSimulation(
register=register,
hamiltonian=drive
)
そして、次は問題をタスクで投げられるように変換
discretized_ahs_program = ahs_program.discretize(device)
例題ではここでタスクを投げられる回数をチェックしています。1000回まで投げられるので100回に指定。金額に気を付けてください。
device.properties.service.shotsRange
(1, 1000)
n_shots = 100
そしたら実行です。これで完了!簡単ですね!
task = device.run(discretized_ahs_program, shots=n_shots)
タスクのIDを確認したりステータスを確認します。記事投稿時は日曜日ですのでちょっとまだ動いてないのでタスクが作られただけです。
metadata = task.metadata()
task_arn = metadata['quantumTaskArn']
task_status = metadata['status']
print(f"ARN: {task_arn}")
print(f"status: {task_status}")
ARN: arn:aws:braket:us-east-1:722034924650:quantum-task/75a1751d-f99c-45b9-8181-f304c0ce4df2
status: CREATED
時間外の時には数日たってからまた確認に来ないといけないのでタスクIDからジョブをとれるようにします。
from braket.aws import AwsQuantumTask
task = AwsQuantumTask(arn="arn:aws:braket:us-east-1:722034924650:quantum-task/75a1751d-f99c-45b9-8181-f304c0ce4df2")
task_status = metadata['status']
print(f"status: {task_status}")
status: CREATED
まだジョブは投げられないようなので終了したら回収します。
次に計算結果の取り出しを確認します。
計算結果の処理を記事として書きたいのですが、計算結果が回収できないので次の機会にしたいと思います。