def test_frozendict_api(): # all the read-only methods that are fine through_methods = [ '__class__', '__cmp__', '__contains__', '__delattr__', '__dir__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__or__', '__reduce__', '__reversed__', '__ror__', '__setattr__', '__sizeof__', '__str__', 'copy', 'get', 'has_key', 'items', 'iteritems', 'iterkeys', 'itervalues', 'keys', 'values', 'viewitems', 'viewkeys', 'viewvalues' ] fd = FrozenDict() ret = [] for attrname in dir(fd): if attrname == '_hash': # in the dir, even before it's set continue attr = getattr(fd, attrname) if not callable(attr): continue if getattr(FrozenDict, attrname) == getattr( dict, attrname, None) and attrname not in through_methods: assert attrname == False ret.append(attrname) import copy assert copy.copy(fd) is fd
def extract_deps(conn, sent, use_conllu_feats=False): for idx, tok in enumerate(sent): assert tok["id"] == idx + 1 tree = sent.to_tree() if use_conllu_feats: # XXX: Might be good add an option to combine both? lemma_map, all_lemma_feats = conllu_to_indexed(sent) else: lemma_map, all_lemma_feats = index_sentence( (token["form"] for token in sent)) tree_index = {} make_tree_index(tree, tree_index) for lemma_idx, key_lemma, word in iter_match_cands(conn, lemma_map, all_lemma_feats): lemma_id = lemma_idx + 1 used_cands = frozenset((lemma_id, )) if word["key_is_head"]: node = tree_index[lemma_idx] head_idx = node.token["head"] if head_idx != 0: used_cands |= frozenset((head_idx, )) matches = select_dep_step( all_lemma_feats, tree_index, word["subwords"], expand_node(tree_index, lemma_id), frozenset((lemma_id, )), frozenset((word["key_idx"], )), FrozenDict(((word["key_idx"], frozenset((lemma_idx, ))), )), ) if matches: yield matches, word
def step(dir): return select_tok_step( lambda n: n + dir, extend_wildcards, all_lemma_feats, subwords, lemma_idx + dir, word["key_idx"] + dir, FrozenDict(), )
def extract_toks_indexed( conn, lemma_map: Dict[str, int], all_lemma_feats: List[Dict[str, str]], extend_wildcards=True, ): key_lemmas, words = get_matchers(conn, lemma_map) for lemma_idx, key_lemma, word in iter_match_cands(conn, lemma_map, all_lemma_feats): # Check lemma and feats for other lemmas subwords = list(enumerate(word["subwords"])) def step(dir): return select_tok_step( lambda n: n + dir, extend_wildcards, all_lemma_feats, subwords, lemma_idx + dir, word["key_idx"] + dir, FrozenDict(), ) left_matches = step(-1) if not left_matches: continue right_matches = step(1) if not right_matches: continue key_matching = FrozenDict(((word["key_idx"], frozenset( (lemma_idx, ))), )) all_matches = { FrozenDict({ **left_matching, **key_matching, **right_matching }) for left_matching in left_matches for right_matching in right_matches } yield all_matches, word
def frozendict_order_insert(fd, new_key, new_value): new = [] inserted = False for existing_key, existing_value in fd.items(): if not inserted and existing_key == new_key: inserted = True new.append((existing_key, existing_value | frozenset( (new_value, )))) continue if not inserted and existing_key > new_key: inserted = True new.append((new_key, frozenset((new_value, )))) new.append((existing_key, existing_value)) if not inserted: new.append((new_key, frozenset((new_value, )))) return FrozenDict(new)
def parameters(self) -> FrozenDict[str, List]: """ FrozenDict[str, List]: Solver parameters in the form of a dict, where keys are keyword parameters in D-Wave format and values are lists of properties in :attr:`.BraketSampler.properties` for each key. `D-Wave System Documentation <https://docs.dwavesys.com/docs/latest/doc_solver_ref.html>`_ describes the parameters and properties supported on the D-Wave system. Solver parameters are dependent on the selected solver and subject to change; for example, new released features may add parameters. """ return FrozenDict({ param: ["parameters"] for param in BraketSolverMetadata.get_metadata_by_arn( self._device_arn)["parameters"] })
def properties(self) -> FrozenDict[str, Any]: """ FrozenDict[str, Any]: Solver properties in D-Wave format. `D-Wave System Documentation <https://docs.dwavesys.com/docs/latest/doc_solver_ref.html>`_ describes the parameters and properties supported on the D-Wave system. Solver properties are dependent on the selected solver and subject to change; for example, new released features may add properties. """ mapping_dict = BraketSolverMetadata.get_metadata_by_arn( self._device_arn)["properties"] return_dict = {} for top_level_key in mapping_dict: solver_dict = getattr(self.solver.properties, top_level_key).dict() for key in mapping_dict[top_level_key]: return_dict[mapping_dict[top_level_key][key]] = copy.deepcopy( solver_dict[key]) return FrozenDict(return_dict)
def test_frozendict_ior(): data = {'a': 'A', 'b': 'B'} fd = FrozenDict(data) with pytest.raises(TypeError, match=".*FrozenDicts are immutable.*"): fd |= fd
def test_frozendict(): efd = FrozenDict() assert isinstance(efd, dict) assert len(efd) == 0 assert not efd assert repr(efd) == "FrozenDict({})" data = {'a': 'A', 'b': 'B'} fd = FrozenDict(data) assert bool(fd) assert len(fd) == 2 assert fd['a'] == 'A' assert fd['b'] == 'B' assert sorted(fd.keys()) == ['a', 'b'] assert sorted(fd.values()) == ['A', 'B'] assert sorted(fd.items()) == [('a', 'A'), ('b', 'B')] assert 'a' in fd assert 'c' not in fd assert hash(fd) fd_map = {'fd': fd} assert fd_map['fd'] is fd with pytest.raises(TypeError): fd['c'] = 'C' with pytest.raises(TypeError): del fd['a'] with pytest.raises(TypeError): fd.update(x='X') with pytest.raises(TypeError): fd.setdefault('x', []) with pytest.raises(TypeError): fd.pop('c') with pytest.raises(TypeError): fd.popitem() with pytest.raises(TypeError): fd.clear() import pickle fkfd = FrozenDict.fromkeys([2, 4, 6], value=0) assert pickle.loads(pickle.dumps(fkfd)) == fkfd assert sorted(fkfd.updated({8: 0}).keys()) == [2, 4, 6, 8] # try something with an unhashable value unfd = FrozenDict({'a': ['A']}) with pytest.raises(TypeError) as excinfo: {unfd: 'val'} assert excinfo.type is FrozenHashError with pytest.raises(TypeError) as excinfo2: {unfd: 'val'} assert excinfo.value is excinfo2.value # test cached exception return
def delete_selected(dedup): """Remove all mails selected in-place, from their original boxes.""" for mail in dedup.selection: logger.debug(f"Deleting {mail!r} in-place...") dedup.stats["mail_deleted"] += 1 if dedup.conf.dry_run: logger.warning("DRY RUN: Skip action.") else: dedup.sources[mail.source_path].remove(mail.mail_id) logger.info(f"{mail!r} deleted.") ACTIONS = FrozenDict({ COPY_SELECTED: copy_selected, COPY_DISCARDED: None, MOVE_SELECTED: move_selected, MOVE_DISCARDED: None, DELETE_SELECTED: delete_selected, DELETE_DISCARDED: None, }) def perform_action(dedup): """Performs the action on selected mail candidates.""" logger.info(f"Perform {choice_style(dedup.conf.action)} action...") selection_count = len(dedup.selection) if selection_count == 0: logger.warning("No mail selected to perform action on.") return logger.info(f"{selection_count} mails selected for action.")
"""Precompute the mapping of all strategy IDs to their prefered method name, including aliases as fallbacks. """ methods = dict() for strategies in STRATEGY_ALIASES: fallback_method = None for strat_id in strategies: mid = get_method_id(strat_id) method = globals().get(mid) if method: fallback_method = method if not fallback_method: raise NotImplementedError(f"Can't find {mid}() method.") methods[strat_id] = fallback_method return methods STRATEGY_METHODS = FrozenDict(build_method_mapping()) def apply_strategy(strat_id, duplicates): """Perform the selection strategy on the provided duplicate set. Returns a set of selected mails objects. """ if strat_id not in STRATEGY_METHODS: raise ValueError(f"Unknown {strat_id} strategy.") method = STRATEGY_METHODS[strat_id] logger.debug(f"Apply {method!r}...") return set(method(duplicates))
def is_macos(): """ Return `True` only if current platform is of the macOS family. """ return sys.platform == 'darwin' def is_windows(): """ Return `True` only if current platform is of the Windows family. """ return sys.platform in ['win32', 'cygwin'] # Map OS IDs to evaluation function and OS labels. OS_DEFINITIONS = FrozenDict({ LINUX: ('Linux', is_linux()), MACOS: ('macOS', is_macos()), WINDOWS: ('Windows', is_windows()) }) # Generare sets of recognized IDs and labels. ALL_OS_LABELS = frozenset([label for label, _ in OS_DEFINITIONS.values()]) def os_label(os_id): """ Return platform label for user-friendly output. """ return OS_DEFINITIONS[os_id][0] logger.debug(f"Raw platform ID: {sys.platform}.")
class AwsDevice(Device): """ Amazon Braket implementation of a device. Use this class to retrieve the latest metadata about the device and to run a quantum task on the device. """ SIMULATOR_ARNS = frozenset({ "arn:aws:braket:::device/quantum-simulator/amazon/sv1", "arn:aws:braket:::device/quantum-simulator/amazon/tn1", }) QPU_REGIONS = FrozenDict({ "arn:aws:braket:::device/qpu/rigetti/Aspen-8": "us-west-1", "arn:aws:braket:::device/qpu/ionq/ionQdevice": "us-east-1", "arn:aws:braket:::device/qpu/d-wave/DW_2000Q_6": "us-west-2", "arn:aws:braket:::device/qpu/d-wave/Advantage_system1": "us-west-2", }) REGIONS = frozenset(QPU_REGIONS.values()) DEFAULT_SHOTS_QPU = 1000 DEFAULT_SHOTS_SIMULATOR = 0 DEFAULT_MAX_PARALLEL = 10 _GET_DEVICES_ORDER_BY_KEYS = frozenset( {"arn", "name", "type", "provider_name", "status"}) def __init__(self, arn: str, aws_session: Optional[AwsSession] = None): """ Args: arn (str): The ARN of the device aws_session (AwsSession, optional): An AWS session object. Default is `None`. Note: Some devices (QPUs) are physically located in specific AWS Regions. In some cases, the current `aws_session` connects to a Region other than the Region in which the QPU is physically located. When this occurs, a cloned `aws_session` is created for the Region the QPU is located in. See `braket.aws.aws_device.AwsDevice.DEVICE_REGIONS` for the AWS Regions provider devices are located in. """ super().__init__(name=None, status=None) self._arn = arn self._aws_session = AwsDevice._aws_session_for_device(arn, aws_session) self._properties = None self._provider_name = None self._topology_graph = None self._type = None self.refresh_metadata() def run( self, task_specification: Union[Circuit, Problem], s3_destination_folder: AwsSession.S3DestinationFolder, shots: Optional[int] = None, poll_timeout_seconds: float = AwsQuantumTask. DEFAULT_RESULTS_POLL_TIMEOUT, poll_interval_seconds: float = AwsQuantumTask. DEFAULT_RESULTS_POLL_INTERVAL, *aws_quantum_task_args, **aws_quantum_task_kwargs, ) -> AwsQuantumTask: """ Run a quantum task specification on this device. A task can be a circuit or an annealing problem. Args: task_specification (Union[Circuit, Problem]): Specification of task (circuit or annealing problem) to run on device. s3_destination_folder: The S3 location to save the task's results to. shots (int, optional): The number of times to run the circuit or annealing problem. Default is 1000 for QPUs and 0 for simulators. poll_timeout_seconds (float): The polling timeout for `AwsQuantumTask.result()`, in seconds. Default: 5 days. poll_interval_seconds (float): The polling interval for `AwsQuantumTask.result()`, in seconds. Default: 1 second. *aws_quantum_task_args: Variable length positional arguments for `braket.aws.aws_quantum_task.AwsQuantumTask.create()`. **aws_quantum_task_kwargs: Variable length keyword arguments for `braket.aws.aws_quantum_task.AwsQuantumTask.create()`. Returns: AwsQuantumTask: An AwsQuantumTask that tracks the execution on the device. Examples: >>> circuit = Circuit().h(0).cnot(0, 1) >>> device = AwsDevice("arn1") >>> device.run(circuit, ("bucket-foo", "key-bar")) >>> circuit = Circuit().h(0).cnot(0, 1) >>> device = AwsDevice("arn2") >>> device.run(task_specification=circuit, >>> s3_destination_folder=("bucket-foo", "key-bar")) >>> circuit = Circuit().h(0).cnot(0, 1) >>> device = AwsDevice("arn3") >>> device.run(task_specification=circuit, >>> s3_destination_folder=("bucket-foo", "key-bar"), disable_qubit_rewiring=True) >>> problem = Problem( >>> ProblemType.ISING, >>> linear={1: 3.14}, >>> quadratic={(1, 2): 10.08}, >>> ) >>> device = AwsDevice("arn4") >>> device.run(problem, ("bucket-foo", "key-bar"), >>> device_parameters={ >>> "providerLevelParameters": {"postprocessingType": "SAMPLING"}} >>> ) See Also: `braket.aws.aws_quantum_task.AwsQuantumTask.create()` """ return AwsQuantumTask.create( self._aws_session, self._arn, task_specification, s3_destination_folder, shots if shots is not None else self._default_shots, poll_timeout_seconds=poll_timeout_seconds, poll_interval_seconds=poll_interval_seconds, *aws_quantum_task_args, **aws_quantum_task_kwargs, ) def run_batch( self, task_specifications: List[Union[Circuit, Problem]], s3_destination_folder: AwsSession.S3DestinationFolder, shots: Optional[int] = None, max_parallel: Optional[int] = None, max_connections: int = AwsQuantumTaskBatch.MAX_CONNECTIONS_DEFAULT, poll_timeout_seconds: float = AwsQuantumTask. DEFAULT_RESULTS_POLL_TIMEOUT, poll_interval_seconds: float = AwsQuantumTask. DEFAULT_RESULTS_POLL_INTERVAL, *aws_quantum_task_args, **aws_quantum_task_kwargs, ) -> AwsQuantumTaskBatch: """Executes a batch of tasks in parallel Args: task_specifications (List[Union[Circuit, Problem]]): List of circuits or annealing problems to run on device. s3_destination_folder: The S3 location to save the tasks' results to. shots (int, optional): The number of times to run the circuit or annealing problem. Default is 1000 for QPUs and 0 for simulators. max_parallel (int, optional): The maximum number of tasks to run on AWS in parallel. Batch creation will fail if this value is greater than the maximum allowed concurrent tasks on the device. Default: 10 max_connections (int): The maximum number of connections in the Boto3 connection pool. Also the maximum number of thread pool workers for the batch. Default: 100 poll_timeout_seconds (float): The polling timeout for `AwsQuantumTask.result()`, in seconds. Default: 5 days. poll_interval_seconds (float): The polling interval for results in seconds. Default: 1 second. *aws_quantum_task_args: Variable length positional arguments for `braket.aws.aws_quantum_task.AwsQuantumTask.create()`. **aws_quantum_task_kwargs: Variable length keyword arguments for `braket.aws.aws_quantum_task.AwsQuantumTask.create()`. Returns: AwsQuantumTaskBatch: A batch containing all of the tasks run See Also: `braket.aws.aws_quantum_task_batch.AwsQuantumTaskBatch` """ return AwsQuantumTaskBatch( AwsDevice._copy_aws_session(self._aws_session, max_connections=max_connections), self._arn, task_specifications, s3_destination_folder, shots if shots is not None else self._default_shots, max_parallel=max_parallel if max_parallel is not None else self._default_max_parallel, max_workers=max_connections, poll_timeout_seconds=poll_timeout_seconds, poll_interval_seconds=poll_interval_seconds, *aws_quantum_task_args, **aws_quantum_task_kwargs, ) def refresh_metadata(self) -> None: """ Refresh the `AwsDevice` object with the most recent Device metadata. """ metadata = self._aws_session.get_device(self._arn) self._name = metadata.get("deviceName") self._status = metadata.get("deviceStatus") self._type = AwsDeviceType(metadata.get("deviceType")) self._provider_name = metadata.get("providerName") qpu_properties = metadata.get("deviceCapabilities") self._properties = BraketSchemaBase.parse_raw_schema(qpu_properties) self._topology_graph = self._construct_topology_graph() @property def type(self) -> str: """str: Return the device type""" return self._type @property def provider_name(self) -> str: """str: Return the provider name""" return self._provider_name @property def arn(self) -> str: """str: Return the ARN of the device""" return self._arn @property # TODO: Add a link to the boto3 docs def properties(self) -> DeviceCapabilities: """DeviceCapabilities: Return the device properties Please see `braket.device_schema` in amazon-braket-schemas-python_ .. _amazon-braket-schemas-python: https://github.com/aws/amazon-braket-schemas-python""" return self._properties @property def topology_graph(self) -> Graph: """Graph: topology of device as a networkx `Graph` object. Returns `None` if the topology is not available for the device. Examples: >>> import networkx as nx >>> device = AwsDevice("arn1") >>> nx.draw_kamada_kawai(device.topology_graph, with_labels=True, font_weight="bold") >>> topology_subgraph = device.topology_graph.subgraph(range(8)) >>> nx.draw_kamada_kawai(topology_subgraph, with_labels=True, font_weight="bold") >>> print(device.topology_graph.edges) """ return self._topology_graph def _construct_topology_graph(self) -> Graph: """ Construct topology graph. If no such metadata is available, return `None`. Returns: Graph: topology of QPU as a networkx `Graph` object. """ if hasattr(self.properties, "paradigm") and isinstance( self.properties.paradigm, GateModelQpuParadigmProperties): if self.properties.paradigm.connectivity.fullyConnected: return complete_graph(int(self.properties.paradigm.qubitCount)) adjacency_lists = self.properties.paradigm.connectivity.connectivityGraph edges = [] for item in adjacency_lists.items(): i = item[0] edges.extend([(int(i), int(j)) for j in item[1]]) return from_edgelist(edges) elif hasattr(self.properties, "provider") and isinstance( self.properties.provider, DwaveProviderProperties): edges = self.properties.provider.couplers return from_edgelist(edges) else: return None @property def _default_shots(self): return (AwsDevice.DEFAULT_SHOTS_QPU if "qpu" in self.arn else AwsDevice.DEFAULT_SHOTS_SIMULATOR) @property def _default_max_parallel(self): return AwsDevice.DEFAULT_MAX_PARALLEL @staticmethod def _aws_session_for_device( device_arn: str, aws_session: Optional[AwsSession]) -> AwsSession: """AwsSession: Returns an AwsSession for the device ARN.""" if "qpu" in device_arn: return AwsDevice._aws_session_for_qpu(device_arn, aws_session) else: return aws_session or AwsSession() @staticmethod def _aws_session_for_qpu(device_arn: str, aws_session: Optional[AwsSession]) -> AwsSession: """ Get an AwsSession for the device ARN. QPUs are physically located in specific AWS Regions. The AWS sessions should connect to the Region that the QPU is located in. See `braket.aws.aws_qpu.AwsDevice.DEVICE_REGIONS` for the AWS Regions the devices are located in. """ if device_arn in AwsDevice.QPU_REGIONS: return AwsDevice._copy_aws_session( aws_session, AwsDevice.QPU_REGIONS.get(device_arn), None) # If the QPU is unknown, search until it is found. device_sessions = AwsDevice._get_arn_sessions([device_arn], None, {AwsDeviceType.QPU}, None, None, aws_session) if device_sessions: return device_sessions[device_arn] raise ValueError(f"QPU {device_arn} not found") @staticmethod def _copy_aws_session( aws_session: Optional[AwsSession], region: Optional[str] = None, max_connections: Optional[int] = None, ) -> AwsSession: config = Config( max_pool_connections=max_connections) if max_connections else None if aws_session: session_region = aws_session.boto_session.region_name new_region = region or session_region if session_region == new_region and not config: return aws_session else: creds = aws_session.boto_session.get_credentials() boto_session = boto3.Session( aws_access_key_id=creds.access_key, aws_secret_access_key=creds.secret_key, aws_session_token=creds.token, region_name=new_region, ) return AwsSession(boto_session=boto_session, config=config) else: boto_session = boto3.Session( region_name=region) if region else None return AwsSession(boto_session=boto_session, config=config) def __repr__(self): return "Device('name': {}, 'arn': {})".format(self.name, self.arn) def __eq__(self, other): if isinstance(other, AwsDevice): return self.arn == other.arn return NotImplemented @staticmethod def get_devices( arns: Optional[List[str]] = None, names: Optional[List[str]] = None, types: Optional[List[AwsDeviceType]] = None, statuses: Optional[List[str]] = None, provider_names: Optional[List[str]] = None, order_by: str = "name", aws_session: Optional[AwsSession] = None, ) -> List[AwsDevice]: """ Get devices based on filters and desired ordering. The result is the AND of all the filters `arns`, `names`, `types`, `statuses`, `provider_names`. Examples: >>> AwsDevice.get_devices(provider_names=['Rigetti'], statuses=['ONLINE']) >>> AwsDevice.get_devices(order_by='provider_name') >>> AwsDevice.get_devices(types=['SIMULATOR']) Args: arns (List[str], optional): device ARN list, default is `None` names (List[str], optional): device name list, default is `None` types (List[AwsDeviceType], optional): device type list, default is `None` QPUs will be searched for all regions and simulators will only be searched for the region of the current session. statuses (List[str], optional): device status list, default is `None` provider_names (List[str], optional): provider name list, default is `None` order_by (str, optional): field to order result by, default is `name`. Accepted values are ['arn', 'name', 'type', 'provider_name', 'status'] aws_session (AwsSession, optional) aws_session: An AWS session object. Default is `None`. Returns: List[AwsDevice]: list of AWS devices """ if order_by not in AwsDevice._GET_DEVICES_ORDER_BY_KEYS: raise ValueError( f"order_by '{order_by}' must be in {AwsDevice._GET_DEVICES_ORDER_BY_KEYS}" ) types = (frozenset(types) if types else frozenset( {device_type for device_type in AwsDeviceType})) arn_sessions = AwsDevice._get_arn_sessions(arns, names, types, statuses, provider_names, aws_session) devices = [AwsDevice(arn, arn_sessions[arn]) for arn in arn_sessions] devices.sort(key=lambda x: getattr(x, order_by)) return devices @staticmethod def _get_arn_sessions(arns, names, types, statuses, provider_names, aws_session): aws_session = aws_session if aws_session else AwsSession() sessions_for_arns = {} session_region = aws_session.boto_session.region_name device_regions_set = AwsDevice._get_devices_regions_set( types, arns, session_region) for region in device_regions_set: session_for_region = AwsDevice._copy_aws_session( aws_session, region) # Simulators are only instantiated in the same region as the AWS session types_for_region = sorted(types if region == session_region else types - {AwsDeviceType.SIMULATOR}) region_device_arns = [ result["deviceArn"] for result in session_for_region.search_devices( arns=arns, names=names, types=types_for_region, statuses=statuses, provider_names=provider_names, ) ] sessions_for_arns.update({ arn: session_for_region for arn in region_device_arns if arn not in sessions_for_arns }) return sessions_for_arns @staticmethod def _get_devices_regions_set(types: Optional[Set[AwsDeviceType]], arns: Optional[List[str]], current_region: str) -> FrozenSet[str]: """Get the set of regions to call `SearchDevices` API given filters""" device_regions_set = ({current_region} if types == { AwsDeviceType.SIMULATOR } else set(AwsDevice.REGIONS)) if arns: arns_region_set = set() for arn in arns: if arn in AwsDevice.QPU_REGIONS: arns_region_set.add(AwsDevice.QPU_REGIONS[arn]) elif arn in AwsDevice.SIMULATOR_ARNS: arns_region_set.add(current_region) else: arns_region_set.update(AwsDevice.REGIONS) device_regions_set &= arns_region_set return frozenset(device_regions_set)
class AwsDevice(Device): """ Amazon Braket implementation of a device. Use this class to retrieve the latest metadata about the device and to run a quantum task on the device. """ DEVICE_REGIONS = FrozenDict({ "rigetti": ["us-west-1"], "ionq": ["us-east-1"], "d-wave": ["us-west-2"], "amazon": ["us-west-2", "us-west-1", "us-east-1"], }) DEFAULT_SHOTS_QPU = 1000 DEFAULT_SHOTS_SIMULATOR = 0 DEFAULT_RESULTS_POLL_TIMEOUT = 432000 DEFAULT_RESULTS_POLL_INTERVAL = 1 def __init__(self, arn: str, aws_session: Optional[AwsSession] = None): """ Args: arn (str): The ARN of the device aws_session (AwsSession, optional) aws_session: An AWS session object. Default = None. Note: Some devices (QPUs) are physically located in specific AWS Regions. In some cases, the current `aws_session` connects to a Region other than the Region in which the QPU is physically located. When this occurs, a cloned `aws_session` is created for the Region the QPU is located in. See `braket.aws.aws_device.AwsDevice.DEVICE_REGIONS` for the AWS Regions provider devices are located in. """ super().__init__(name=None, status=None) self._arn = arn self._aws_session = AwsDevice._aws_session_for_device(arn, aws_session) self._properties = None self._provider_name = None self._type = None self.refresh_metadata() def run( self, task_specification: Union[Circuit, Problem], s3_destination_folder: AwsSession.S3DestinationFolder, shots: Optional[int] = None, poll_timeout_seconds: Optional[int] = DEFAULT_RESULTS_POLL_TIMEOUT, poll_interval_seconds: Optional[int] = DEFAULT_RESULTS_POLL_INTERVAL, *aws_quantum_task_args, **aws_quantum_task_kwargs, ) -> AwsQuantumTask: """ Run a quantum task specification on this device. A task can be a circuit or an annealing problem. Args: task_specification (Union[Circuit, Problem]): Specification of task (circuit or annealing problem) to run on device. s3_destination_folder: The S3 location to save the task's results shots (int, optional): The number of times to run the circuit or annealing problem. Default is 1000 for QPUs and 0 for simulators. poll_timeout_seconds (int): The polling timeout for AwsQuantumTask.result(), in seconds. Default: 5 days. poll_interval_seconds (int): The polling interval for AwsQuantumTask.result(), in seconds. Default: 1 second. *aws_quantum_task_args: Variable length positional arguments for `braket.aws.aws_quantum_task.AwsQuantumTask.create()`. **aws_quantum_task_kwargs: Variable length keyword arguments for `braket.aws.aws_quantum_task.AwsQuantumTask.create()`. Returns: AwsQuantumTask: An AwsQuantumTask that tracks the execution on the device. Examples: >>> circuit = Circuit().h(0).cnot(0, 1) >>> device = AwsDevice("arn1") >>> device.run(circuit, ("bucket-foo", "key-bar")) >>> circuit = Circuit().h(0).cnot(0, 1) >>> device = AwsDevice("arn2") >>> device.run(task_specification=circuit, >>> s3_destination_folder=("bucket-foo", "key-bar")) >>> problem = Problem( >>> ProblemType.ISING, >>> linear={1: 3.14}, >>> quadratic={(1, 2): 10.08}, >>> ) >>> device = AwsDevice("arn3") >>> device.run(problem, ("bucket-foo", "key-bar"), >>> device_parameters={ >>> "providerLevelParameters": {"postprocessingType": "SAMPLING"}} >>> ) See Also: `braket.aws.aws_quantum_task.AwsQuantumTask.create()` """ if shots is None: if "qpu" in self.arn: shots = AwsDevice.DEFAULT_SHOTS_QPU else: shots = AwsDevice.DEFAULT_SHOTS_SIMULATOR return AwsQuantumTask.create( self._aws_session, self._arn, task_specification, s3_destination_folder, shots, poll_timeout_seconds=poll_timeout_seconds, poll_interval_seconds=poll_interval_seconds, *aws_quantum_task_args, **aws_quantum_task_kwargs, ) def refresh_metadata(self) -> None: """ Refresh the `AwsDevice` object with the most recent Device metadata. """ metadata = self._aws_session.get_device(self._arn) self._name = metadata.get("deviceName") self._status = metadata.get("deviceStatus") self._type = AwsDeviceType(metadata.get("deviceType")) self._provider_name = metadata.get("providerName") qpu_properties = metadata.get("deviceCapabilities") self._properties = BraketSchemaBase.parse_raw_schema(qpu_properties) self._topology_graph = self._construct_topology_graph() @property def type(self) -> str: """str: Return the device type""" return self._type @property def provider_name(self) -> str: """str: Return the provider name""" return self._provider_name @property def arn(self) -> str: """str: Return the ARN of the device""" return self._arn @property # TODO: Add a link to the boto3 docs def properties(self) -> DeviceCapabilities: """DeviceCapabilities: Return the device properties Please see `braket.device_schema` in amazon-braket-schemas-python_ .. _amazon-braket-schemas-python: https://github.com/aws/amazon-braket-schemas-python""" return self._properties @property def topology_graph(self) -> Graph: """Graph: topology of device as a networkx Graph object. Returns None if the topology is not available for the device. Examples: >>> import networkx as nx >>> device = AwsDevice("arn1") >>> nx.draw_kamada_kawai(device.topology_graph, with_labels=True, font_weight="bold") >>> topology_subgraph = device.topology_graph.subgraph(range(8)) >>> nx.draw_kamada_kawai(topology_subgraph, with_labels=True, font_weight="bold") >>> print(device.topology_graph.edges) """ return self._topology_graph def _construct_topology_graph(self) -> Graph: """ Construct topology graph. If no such metadata is available, return None. Returns: Graph: topology of QPU as a networkx Graph object """ if hasattr(self.properties, "paradigm") and isinstance( self.properties.paradigm, GateModelQpuParadigmProperties): if self.properties.paradigm.connectivity.fullyConnected: return complete_graph(int(self.properties.paradigm.qubitCount)) adjacency_lists = self.properties.paradigm.connectivity.connectivityGraph edges = [] for item in adjacency_lists.items(): i = item[0] edges.extend([(int(i), int(j)) for j in item[1]]) return from_edgelist(edges) elif hasattr(self.properties, "provider") and isinstance( self.properties.provider, DwaveProviderProperties): edges = self.properties.provider.couplers return from_edgelist(edges) else: return None @staticmethod def _aws_session_for_device( device_arn: str, aws_session: Optional[AwsSession]) -> AwsSession: """AwsSession: Returns an AwsSession for the device ARN. """ if "qpu" in device_arn: return AwsDevice._aws_session_for_qpu(device_arn, aws_session) else: return aws_session or AwsSession() @staticmethod def _aws_session_for_qpu(device_arn: str, aws_session: Optional[AwsSession]) -> AwsSession: """ Get an AwsSession for the device ARN. QPUs are physically located in specific AWS Regions. The AWS sessions should connect to the Region that the QPU is located in. See `braket.aws.aws_qpu.AwsDevice.DEVICE_REGIONS` for the AWS Regions the devices are located in. """ region_key = device_arn.split("/")[-2] qpu_regions = AwsDevice.DEVICE_REGIONS.get(region_key, []) return AwsDevice._copy_aws_session(aws_session, qpu_regions) @staticmethod def _copy_aws_session(aws_session: Optional[AwsSession], regions: List[str]) -> AwsSession: if aws_session: if aws_session.boto_session.region_name in regions: return aws_session else: creds = aws_session.boto_session.get_credentials() boto_session = boto3.Session( aws_access_key_id=creds.access_key, aws_secret_access_key=creds.secret_key, aws_session_token=creds.token, region_name=regions[0], ) return AwsSession(boto_session=boto_session) else: boto_session = boto3.Session(region_name=regions[0]) return AwsSession(boto_session=boto_session) def __repr__(self): return "Device('name': {}, 'arn': {})".format(self.name, self.arn) def __eq__(self, other): if isinstance(other, AwsDevice): return self.arn == other.arn return NotImplemented @staticmethod def get_devices( arns: Optional[List[str]] = None, names: Optional[List[str]] = None, types: Optional[List[AwsDeviceType]] = None, statuses: Optional[List[str]] = None, provider_names: Optional[List[str]] = None, order_by: str = "name", aws_session: Optional[AwsSession] = None, ) -> List[AwsDevice]: """ Get devices based on filters and desired ordering. The result is the AND of all the filters `arns`, `names`, `types`, `statuses`, `provider_names`. Examples: >>> AwsDevice.get_devices(provider_names=['Rigetti'], statuses=['ONLINE']) >>> AwsDevice.get_devices(order_by='provider_name') >>> AwsDevice.get_devices(types=['SIMULATOR']) Args: arns (List[str], optional): device ARN list, default is `None` names (List[str], optional): device name list, default is `None` types (List[AwsDeviceType], optional): device type list, default is `None` statuses (List[str], optional): device status list, default is `None` provider_names (List[str], optional): provider name list, default is `None` order_by (str, optional): field to order result by, default is `name`. Accepted values are ['arn', 'name', 'type', 'provider_name', 'status'] aws_session (AwsSession, optional) aws_session: An AWS session object. Default = None. Returns: List[AwsDevice]: list of AWS devices """ order_by_list = ["arn", "name", "type", "provider_name", "status"] if order_by not in order_by_list: raise ValueError( f"order_by '{order_by}' must be in {order_by_list}") device_regions_set = AwsDevice._get_devices_regions_set( arns, provider_names, types) results = [] for region in device_regions_set: aws_session = AwsDevice._copy_aws_session(aws_session, [region]) results.extend( aws_session.search_devices( arns=arns, names=names, types=types, statuses=statuses, provider_names=provider_names, )) arns = set([result["deviceArn"] for result in results]) devices = [AwsDevice(arn, aws_session) for arn in arns] devices.sort(key=lambda x: getattr(x, order_by)) return devices @staticmethod def _get_devices_regions_set( arns: Optional[List[str]], provider_names: Optional[List[str]], types: Optional[List[AwsDeviceType]], ) -> Set[str]: """Get the set of regions to call `SearchDevices` API given filters""" device_regions_set = set(AwsDevice.DEVICE_REGIONS[key][0] for key in AwsDevice.DEVICE_REGIONS) if provider_names: provider_region_set = set() for provider in provider_names: for key in AwsDevice.DEVICE_REGIONS: if key in provider.lower(): provider_region_set.add( AwsDevice.DEVICE_REGIONS[key][0]) break device_regions_set = device_regions_set.intersection( provider_region_set) if arns: arns_region_set = set([ AwsDevice.DEVICE_REGIONS[arn.split("/")[-2]][0] for arn in arns ]) device_regions_set = device_regions_set.intersection( arns_region_set) if types and types == [AwsDeviceType.SIMULATOR]: device_regions_set = device_regions_set.intersection( [AwsDevice.DEVICE_REGIONS["amazon"][0]]) return device_regions_set
f"Extend the default message factory for {klass} with " "our own ``DedupMail`` class to add deduplication utilities." }, ) # Set our own custom factory and safety options to default constructor. constructor = partial(klass, factory=factory_klass, create=False) # Generates our own box_type_id for use in CLI parameters. box_type_id = klass.__name__.lower() yield box_type_id, constructor # Mapping between supported box type IDs and their constructors. BOX_TYPES = FrozenDict(build_box_constructors()) # Categorize each box type into its structure type. BOX_STRUCTURES = FrozenDict({ "file": {"mbox", "mmdf", "babyl"}, "folder": {"maildir", "mh"}, }) # Check we did not forgot any box type. assert set(flatten(BOX_STRUCTURES.values())) == set(BOX_TYPES) # List of required sub-folders defining a properly structured maildir. MAILDIR_SUBDIRS = frozenset(("cur", "new", "tmp")) def autodetect_box_type(path): """Auto-detect the format of the mailbox located at the provided path.