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 List, Tuple, Union 

15 

16from braket.circuits.circuit_diagram import CircuitDiagram 

17from braket.circuits.gate import Gate 

18from braket.circuits.instruction import Instruction 

19from braket.circuits.qubit_set import QubitSet 

20from braket.circuits.result_type import ResultType 

21 

22 

23class AsciiCircuitDiagram(CircuitDiagram): 

24 """Builds ASCII string circuit diagrams.""" 

25 

26 @staticmethod 

27 def build_diagram(circuit) -> str: 

28 """ 

29 Build an ASCII string circuit diagram. 

30 

31 Args: 

32 circuit (Circuit): Circuit for which to build a diagram. 

33 

34 Returns: 

35 str: ASCII string circuit diagram. 

36 """ 

37 

38 if not circuit.instructions: 

39 return "" 

40 

41 circuit_qubits = circuit.qubits 

42 circuit_qubits.sort() 

43 

44 # Y Axis Column 

45 y_axis_width = len(str(int(max(circuit_qubits)))) 

46 y_axis_str = "{0:{width}} : |\n".format("T", width=y_axis_width + 1) 

47 for qubit in circuit_qubits: 

48 y_axis_str += "{0:{width}}\n".format(" ", width=y_axis_width + 5) 

49 y_axis_str += "q{0:{width}} : -\n".format(str(int(qubit)), width=y_axis_width) 

50 

51 time_slices = circuit.moments.time_slices() 

52 column_strs = [] 

53 

54 # Moment columns 

55 for time, instructions in time_slices.items(): 

56 moment_str = AsciiCircuitDiagram._ascii_diagram_column_set( 

57 str(time), circuit_qubits, instructions 

58 ) 

59 column_strs.append(moment_str) 

60 

61 # Result type columns 

62 additional_result_types, target_result_types = AsciiCircuitDiagram._categorize_result_types( 

63 circuit.result_types 

64 ) 

65 if target_result_types: 

66 column_strs.append( 

67 AsciiCircuitDiagram._ascii_diagram_column_set( 

68 "Result Types", circuit_qubits, target_result_types 

69 ) 

70 ) 

71 

72 # Unite strings 

73 lines = y_axis_str.split("\n") 

74 for col_str in column_strs: 

75 for i, line_in_col in enumerate(col_str.split("\n")): 

76 lines[i] += line_in_col 

77 

78 # Time on top and bottom 

79 lines.append(lines[0]) 

80 

81 # Additional result types line on bottom 

82 if additional_result_types: 

83 lines.append(f"\nAdditional result types: {', '.join(additional_result_types)}") 

84 

85 return "\n".join(lines) 

86 

87 @staticmethod 

88 def _ascii_group_items( 

89 circuit_qubits: QubitSet, items: List[Union[Instruction, ResultType]], 

90 ) -> List[Tuple[QubitSet, List[Instruction]]]: 

91 """ 

92 Group instructions in a moment for ASCII diagram 

93 

94 Args: 

95 circuit_qubits (QubitSet): set of qubits in circuit 

96 items (List[Union[Instruction, ResultType]]): list of instructions or result types 

97 

98 Returns: 

99 List[(QubitSet, List[Union[Instruction, ResultType]])]: list of grouped instructions 

100 or result types 

101 """ 

102 groupings = [] 

103 for item in items: 

104 # Can only print Gate operators for instructions at the moment 

105 if isinstance(item, Instruction) and not isinstance(item.operator, Gate): 

106 continue 

107 

108 if isinstance(item, ResultType) and not item.target: 

109 qubit_range = circuit_qubits 

110 else: 

111 qubit_range = QubitSet(range(min(item.target), max(item.target) + 1)) 

112 

113 found_grouping = False 

114 for group in groupings: 

115 qubits_added = group[0] 

116 instr_group = group[1] 

117 # Take into account overlapping multi-qubit gates 

118 if not qubits_added.intersection(set(qubit_range)): 

119 instr_group.append(item) 

120 qubits_added.update(qubit_range) 

121 found_grouping = True 

122 break 

123 

124 if not found_grouping: 

125 groupings.append((qubit_range, [item])) 

126 

127 return groupings 

128 

129 @staticmethod 

130 def _categorize_result_types(result_types: List[ResultType]) -> Tuple[List[ResultType]]: 

131 """ 

132 Categorize result types into result types with target and those without. 

133 

134 Args: 

135 result_types (List[ResultType]): list of result types 

136 

137 Returns: 

138 Tuple: first element is a list of result types without `target` attribute; 

139 second element is a list of result types with `target` attribute 

140 """ 

141 additional_result_types = [] 

142 target_result_types = [] 

143 for result_type in result_types: 

144 if hasattr(result_type, "target"): 

145 target_result_types.append(result_type) 

146 else: 

147 additional_result_types.extend(result_type.ascii_symbols) 

148 return (additional_result_types, target_result_types) 

149 

150 @staticmethod 

151 def _ascii_diagram_column_set( 

152 col_title: str, circuit_qubits: QubitSet, items: List[Union[Instruction, ResultType]] 

153 ) -> str: 

154 """ 

155 Return a set of columns in the ASCII string diagram of the circuit for a list of items. 

156 

157 Args: 

158 col_title (str): title of column set 

159 circuit_qubits (QubitSet): qubits in circuit 

160 items (List[Union[Instruction, ResultType]]): list of instructions or result types 

161 

162 Returns: 

163 str: An ASCII string diagram for the column set. 

164 """ 

165 

166 # Group items to separate out overlapping multi-qubit items 

167 groupings = AsciiCircuitDiagram._ascii_group_items(circuit_qubits, items) 

168 

169 column_strs = [ 

170 AsciiCircuitDiagram._ascii_diagram_column(circuit_qubits, grouping[1]) 

171 for grouping in groupings 

172 ] 

173 

174 # Unite column strings 

175 lines = column_strs[0].split("\n") 

176 for column_str in column_strs[1:]: 

177 for i, moment_line in enumerate(column_str.split("\n")): 

178 lines[i] += moment_line 

179 

180 # Adjust for column title width 

181 col_title_width = len(col_title) 

182 symbols_width = len(lines[0]) - 1 

183 if symbols_width < col_title_width: 

184 diff = col_title_width - symbols_width 

185 for i in range(len(lines) - 1): 

186 if lines[i].endswith("-"): 

187 lines[i] += "-" * diff 

188 else: 

189 lines[i] += " " 

190 

191 first_line = "{:^{width}}|\n".format(col_title, width=len(lines[0]) - 1) 

192 

193 return first_line + "\n".join(lines) 

194 

195 @staticmethod 

196 def _ascii_diagram_column( 

197 circuit_qubits: QubitSet, items: List[Union[Instruction, ResultType]] 

198 ) -> str: 

199 """ 

200 Return a column in the ASCII string diagram of the circuit for a given list of items. 

201 

202 Args: 

203 circuit_qubits (QubitSet): qubits in circuit 

204 items (List[Union[Instruction, ResultType]]): list of instructions or result types 

205 

206 Returns: 

207 str: An ASCII string diagram for the specified moment in time for a column. 

208 """ 

209 symbols = {qubit: "-" for qubit in circuit_qubits} 

210 margins = {qubit: " " for qubit in circuit_qubits} 

211 

212 for item in items: 

213 if isinstance(item, ResultType) and not item.target: 

214 target_qubits = circuit_qubits 

215 qubits = circuit_qubits 

216 ascii_symbols = [item.ascii_symbols[0]] * len(circuit_qubits) 

217 else: 

218 target_qubits = item.target 

219 qubits = circuit_qubits.intersection( 

220 set(range(min(item.target), max(item.target) + 1)) 

221 ) 

222 ascii_symbols = ( 

223 item.operator.ascii_symbols 

224 if isinstance(item, Instruction) 

225 else item.ascii_symbols 

226 ) 

227 

228 for qubit in qubits: 

229 # Determine if the qubit is part of the item or in the middle of a 

230 # multi qubit item. 

231 if qubit in target_qubits: 

232 item_qubit_index = [ 

233 index for index, q in enumerate(target_qubits) if q == qubit 

234 ][0] 

235 symbols[qubit] = ascii_symbols[item_qubit_index] 

236 else: 

237 symbols[qubit] = "|" 

238 

239 # Set the margin to be a connector if not on the first qubit 

240 if qubit != min(target_qubits): 

241 margins[qubit] = "|" 

242 

243 symbols_width = max([len(symbol) for symbol in symbols.values()]) 

244 

245 output = "" 

246 for qubit in circuit_qubits: 

247 output += "{0:{width}}\n".format(margins[qubit], width=symbols_width + 1) 

248 output += "{0:{fill}{align}{width}}\n".format( 

249 symbols[qubit], fill="-", align="<", width=symbols_width + 1 

250 ) 

251 return output