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 def __init__(self, arn: str, aws_session=None): 

40 """ 

41 Args: 

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

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

44 

45 Raises: 

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

47 

48 Note: 

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

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

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

52 the QPU is located in. 

53 

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

55 in. 

56 """ 

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

58 self._arn = arn 

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

60 self._properties = None 

61 self.refresh_metadata() 

62 

63 def run( 

64 self, 

65 task_specification: Union[Circuit, Problem], 

66 s3_destination_folder: AwsSession.S3DestinationFolder, 

67 shots: int = 1000, 

68 *aws_quantum_task_args, 

69 **aws_quantum_task_kwargs, 

70 ) -> AwsQuantumTask: 

71 """ 

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

73 annealing problem. 

74 

75 Args: 

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

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

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

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

80 Default is 1000. 

81 *aws_quantum_task_args: Variable length positional arguments for 

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

83 **aws_quantum_task_kwargs: Variable length keyword arguments for 

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

85 

86 Returns: 

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

88 

89 Examples: 

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

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

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

93 

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

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

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

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

98 

99 >>> problem = Problem( 

100 >>> ProblemType.ISING, 

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

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

103 >>> ) 

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

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

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

107 

108 See Also: 

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

110 """ 

111 

112 # TODO: Restrict execution to compatible task types 

113 return AwsQuantumTask.create( 

114 self._aws_session, 

115 self._arn, 

116 task_specification, 

117 s3_destination_folder, 

118 shots, 

119 *aws_quantum_task_args, 

120 **aws_quantum_task_kwargs, 

121 ) 

122 

123 def refresh_metadata(self) -> None: 

124 """ 

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

126 """ 

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

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

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

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

131 qpu_properties = qpu_metadata.get("properties") 

132 self._properties = ( 

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

134 if "annealingModelProperties" in qpu_properties 

135 else qpu_properties.get("gateModelProperties") 

136 ) 

137 self._topology_graph = self._construct_topology_graph() 

138 

139 @property 

140 def arn(self) -> str: 

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

142 return self._arn 

143 

144 @property 

145 # TODO: Add a link to the boto3 docs 

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

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

148 return self._properties 

149 

150 @property 

151 def topology_graph(self) -> Graph: 

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

153 

154 Examples: 

155 >>> import networkx as nx 

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

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

158 

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

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

161 

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

163 """ 

164 return self._topology_graph 

165 

166 def _construct_topology_graph(self) -> Graph: 

167 """ 

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

169 

170 Returns: 

171 Graph: topology of QPU as a networkx Graph object 

172 """ 

173 if "connectivity" in self.properties: 

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

175 edges = [] 

176 for item in adjacency_lists.items(): 

177 i = item[0] 

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

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

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

181 else: 

182 return from_edgelist(edges) 

183 elif "couplers" in self.properties: 

184 edges = self.properties["couplers"] 

185 return from_edgelist(edges) 

186 else: 

187 return None 

188 

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

190 """ 

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

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

193 

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

195 """ 

196 

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

198 if not qpu_regions: 

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

200 

201 if aws_session: 

202 if aws_session.boto_session.region_name in qpu_regions: 

203 return aws_session 

204 else: 

205 creds = aws_session.boto_session.get_credentials() 

206 boto_session = boto3.Session( 

207 aws_access_key_id=creds.access_key, 

208 aws_secret_access_key=creds.secret_key, 

209 aws_session_token=creds.token, 

210 region_name=qpu_regions[0], 

211 ) 

212 return AwsSession(boto_session=boto_session) 

213 else: 

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

215 return AwsSession(boto_session=boto_session) 

216 

217 def __repr__(self): 

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

219 

220 def __eq__(self, other): 

221 if isinstance(other, AwsQpu): 

222 return self.arn == other.arn 

223 return NotImplemented