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 ( 

15 Dict, 

16 ItemsView, 

17 Iterable, 

18 KeysView, 

19 List, 

20 Mapping, 

21 NamedTuple, 

22 OrderedDict, 

23 ValuesView, 

24) 

25 

26from braket.circuits.instruction import Instruction 

27from braket.circuits.qubit import Qubit 

28from braket.circuits.qubit_set import QubitSet 

29 

30 

31class MomentsKey(NamedTuple): 

32 """Key of the Moments mapping.""" 

33 

34 time: int 

35 qubits: QubitSet 

36 

37 

38class Moments(Mapping[MomentsKey, Instruction]): 

39 """ 

40 An ordered mapping of `MomentsKey` to `Instruction`. The core data structure that 

41 contains instructions, ordering they are inserted in, and time slices when they 

42 occur. `Moments` implements `Mapping` and functions the same as a read-only 

43 dictionary. It is mutable only through the `add()` method. 

44 

45 This data structure is useful to determine a dependency of instructions, such as 

46 printing or optimizing circuit structure, before sending it to a quantum 

47 device. The original insertion order is preserved and can be retrieved via the `values()` 

48 method. 

49 

50 Args: 

51 instructions (Iterable[Instruction], optional): Instructions to initialize self with. 

52 Default = []. 

53 

54 Examples: 

55 >>> moments = Moments() 

56 >>> moments.add([Instruction(Gate.H(), 0), Instruction(Gate.CNot(), [0, 1])]) 

57 >>> moments.add([Instruction(Gate.H(), 0), Instruction(Gate.H(), 1)]) 

58 >>> for i, item in enumerate(moments.items()): 

59 ... print(f"Item {i}") 

60 ... print(f"\\tKey: {item[0]}") 

61 ... print(f"\\tValue: {item[1]}") 

62 ... 

63 Item 0 

64 Key: MomentsKey(time=0, qubits=QubitSet([Qubit(0)])) 

65 Value: Instruction('operator': H, 'target': QubitSet([Qubit(0)])) 

66 Item 1 

67 Key: MomentsKey(time=1, qubits=QubitSet([Qubit(0), Qubit(1)])) 

68 Value: Instruction('operator': CNOT, 'target': QubitSet([Qubit(0), Qubit(1)])) 

69 Item 2 

70 Key: MomentsKey(time=2, qubits=QubitSet([Qubit(0)])) 

71 Value: Instruction('operator': H, 'target': QubitSet([Qubit(0)])) 

72 Item 3 

73 Key: MomentsKey(time=2, qubits=QubitSet([Qubit(1)])) 

74 Value: Instruction('operator': H, 'target': QubitSet([Qubit(1)])) 

75 """ 

76 

77 def __init__(self, instructions: Iterable[Instruction] = []): 

78 self._moments: OrderedDict[MomentsKey, Instruction] = OrderedDict() 

79 self._max_times: Dict[Qubit, int] = {} 

80 self._qubits = QubitSet() 

81 self._depth = 0 

82 

83 self.add(instructions) 

84 

85 @property 

86 def depth(self) -> int: 

87 """int: Get the depth (number of slices) of self.""" 

88 return self._depth 

89 

90 @property 

91 def qubit_count(self) -> int: 

92 """int: Get the number of qubits used across all of the instructions.""" 

93 return len(self._qubits) 

94 

95 @property 

96 def qubits(self) -> QubitSet: 

97 """ 

98 QubitSet: Get the qubits used across all of the instructions. The order of qubits is based 

99 on the order in which the instructions were added. 

100 

101 Note: 

102 Don't mutate this object, any changes may impact the behavior of this class and / or 

103 consumers. If you need to mutate this, then copy it via `QubitSet(moments.qubits())`. 

104 """ 

105 return self._qubits 

106 

107 def time_slices(self) -> Dict[int, List[Instruction]]: 

108 """ 

109 Get instructions keyed by time. 

110 

111 Returns: 

112 Dict[int, List[Instruction]]: Key is the time and value is a list of instructions that 

113 occur at that moment in time. The order of instructions is in no particular order. 

114 

115 Note: 

116 This is a computed result over self and can be freely mutated. This is re-computed with 

117 every call, with a computational runtime O(N) where N is the number 

118 of instructions in self. 

119 """ 

120 

121 time_slices = {} 

122 for key, instruction in self._moments.items(): 

123 instructions = time_slices.get(key.time, []) 

124 instructions.append(instruction) 

125 time_slices[key.time] = instructions 

126 

127 return time_slices 

128 

129 def add(self, instructions: Iterable[Instruction]) -> None: 

130 """ 

131 Add instructions to self. 

132 

133 Args: 

134 instructions (Iterable[Instruction]): Instructions to add to self. The instruction 

135 are added to the max time slice in which the instruction fits. 

136 """ 

137 for instruction in instructions: 

138 self._add(instruction) 

139 

140 def _add(self, instruction: Instruction) -> None: 

141 qubit_range = instruction.target 

142 time = max([self._max_time_for_qubit(qubit) for qubit in qubit_range]) + 1 

143 

144 # Mark all qubits in qubit_range with max_time 

145 for qubit in qubit_range: 

146 self._max_times[qubit] = max(time, self._max_time_for_qubit(qubit)) 

147 

148 self._moments[MomentsKey(time, instruction.target)] = instruction 

149 self._qubits.update(instruction.target) 

150 self._depth = max(self._depth, time + 1) 

151 

152 def _max_time_for_qubit(self, qubit: Qubit) -> int: 

153 return self._max_times.get(qubit, -1) 

154 

155 # 

156 # Implement abstract methods, default to calling selfs underlying dictionary 

157 # 

158 

159 def keys(self) -> KeysView[MomentsKey]: 

160 """Return a view of self's keys.""" 

161 return self._moments.keys() 

162 

163 def items(self) -> ItemsView[MomentsKey, Instruction]: 

164 """Return a view of self's (key, instruction).""" 

165 return self._moments.items() 

166 

167 def values(self) -> ValuesView[Instruction]: 

168 """Return a view of self's instructions.""" 

169 return self._moments.values() 

170 

171 def get(self, key: MomentsKey, default=None) -> Instruction: 

172 """ 

173 Get the instruction in self by key. 

174 

175 Args: 

176 key (MomentsKey): Key of the instruction to fetch. 

177 default (Any, optional): Value to return if `key` is not in moment. Default = None. 

178 

179 Returns: 

180 Instruction: moments[key] if key in moments, else `default` is returned. 

181 """ 

182 return self._moments.get(key, default) 

183 

184 def __getitem__(self, key): 

185 return self._moments.__getitem__(key) 

186 

187 def __iter__(self): 

188 return self._moments.__iter__() 

189 

190 def __len__(self): 

191 return self._moments.__len__() 

192 

193 def __contains__(self, item): 

194 return self._moments.__contains__(item) 

195 

196 def __eq__(self, other): 

197 if isinstance(other, Moments): 

198 return (self._moments) == (other._moments) 

199 return NotImplemented 

200 

201 def __ne__(self, other): 

202 result = self.__eq__(other) 

203 if result is not NotImplemented: 

204 return not result 

205 return NotImplemented 

206 

207 def __repr__(self): 

208 return self._moments.__repr__() 

209 

210 def __str__(self): 

211 return self._moments.__str__()