Coverage for src/braket/circuits/result_type.py : 100%

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.
13from __future__ import annotations
15from typing import Any, Dict
17from braket.circuits.observable import Observable
18from braket.circuits.qubit import QubitInput
19from braket.circuits.qubit_set import QubitSet, QubitSetInput
22class ResultType:
23 """
24 Class `ResultType` represents a requested result type for the circuit.
25 This class is considered the result type definition containing
26 the metadata that defines what a requested result type is and what it does.
27 """
29 def __init__(self, ascii_symbol: str):
30 """
31 Args:
32 ascii_symbol (str): ASCII string symbol for the result type. This is used when
33 printing a diagram of circuits.
35 Raises:
36 ValueError: `ascii_symbol` is None
37 """
39 if ascii_symbol is None:
40 raise ValueError(f"ascii_symbol must not be None")
42 self._ascii_symbol = ascii_symbol
44 @property
45 def ascii_symbol(self) -> str:
46 """str: Returns the ascii symbol for the requested result type."""
47 return self._ascii_symbol
49 @property
50 def name(self) -> str:
51 """
52 Returns the name of the result type
54 Returns:
55 The name of the result type as a string
56 """
57 return self.__class__.__name__
59 def to_ir(self, *args, **kwargs) -> Any:
60 """Returns IR object of the result type
62 Args:
63 *args: Positional arguments
64 **kwargs: Keyword arguments
66 Returns:
67 IR object of the result type
68 """
69 raise NotImplementedError("to_ir has not been implemented yet.")
71 def copy(self, target_mapping: Dict[QubitInput, QubitInput] = {}, target: QubitSetInput = None):
72 """
73 Return a shallow copy of the result type.
75 Note:
76 If `target_mapping` is specified, then `self.target` is mapped to the specified
77 qubits. This is useful apply an instruction to a circuit and change the target qubits.
79 Args:
80 target_mapping (dictionary[int or Qubit, int or Qubit], optional): A dictionary of
81 qubit mappings to apply to the target. Key is the qubit in this `target` and the
82 value is what the key is changed to. Default = {}.
83 target (int, Qubit, or iterable of int / Qubit, optional): Target qubits for the new
84 instruction.
86 Returns:
87 ResultType: A shallow copy of the result type.
89 Raises:
90 TypeError: If both `target_mapping` and `target` are supplied.
92 Examples:
93 >>> result_type = ResultType.Probabilities(targets=[0])
94 >>> new_result_type = result_type.copy()
95 >>> new_result_type.targets
96 QubitSet(Qubit(0))
97 >>> new_result = result_type.copy(target_mapping={0: 5})
98 >>> new_result_type.target
99 QubitSet(Qubit(5))
100 >>> new_result = result_type.copy(target=[5])
101 >>> new_result_type.target
102 QubitSet(Qubit(5))
103 """
104 copy = self.__copy__()
105 if target_mapping and target is not None:
106 raise TypeError("Only 'target_mapping' or 'target' can be supplied, but not both.")
107 elif target is not None:
108 if hasattr(copy, "target"):
109 copy.target = target
110 else:
111 if hasattr(copy, "target"):
112 copy.target = self._target.map(target_mapping)
113 return copy
115 @classmethod
116 def register_result_type(cls, result_type: "ResultType"):
117 """Register a result type implementation by adding it into the ResultType class.
119 Args:
120 result_type (ResultType): ResultType instance to register.
121 """
122 setattr(cls, result_type.__name__, result_type)
124 def __repr__(self) -> str:
125 return f"{self.name}()"
128class ObservableResultType(ResultType):
129 """
130 Result types with observables and targets.
131 If no targets are specified, the observable must only operate on 1 qubit and it
132 will be applied to all qubits in parallel. Otherwise, the number of specified targets
133 must be equivalent to the number of qubits the observable can be applied to.
135 See :mod:`braket.circuits.observables` module for all of the supported observables.
136 """
138 def __init__(self, ascii_symbol: str, observable: Observable, target: QubitSetInput = None):
139 """
140 Args:
141 observable (Observable): the observable for the result type
142 target (int, Qubit, or iterable of int / Qubit, optional): Target qubits that the
143 result type is requested for. Default is None, which means the observable must
144 only operate on 1 qubit and it will be applied to all qubits in parallel
146 Raises:
147 ValueError: If the observable's qubit count and the number of target qubits
148 are not equal. Or, if target=None and the observable's qubit count is not 1.
149 """
150 super().__init__(ascii_symbol)
151 self._observable = observable
152 self._target = QubitSet(target)
153 if not self._target:
154 if self._observable.qubit_count != 1:
155 raise ValueError(
156 f"Observable {self._observable} must only operate on 1 qubit for target=None"
157 )
158 elif self._observable.qubit_count != len(self._target):
159 raise ValueError(
160 f"Observable's qubit count and the number of target qubits must be equal"
161 )
163 @property
164 def observable(self) -> Observable:
165 return self._observable
167 @property
168 def target(self) -> QubitSet:
169 return self._target
171 @target.setter
172 def target(self, target: QubitSetInput) -> None:
173 self._target = QubitSet(target)
175 def __eq__(self, other) -> bool:
176 if isinstance(other, ObservableResultType):
177 return (
178 self.name == other.name
179 and self.target == other.target
180 and self.observable == other.observable
181 )
182 return NotImplemented
184 def __repr__(self) -> str:
185 return f"{self.name}(observable={self.observable}, target={self.target})"
187 def __copy__(self) -> ObservableResultType:
188 return type(self)(observable=self.observable, target=self.target)