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. 

13from __future__ import annotations 

14 

15from typing import Any, Dict 

16 

17from braket.circuits.observable import Observable 

18from braket.circuits.qubit import QubitInput 

19from braket.circuits.qubit_set import QubitSet, QubitSetInput 

20 

21 

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 """ 

28 

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. 

34 

35 Raises: 

36 ValueError: `ascii_symbol` is None 

37 """ 

38 

39 if ascii_symbol is None: 

40 raise ValueError(f"ascii_symbol must not be None") 

41 

42 self._ascii_symbol = ascii_symbol 

43 

44 @property 

45 def ascii_symbol(self) -> str: 

46 """str: Returns the ascii symbol for the requested result type.""" 

47 return self._ascii_symbol 

48 

49 @property 

50 def name(self) -> str: 

51 """ 

52 Returns the name of the result type 

53 

54 Returns: 

55 The name of the result type as a string 

56 """ 

57 return self.__class__.__name__ 

58 

59 def to_ir(self, *args, **kwargs) -> Any: 

60 """Returns IR object of the result type 

61 

62 Args: 

63 *args: Positional arguments 

64 **kwargs: Keyword arguments 

65 

66 Returns: 

67 IR object of the result type 

68 """ 

69 raise NotImplementedError("to_ir has not been implemented yet.") 

70 

71 def copy(self, target_mapping: Dict[QubitInput, QubitInput] = {}, target: QubitSetInput = None): 

72 """ 

73 Return a shallow copy of the result type. 

74 

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. 

78 

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. 

85 

86 Returns: 

87 ResultType: A shallow copy of the result type. 

88 

89 Raises: 

90 TypeError: If both `target_mapping` and `target` are supplied. 

91 

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 

114 

115 @classmethod 

116 def register_result_type(cls, result_type: "ResultType"): 

117 """Register a result type implementation by adding it into the ResultType class. 

118 

119 Args: 

120 result_type (ResultType): ResultType instance to register. 

121 """ 

122 setattr(cls, result_type.__name__, result_type) 

123 

124 def __repr__(self) -> str: 

125 return f"{self.name}()" 

126 

127 

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. 

134 

135 See :mod:`braket.circuits.observables` module for all of the supported observables. 

136 """ 

137 

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 

145 

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 ) 

162 

163 @property 

164 def observable(self) -> Observable: 

165 return self._observable 

166 

167 @property 

168 def target(self) -> QubitSet: 

169 return self._target 

170 

171 @target.setter 

172 def target(self, target: QubitSetInput) -> None: 

173 self._target = QubitSet(target) 

174 

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 

183 

184 def __repr__(self) -> str: 

185 return f"{self.name}(observable={self.observable}, target={self.target})" 

186 

187 def __copy__(self) -> ObservableResultType: 

188 return type(self)(observable=self.observable, target=self.target)