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