Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1# Copyright 2019-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. 

2# 

3# Licensed under the Apache License, Version 2.0 (the "License"). You 

4# may not use this file except in compliance with the License. A copy of 

5# the License is located at 

6# 

7# http://aws.amazon.com/apache2.0/ 

8# 

9# or in the "license" file accompanying this file. This file is 

10# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 

11# ANY KIND, either express or implied. See the License for the specific 

12# language governing permissions and limitations under the License. 

13 

14from typing import Any, Dict, Union 

15 

16import boto3 

17from braket.annealing.problem import Problem 

18from braket.aws.aws_qpu_arns import AwsQpuArns 

19from braket.aws.aws_quantum_task import AwsQuantumTask 

20from braket.aws.aws_session import AwsSession 

21from braket.circuits import Circuit 

22from braket.devices.device import Device 

23from networkx import Graph, complete_graph, from_edgelist 

24 

25 

26class AwsQpu(Device): 

27 """ 

28 Amazon Braket implementation of a Quantum Processing Unit (QPU). 

29 Use this class to retrieve the latest metadata about the QPU, and to run a quantum task on the 

30 QPU. 

31 """ 

32 

33 QPU_REGIONS = { 

34 AwsQpuArns.RIGETTI: ["us-west-1"], 

35 AwsQpuArns.IONQ: ["us-east-1"], 

36 AwsQpuArns.DWAVE: ["us-west-2"], 

37 } 

38 

39 DEFAULT_SHOTS_QPU = 1000 

40 DEFAULT_RESULTS_POLL_TIMEOUT_QPU = 432000 

41 DEFAULT_RESULTS_POLL_INTERVAL_QPU = 1 

42 

43 def __init__(self, arn: str, aws_session=None): 

44 """ 

45 Args: 

46 arn (str): The ARN of the QPU, for example, "arn:aws:aqx:::qpu:ionq" 

47 aws_session (AwsSession, optional) aws_session: An AWS session object. Default = None. 

48 

49 Raises: 

50 ValueError: If an unknown `arn` is specified. 

51 

52 Note: 

53 QPUs are physically located in specific AWS Regions. In some cases, the current 

54 `aws_session` connects to a Region other than the Region in which the QPU is 

55 physically located. When this occurs, a cloned `aws_session` is created for the Region 

56 the QPU is located in. 

57 

58 See `braket.aws.aws_qpu.AwsQpu.QPU_REGIONS` for the AWS Regions the QPUs are located 

59 in. 

60 """ 

61 super().__init__(name=None, status=None, status_reason=None) 

62 self._arn = arn 

63 self._aws_session = self._aws_session_for_qpu(arn, aws_session) 

64 self._properties = None 

65 self.refresh_metadata() 

66 

67 def run( 

68 self, 

69 task_specification: Union[Circuit, Problem], 

70 s3_destination_folder: AwsSession.S3DestinationFolder, 

71 shots: int = DEFAULT_SHOTS_QPU, 

72 poll_timeout_seconds: int = DEFAULT_RESULTS_POLL_TIMEOUT_QPU, 

73 poll_interval_seconds: int = DEFAULT_RESULTS_POLL_INTERVAL_QPU, 

74 *aws_quantum_task_args, 

75 **aws_quantum_task_kwargs, 

76 ) -> AwsQuantumTask: 

77 """ 

78 Run a quantum task specification on this quantum device. A task can be a circuit or an 

79 annealing problem. 

80 

81 Args: 

82 task_specification (Union[Circuit, Problem]): Specification of task 

83 (circuit or annealing problem) to run on device. 

84 s3_destination_folder: The S3 location to save the task's results 

85 shots (int, optional): The number of times to run the circuit or annealing problem. 

86 Default is 1000. 

87 poll_timeout_seconds (int): The polling timeout for AwsQuantumTask.result(), in seconds. 

88 Default: 5 days. 

89 poll_interval_seconds (int): The polling interval for AwsQuantumTask.result(), 

90 in seconds. Default: 1 second. 

91 *aws_quantum_task_args: Variable length positional arguments for 

92 `braket.aws.aws_quantum_task.AwsQuantumTask.create()`. 

93 **aws_quantum_task_kwargs: Variable length keyword arguments for 

94 `braket.aws.aws_quantum_task.AwsQuantumTask.create()`. 

95 

96 Returns: 

97 AwsQuantumTask: An AwsQuantumTask that tracks the execution on the device. 

98 

99 Examples: 

100 >>> circuit = Circuit().h(0).cnot(0, 1) 

101 >>> device = AwsQpu("arn:aws:aqx:::qpu:rigetti") 

102 >>> device.run(circuit, ("bucket-foo", "key-bar")) 

103 

104 >>> circuit = Circuit().h(0).cnot(0, 1) 

105 >>> device = AwsQpu("arn:aws:aqx:::qpu:rigetti") 

106 >>> device.run(task_specification=circuit, 

107 >>> s3_destination_folder=("bucket-foo", "key-bar")) 

108 

109 >>> problem = Problem( 

110 >>> ProblemType.ISING, 

111 >>> linear={1: 3.14}, 

112 >>> quadratic={(1, 2): 10.08}, 

113 >>> ) 

114 >>> device = AwsQpu("arn:aws:aqx:::qpu:d-wave") 

115 >>> device.run(problem, ("bucket-foo", "key-bar"), 

116 >>> backend_parameters = {"dWaveParameters": {"postprocessingType": "SAMPLING"}}) 

117 

118 See Also: 

119 `braket.aws.aws_quantum_task.AwsQuantumTask.create()` 

120 """ 

121 

122 # TODO: Restrict execution to compatible task types 

123 return AwsQuantumTask.create( 

124 self._aws_session, 

125 self._arn, 

126 task_specification, 

127 s3_destination_folder, 

128 shots, 

129 poll_timeout_seconds=poll_timeout_seconds, 

130 poll_interval_seconds=poll_interval_seconds, 

131 *aws_quantum_task_args, 

132 **aws_quantum_task_kwargs, 

133 ) 

134 

135 def refresh_metadata(self) -> None: 

136 """ 

137 Refresh the `AwsQpu` object with the most recent QPU metadata. 

138 """ 

139 qpu_metadata = self._aws_session.get_qpu_metadata(self._arn) 

140 self._name = qpu_metadata.get("name") 

141 self._status = qpu_metadata.get("status") 

142 self._status_reason = qpu_metadata.get("statusReason") 

143 qpu_properties = qpu_metadata.get("properties") 

144 self._properties = ( 

145 qpu_properties.get("annealingModelProperties", {}).get("dWaveProperties") 

146 if "annealingModelProperties" in qpu_properties 

147 else qpu_properties.get("gateModelProperties") 

148 ) 

149 self._topology_graph = self._construct_topology_graph() 

150 

151 @property 

152 def arn(self) -> str: 

153 """str: Return the ARN of the QPU""" 

154 return self._arn 

155 

156 @property 

157 # TODO: Add a link to the boto3 docs 

158 def properties(self) -> Dict[str, Any]: 

159 """Dict[str, Any]: Return the QPU properties""" 

160 return self._properties 

161 

162 @property 

163 def topology_graph(self) -> Graph: 

164 """Graph: topology of QPU as a networkx Graph object 

165 

166 Examples: 

167 >>> import networkx as nx 

168 >>> device = AwsQpu("arn:aws:aqx:::qpu:rigetti") 

169 >>> nx.draw_kamada_kawai(device.topology_graph, with_labels=True, font_weight="bold") 

170 

171 >>> topology_subgraph = device.topology_graph.subgraph(range(8)) 

172 >>> nx.draw_kamada_kawai(topology_subgraph, with_labels=True, font_weight="bold") 

173 

174 >>> print(device.topology_graph.edges) 

175 """ 

176 return self._topology_graph 

177 

178 def _construct_topology_graph(self) -> Graph: 

179 """ 

180 Construct topology graph. If no such metadata is available, return None. 

181 

182 Returns: 

183 Graph: topology of QPU as a networkx Graph object 

184 """ 

185 if "connectivity" in self.properties: 

186 adjacency_lists = self.properties["connectivity"]["connectivityGraph"] 

187 edges = [] 

188 for item in adjacency_lists.items(): 

189 i = item[0] 

190 edges.extend([(int(i), int(j)) for j in item[1]]) 

191 if len(edges) == 0: # empty connectivity graph means fully connected 

192 return complete_graph(int(self.properties["qubitCount"])) 

193 else: 

194 return from_edgelist(edges) 

195 elif "couplers" in self.properties: 

196 edges = self.properties["couplers"] 

197 return from_edgelist(edges) 

198 else: 

199 return None 

200 

201 def _aws_session_for_qpu(self, qpu_arn: str, aws_session: AwsSession) -> AwsSession: 

202 """ 

203 Get an AwsSession for the QPU ARN. QPUs are physically located in specific AWS Regions. 

204 The AWS sessions should connect to the Region that the QPU is located in. 

205 

206 See `braket.aws.aws_qpu.AwsQpu.QPU_REGIONS` for the AWS Regions the QPUs are located in. 

207 """ 

208 

209 qpu_regions = AwsQpu.QPU_REGIONS.get(qpu_arn, []) 

210 if not qpu_regions: 

211 raise ValueError(f"Unknown QPU {qpu_arn} was supplied.") 

212 

213 if aws_session: 

214 if aws_session.boto_session.region_name in qpu_regions: 

215 return aws_session 

216 else: 

217 creds = aws_session.boto_session.get_credentials() 

218 boto_session = boto3.Session( 

219 aws_access_key_id=creds.access_key, 

220 aws_secret_access_key=creds.secret_key, 

221 aws_session_token=creds.token, 

222 region_name=qpu_regions[0], 

223 ) 

224 return AwsSession(boto_session=boto_session) 

225 else: 

226 boto_session = boto3.Session(region_name=qpu_regions[0]) 

227 return AwsSession(boto_session=boto_session) 

228 

229 def __repr__(self): 

230 return "QPU('name': {}, 'arn': {})".format(self.name, self.arn) 

231 

232 def __eq__(self, other): 

233 if isinstance(other, AwsQpu): 

234 return self.arn == other.arn 

235 return NotImplemented