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 

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 

20 

21 

22class AsciiCircuitDiagram(CircuitDiagram): 

23 """Builds ASCII string circuit diagrams.""" 

24 

25 @staticmethod 

26 def build_diagram(circuit) -> str: 

27 """ 

28 Build an ASCII string circuit diagram. 

29 

30 Args: 

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

32 

33 Returns: 

34 str: ASCII string circuit diagram. 

35 """ 

36 

37 if not circuit.instructions: 

38 return "" 

39 

40 circuit_qubits = circuit.qubits 

41 circuit_qubits.sort() 

42 

43 # Y Axis Column 

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

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

46 for qubit in circuit_qubits: 

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

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

49 

50 time_slices = circuit.moments.time_slices() 

51 

52 # Moment columns 

53 moments_strs = [] 

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

55 moment_str = AsciiCircuitDiagram._ascii_diagram_moment( 

56 time, circuit_qubits, instructions 

57 ) 

58 moments_strs.append(moment_str) 

59 

60 # Unite strings 

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

62 for moment_str in moments_strs: 

63 for i, moment_line in enumerate(moment_str.split("\n")): 

64 lines[i] += moment_line 

65 

66 # Time on top and bottom 

67 lines.append(lines[0]) 

68 

69 return "\n".join(lines) 

70 

71 @staticmethod 

72 def _ascii_moment_group_instructions( 

73 instructions: List[Instruction], 

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

75 """ 

76 Group instructions in a moment for ASCII diagram 

77 

78 Args: 

79 instructions (List[Instruction]): list of instructions 

80 

81 Returns: 

82 List[(QubitSet, List[Instruction])]: list of grouped instructions 

83 """ 

84 groupings = [] 

85 for instr in instructions: 

86 # Can only print Gate operators at the moment 

87 if not isinstance(instr.operator, Gate): 

88 continue 

89 

90 qubit_range = QubitSet(range(min(instr.target), max(instr.target) + 1)) 

91 

92 found_grouping = False 

93 for group in groupings: 

94 qubits_added = group[0] 

95 instr_group = group[1] 

96 # Take into account overlapping multi-qubit gates 

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

98 instr_group.append(instr) 

99 qubits_added.update(qubit_range) 

100 found_grouping = True 

101 break 

102 

103 if not found_grouping: 

104 groupings.append((qubit_range, [instr])) 

105 

106 return groupings 

107 

108 @staticmethod 

109 def _ascii_diagram_moment( 

110 time: int, circuit_qubits: QubitSet, instructions: List[Instruction] 

111 ) -> str: 

112 """ 

113 Return an ASCII string diagram of the circuit at a particular moment in time. 

114 

115 Args: 

116 time (int): time of moment 

117 circuit_qubits (QubitSet): qubits in circuit 

118 instructions (List[Instruction]): list of instructions 

119 

120 Returns: 

121 str: An ASCII string diagram for the specified moment in time. 

122 """ 

123 

124 # Group instructions to separate out overlapping multi-qubit gates 

125 groupings = AsciiCircuitDiagram._ascii_moment_group_instructions(instructions) 

126 

127 column_strs = [ 

128 AsciiCircuitDiagram._ascii_diagram_moment_column(circuit_qubits, grouping[1]) 

129 for grouping in groupings 

130 ] 

131 

132 # Unite column strings 

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

134 for column_str in column_strs[1:]: 

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

136 lines[i] += moment_line 

137 

138 # Adjust for time width 

139 time_width = len(str(time)) 

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

141 if symbols_width < time_width: 

142 diff = time_width - symbols_width 

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

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

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

146 else: 

147 lines[i] += " " 

148 

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

150 

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

152 

153 @staticmethod 

154 def _ascii_diagram_moment_column( 

155 circuit_qubits: QubitSet, instructions: List[Instruction] 

156 ) -> str: 

157 """ 

158 Return an ASCII string diagram of the circuit at a particular moment in time for a column. 

159 

160 Args: 

161 circuit_qubits (QubitSet): qubits in circuit 

162 instructions (List[Instruction]): list of instructions 

163 

164 Returns: 

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

166 """ 

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

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

169 

170 for instr in instructions: 

171 

172 qubits = circuit_qubits.intersection( 

173 set(range(min(instr.target), max(instr.target) + 1)) 

174 ) 

175 for qubit in qubits: 

176 # Determine if the qubit is part of the instruction or in the middle of a 

177 # multi qubit gate. 

178 if qubit in instr.target: 

179 instr_qubit_index = [ 

180 index for index, q in enumerate(instr.target) if q == qubit 

181 ][0] 

182 symbols[qubit] = instr.operator.ascii_symbols[instr_qubit_index] 

183 else: 

184 symbols[qubit] = "|" 

185 

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

187 if qubit != min(instr.target): 

188 margins[qubit] = "|" 

189 

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

191 

192 output = "" 

193 for qubit in circuit_qubits: 

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

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

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

197 ) 

198 return output