Coverage for src/braket/circuits/ascii_circuit_diagram.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 typing import List, Tuple
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
22class AsciiCircuitDiagram(CircuitDiagram):
23 """Builds ASCII string circuit diagrams."""
25 @staticmethod
26 def build_diagram(circuit) -> str:
27 """
28 Build an ASCII string circuit diagram.
30 Args:
31 circuit (Circuit): Circuit for which to build a diagram.
33 Returns:
34 str: ASCII string circuit diagram.
35 """
37 if not circuit.instructions:
38 return ""
40 circuit_qubits = circuit.qubits
41 circuit_qubits.sort()
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)
50 time_slices = circuit.moments.time_slices()
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)
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
66 # Time on top and bottom
67 lines.append(lines[0])
69 return "\n".join(lines)
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
78 Args:
79 instructions (List[Instruction]): list of instructions
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
90 qubit_range = QubitSet(range(min(instr.target), max(instr.target) + 1))
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
103 if not found_grouping:
104 groupings.append((qubit_range, [instr]))
106 return groupings
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.
115 Args:
116 time (int): time of moment
117 circuit_qubits (QubitSet): qubits in circuit
118 instructions (List[Instruction]): list of instructions
120 Returns:
121 str: An ASCII string diagram for the specified moment in time.
122 """
124 # Group instructions to separate out overlapping multi-qubit gates
125 groupings = AsciiCircuitDiagram._ascii_moment_group_instructions(instructions)
127 column_strs = [
128 AsciiCircuitDiagram._ascii_diagram_moment_column(circuit_qubits, grouping[1])
129 for grouping in groupings
130 ]
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
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] += " "
149 first_line = "{:^{width}}|\n".format(str(time), width=len(lines[0]) - 1)
151 return first_line + "\n".join(lines)
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.
160 Args:
161 circuit_qubits (QubitSet): qubits in circuit
162 instructions (List[Instruction]): list of instructions
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}
170 for instr in instructions:
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] = "|"
186 # Set the margin to be a connector if not on the first qubit
187 if qubit != min(instr.target):
188 margins[qubit] = "|"
190 symbols_width = max([len(symbol) for symbol in symbols.values()])
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