qiskit_trebugger.views.cli.cli_pass_pad
1import curses 2from datetime import datetime 3from collections import defaultdict 4 5import tabulate 6 7 8class TranspilerPassPad: 9 def __init__(self, step, circuit, property_set, height, width, pad_obj): 10 """Pass Pad for the CLI Debugger 11 12 Args: 13 step (TranspilationStep): The transpilation step to be displayed 14 circuit (): Text circuit diagram 15 property_set (default dict): The property set to be displayed 16 height (int)): The height of the pad 17 width (int): The width of the pad 18 pad_obj (curses.Window): The curses pad object 19 """ 20 self.transpiler_pass = step 21 self.circuit = circuit 22 self.property_set = property_set 23 self.log_data = [] 24 self.height = height 25 self.width = width 26 self.pad = pad_obj 27 self._start_row = 0 28 29 def _get_center(self, width, string_len, divisor=2): 30 """Get the center of the pad 31 32 Args: 33 width (int): The width of the pad 34 string_len (int): The length of the string to be centered 35 divisor (int, optional): The divisor to be used. Defaults to 2. 36 37 """ 38 return max(0, int(width // divisor - string_len // 2 - string_len % 2)) 39 40 def _display_header(self, string): 41 """Display a header in the pad 42 43 Args: 44 string (str): The string to be displayed 45 """ 46 offset = self._get_center(self.width, len(string)) 47 self.pad.addstr(self._start_row, offset, string, curses.A_BOLD) 48 49 def _add_title(self): 50 """Add the title of the pass to the pad 51 52 Args: 53 None 54 """ 55 pass_name = f"{self.transpiler_pass.index}. {self.transpiler_pass.name}"[ 56 : self.width - 1 57 ] 58 title_offset = self._get_center(self.width - 4, len(pass_name)) 59 self.pad.addstr( 60 self._start_row, 61 title_offset, 62 pass_name, 63 curses.A_BOLD, 64 ) 65 self._start_row += 1 66 self.pad.hline(self._start_row, 0, "_", self.width - 4) 67 68 def _add_information(self): 69 """Add the information of the pass to the pad 70 71 Args: 72 None 73 """ 74 self._start_row += 2 75 pass_type = self.transpiler_pass.pass_type.value 76 pass_runtime = self.transpiler_pass.duration 77 info_string = f"Type : {pass_type} | Runtime (ms) : {pass_runtime}"[ 78 : self.width - 1 79 ] 80 81 self._display_header(info_string) 82 83 def _add_statistics(self): 84 """Add the statistics of the pass to the pad 85 86 Args: 87 None 88 """ 89 90 self._start_row += 2 91 92 props_string = f"Depth : {self.transpiler_pass.circuit_stats.depth} | " 93 props_string += f"Width : {self.transpiler_pass.circuit_stats.width} | " 94 props_string += f"Size : {self.transpiler_pass.circuit_stats.size} | " 95 props_string += f"1Q Ops : {self.transpiler_pass.circuit_stats.ops_1q} | " 96 props_string += f"2Q Ops : {self.transpiler_pass.circuit_stats.ops_2q}" 97 98 props_string = props_string[: self.width - 1] 99 props_offset = self._get_center(self.width, len(props_string)) 100 self.pad.addstr(self._start_row, props_offset, props_string) 101 102 def _get_property_data(self): 103 """Get the property set data as a list of lists 104 105 Args: 106 None 107 """ 108 109 prop_data = [] 110 vf2_properties = { 111 "VF2Layout_stop_reason", 112 "VF2PostLayout_stop_reason", 113 } 114 115 for name, property_ in self.property_set.items(): 116 changed_prop = True 117 if property_.prop_type not in (int, float, bool, str): 118 if name in vf2_properties: 119 txt = property_.value.name 120 elif name == "optimization_loop_minimum_point_state": 121 txt = f"""score : {property_.value.score}, since : {property_.value.since}""" 122 elif name == "commutation_set": 123 txt = "(dict)" 124 else: 125 txt = ( 126 "(dict)" 127 if isinstance(property_.value, defaultdict) 128 else "(" + property_.prop_type.__name__ + ")" 129 ) 130 131 else: 132 txt = str(property_.value) 133 134 if not property_.state or len(property_.state) == 0: 135 changed_prop = False 136 property_.state = "---" 137 138 data_item = [name, txt, property_.state] 139 if changed_prop: 140 prop_data.insert(0, data_item) 141 else: 142 prop_data.append(data_item) 143 144 return prop_data 145 146 def _add_property_set(self): 147 """Add the property set to the pad 148 149 Args: 150 None 151 """ 152 153 self._start_row += 2 154 self._display_header("Property Set"[: self.width - 1]) 155 self._start_row += 1 156 157 headers = ["Property", "Value", "State"] 158 159 prop_data = self._get_property_data() 160 161 prop_set_table = tabulate.tabulate( 162 tabular_data=prop_data, 163 headers=headers, 164 tablefmt="simple_grid", 165 stralign="center", 166 numalign="center", 167 showindex=True, 168 ).splitlines() 169 170 props_offset = self._get_center(self.width, len(prop_set_table[0])) 171 for index, row in enumerate(prop_set_table): 172 # 0 is default 173 highlight = 0 if index > 2 else curses.A_BOLD 174 self.pad.addstr( 175 index + self._start_row, 176 props_offset, 177 row[: self.width - 1], 178 highlight, 179 ) 180 self._start_row += len(prop_set_table) 181 182 def _add_original_qubits(self): 183 if "original_qubit_indices" not in self.property_set: 184 return 185 186 self._start_row += 2 187 self._display_header("Original Qubit Indices"[: self.width - 1]) 188 self._start_row += 1 189 190 original_indices = self.property_set["original_qubit_indices"].value.items() 191 192 index_data = [] 193 for qubit, index in original_indices: 194 index_data.append([qubit, index]) 195 196 headers = ["Qubit", "Index"] 197 198 indices_table = tabulate.tabulate( 199 tabular_data=index_data, 200 headers=headers, 201 tablefmt="simple_grid", 202 stralign="center", 203 numalign="center", 204 showindex=False, 205 ).splitlines() 206 207 indices_offset = self._get_center(self.width, len(indices_table[0])) 208 for index, row in enumerate(indices_table): 209 # 0 is default 210 highlight = 0 if index > 2 else curses.A_BOLD 211 self.pad.addstr( 212 index + self._start_row, 213 indices_offset, 214 row[: self.width - 1], 215 highlight, 216 ) 217 self._start_row += len(indices_table) 218 219 def _add_layout(self, layout_type): 220 if "original_qubit_indices" not in self.property_set: 221 return 222 223 if layout_type not in self.property_set: 224 return 225 226 # total num of physical qubits 227 physical_qubits = len(self.property_set["original_qubit_indices"].value) 228 curr_layout = self.property_set[layout_type].value.get_physical_bits() 229 230 # original map of qubits to indices 231 original_indices = self.property_set["original_qubit_indices"].value 232 233 # add the layout to the pad 234 self._start_row += 2 235 self._display_header(f"{layout_type}"[: self.width - 1]) 236 self._start_row += 1 237 238 elements_per_table = 15 239 # multiple tables required 240 num_tables = physical_qubits // elements_per_table 241 num_tables += 1 if physical_qubits % elements_per_table != 0 else 0 242 243 for i in range(num_tables): 244 data = [] 245 start = i * elements_per_table 246 end = start + elements_per_table - 1 247 248 if start >= end: 249 break 250 251 data.append(f"Physical Qubits({start}-{min(physical_qubits-1,end)})") 252 253 for qubit in range(start, end + 1): 254 if qubit not in curr_layout: 255 data.append("--") 256 continue 257 virtual_qubit = curr_layout[qubit] 258 data.append(original_indices[virtual_qubit]) 259 260 # draw this single row table now 261 data_table = tabulate.tabulate( 262 tabular_data=[data], 263 tablefmt="simple_grid", 264 stralign="center", 265 numalign="center", 266 showindex=False, 267 ).splitlines() 268 269 table_offset = self._get_center(self.width, len(data_table[0])) 270 for row, _ in enumerate(data_table): 271 self.pad.addstr( 272 row + self._start_row, 273 table_offset, 274 data_table[row][: self.width - 1], 275 curses.A_BOLD, 276 ) 277 self._start_row += len(data_table) + 1 278 279 self._start_row += 1 280 281 def _add_documentation(self): 282 """Add the documentation to the pad 283 284 Args: 285 None 286 """ 287 288 self._start_row += 2 289 self._display_header("Documentation"[: self.width - 1]) 290 self._start_row += 1 291 pass_docs = self.transpiler_pass.get_docs() 292 293 if pass_docs and pass_docs.count("\n") > 0: 294 pass_docs = " " + pass_docs 295 pass_docs = [[pass_docs], [self.transpiler_pass.run_method_docs]] 296 297 docs_table = tabulate.tabulate( 298 tabular_data=pass_docs, 299 tablefmt="simple_grid", 300 stralign="left", 301 ).splitlines() 302 303 docs_offset = self._get_center(self.width, len(docs_table[0])) 304 305 for row in range(len(docs_table)): 306 self.pad.addstr( 307 row + self._start_row, 308 docs_offset, 309 docs_table[row][: self.width - 1], 310 ) 311 self._start_row += len(docs_table) 312 313 def _add_circuit(self): 314 """Add the circuit diagram to the pad 315 316 Args: 317 None 318 """ 319 self._start_row += 2 320 self._display_header("Circuit Diagram"[: self.width - 1]) 321 self._start_row += 1 322 if self.transpiler_pass.circuit_stats.depth < 300: 323 # only if <300 depth, we will get a circuit to draw 324 circ_string = [[self.circuit.draw(output="text", fold=100)]] 325 else: 326 circ_string = [ 327 [ 328 f"Circuit depth {self.transpiler_pass.circuit_stats.depth} too large to display" 329 ] 330 ] 331 circ_table = tabulate.tabulate( 332 tabular_data=circ_string, 333 tablefmt="simple_grid", 334 stralign="center", 335 numalign="center", 336 ).splitlines() 337 338 circ_offset = self._get_center(self.width, len(circ_table[0])) 339 for index, row in enumerate(circ_table): 340 self.pad.addstr(index + self._start_row, circ_offset, row) 341 342 self._start_row += len(circ_table) 343 344 def _add_logs(self): 345 """Add the logs to the pad 346 347 Args: 348 None 349 """ 350 self._start_row += 2 351 self._display_header("Logs"[: self.width - 1]) 352 self._start_row += 1 353 354 if not self.log_data: 355 self.log_data = [] 356 for entry in self.transpiler_pass.logs: 357 log_string = f"{datetime.fromtimestamp(entry.time).strftime('%H:%M:%S.%f')[:-3]} | " 358 359 log_string += f"{entry.levelname} \n {entry.msg}" % entry.args 360 361 self.log_data.append([log_string]) 362 363 if not self.log_data: 364 self.log_data = [["This pass does not display any Logs."]] 365 366 log_table = tabulate.tabulate( 367 tabular_data=self.log_data, 368 tablefmt="simple_grid", 369 stralign="left", 370 numalign="center", 371 ).splitlines() 372 373 logs_offset = self._get_center(self.width, len(log_table[0])) 374 for index, row in enumerate(log_table): 375 self.pad.addstr(index + self._start_row, logs_offset, row[: self.width - 1]) 376 self._start_row += len(log_table) 377 378 def build_pad(self): 379 """Build the pad view""" 380 381 self._add_title() 382 self._add_information() 383 self._add_statistics() 384 self._add_property_set() 385 self._add_original_qubits() 386 self._add_layout("layout") 387 # self._add_layout("final_layout") 388 self._add_circuit() 389 self._add_documentation() 390 self._add_logs()
class
TranspilerPassPad:
9class TranspilerPassPad: 10 def __init__(self, step, circuit, property_set, height, width, pad_obj): 11 """Pass Pad for the CLI Debugger 12 13 Args: 14 step (TranspilationStep): The transpilation step to be displayed 15 circuit (): Text circuit diagram 16 property_set (default dict): The property set to be displayed 17 height (int)): The height of the pad 18 width (int): The width of the pad 19 pad_obj (curses.Window): The curses pad object 20 """ 21 self.transpiler_pass = step 22 self.circuit = circuit 23 self.property_set = property_set 24 self.log_data = [] 25 self.height = height 26 self.width = width 27 self.pad = pad_obj 28 self._start_row = 0 29 30 def _get_center(self, width, string_len, divisor=2): 31 """Get the center of the pad 32 33 Args: 34 width (int): The width of the pad 35 string_len (int): The length of the string to be centered 36 divisor (int, optional): The divisor to be used. Defaults to 2. 37 38 """ 39 return max(0, int(width // divisor - string_len // 2 - string_len % 2)) 40 41 def _display_header(self, string): 42 """Display a header in the pad 43 44 Args: 45 string (str): The string to be displayed 46 """ 47 offset = self._get_center(self.width, len(string)) 48 self.pad.addstr(self._start_row, offset, string, curses.A_BOLD) 49 50 def _add_title(self): 51 """Add the title of the pass to the pad 52 53 Args: 54 None 55 """ 56 pass_name = f"{self.transpiler_pass.index}. {self.transpiler_pass.name}"[ 57 : self.width - 1 58 ] 59 title_offset = self._get_center(self.width - 4, len(pass_name)) 60 self.pad.addstr( 61 self._start_row, 62 title_offset, 63 pass_name, 64 curses.A_BOLD, 65 ) 66 self._start_row += 1 67 self.pad.hline(self._start_row, 0, "_", self.width - 4) 68 69 def _add_information(self): 70 """Add the information of the pass to the pad 71 72 Args: 73 None 74 """ 75 self._start_row += 2 76 pass_type = self.transpiler_pass.pass_type.value 77 pass_runtime = self.transpiler_pass.duration 78 info_string = f"Type : {pass_type} | Runtime (ms) : {pass_runtime}"[ 79 : self.width - 1 80 ] 81 82 self._display_header(info_string) 83 84 def _add_statistics(self): 85 """Add the statistics of the pass to the pad 86 87 Args: 88 None 89 """ 90 91 self._start_row += 2 92 93 props_string = f"Depth : {self.transpiler_pass.circuit_stats.depth} | " 94 props_string += f"Width : {self.transpiler_pass.circuit_stats.width} | " 95 props_string += f"Size : {self.transpiler_pass.circuit_stats.size} | " 96 props_string += f"1Q Ops : {self.transpiler_pass.circuit_stats.ops_1q} | " 97 props_string += f"2Q Ops : {self.transpiler_pass.circuit_stats.ops_2q}" 98 99 props_string = props_string[: self.width - 1] 100 props_offset = self._get_center(self.width, len(props_string)) 101 self.pad.addstr(self._start_row, props_offset, props_string) 102 103 def _get_property_data(self): 104 """Get the property set data as a list of lists 105 106 Args: 107 None 108 """ 109 110 prop_data = [] 111 vf2_properties = { 112 "VF2Layout_stop_reason", 113 "VF2PostLayout_stop_reason", 114 } 115 116 for name, property_ in self.property_set.items(): 117 changed_prop = True 118 if property_.prop_type not in (int, float, bool, str): 119 if name in vf2_properties: 120 txt = property_.value.name 121 elif name == "optimization_loop_minimum_point_state": 122 txt = f"""score : {property_.value.score}, since : {property_.value.since}""" 123 elif name == "commutation_set": 124 txt = "(dict)" 125 else: 126 txt = ( 127 "(dict)" 128 if isinstance(property_.value, defaultdict) 129 else "(" + property_.prop_type.__name__ + ")" 130 ) 131 132 else: 133 txt = str(property_.value) 134 135 if not property_.state or len(property_.state) == 0: 136 changed_prop = False 137 property_.state = "---" 138 139 data_item = [name, txt, property_.state] 140 if changed_prop: 141 prop_data.insert(0, data_item) 142 else: 143 prop_data.append(data_item) 144 145 return prop_data 146 147 def _add_property_set(self): 148 """Add the property set to the pad 149 150 Args: 151 None 152 """ 153 154 self._start_row += 2 155 self._display_header("Property Set"[: self.width - 1]) 156 self._start_row += 1 157 158 headers = ["Property", "Value", "State"] 159 160 prop_data = self._get_property_data() 161 162 prop_set_table = tabulate.tabulate( 163 tabular_data=prop_data, 164 headers=headers, 165 tablefmt="simple_grid", 166 stralign="center", 167 numalign="center", 168 showindex=True, 169 ).splitlines() 170 171 props_offset = self._get_center(self.width, len(prop_set_table[0])) 172 for index, row in enumerate(prop_set_table): 173 # 0 is default 174 highlight = 0 if index > 2 else curses.A_BOLD 175 self.pad.addstr( 176 index + self._start_row, 177 props_offset, 178 row[: self.width - 1], 179 highlight, 180 ) 181 self._start_row += len(prop_set_table) 182 183 def _add_original_qubits(self): 184 if "original_qubit_indices" not in self.property_set: 185 return 186 187 self._start_row += 2 188 self._display_header("Original Qubit Indices"[: self.width - 1]) 189 self._start_row += 1 190 191 original_indices = self.property_set["original_qubit_indices"].value.items() 192 193 index_data = [] 194 for qubit, index in original_indices: 195 index_data.append([qubit, index]) 196 197 headers = ["Qubit", "Index"] 198 199 indices_table = tabulate.tabulate( 200 tabular_data=index_data, 201 headers=headers, 202 tablefmt="simple_grid", 203 stralign="center", 204 numalign="center", 205 showindex=False, 206 ).splitlines() 207 208 indices_offset = self._get_center(self.width, len(indices_table[0])) 209 for index, row in enumerate(indices_table): 210 # 0 is default 211 highlight = 0 if index > 2 else curses.A_BOLD 212 self.pad.addstr( 213 index + self._start_row, 214 indices_offset, 215 row[: self.width - 1], 216 highlight, 217 ) 218 self._start_row += len(indices_table) 219 220 def _add_layout(self, layout_type): 221 if "original_qubit_indices" not in self.property_set: 222 return 223 224 if layout_type not in self.property_set: 225 return 226 227 # total num of physical qubits 228 physical_qubits = len(self.property_set["original_qubit_indices"].value) 229 curr_layout = self.property_set[layout_type].value.get_physical_bits() 230 231 # original map of qubits to indices 232 original_indices = self.property_set["original_qubit_indices"].value 233 234 # add the layout to the pad 235 self._start_row += 2 236 self._display_header(f"{layout_type}"[: self.width - 1]) 237 self._start_row += 1 238 239 elements_per_table = 15 240 # multiple tables required 241 num_tables = physical_qubits // elements_per_table 242 num_tables += 1 if physical_qubits % elements_per_table != 0 else 0 243 244 for i in range(num_tables): 245 data = [] 246 start = i * elements_per_table 247 end = start + elements_per_table - 1 248 249 if start >= end: 250 break 251 252 data.append(f"Physical Qubits({start}-{min(physical_qubits-1,end)})") 253 254 for qubit in range(start, end + 1): 255 if qubit not in curr_layout: 256 data.append("--") 257 continue 258 virtual_qubit = curr_layout[qubit] 259 data.append(original_indices[virtual_qubit]) 260 261 # draw this single row table now 262 data_table = tabulate.tabulate( 263 tabular_data=[data], 264 tablefmt="simple_grid", 265 stralign="center", 266 numalign="center", 267 showindex=False, 268 ).splitlines() 269 270 table_offset = self._get_center(self.width, len(data_table[0])) 271 for row, _ in enumerate(data_table): 272 self.pad.addstr( 273 row + self._start_row, 274 table_offset, 275 data_table[row][: self.width - 1], 276 curses.A_BOLD, 277 ) 278 self._start_row += len(data_table) + 1 279 280 self._start_row += 1 281 282 def _add_documentation(self): 283 """Add the documentation to the pad 284 285 Args: 286 None 287 """ 288 289 self._start_row += 2 290 self._display_header("Documentation"[: self.width - 1]) 291 self._start_row += 1 292 pass_docs = self.transpiler_pass.get_docs() 293 294 if pass_docs and pass_docs.count("\n") > 0: 295 pass_docs = " " + pass_docs 296 pass_docs = [[pass_docs], [self.transpiler_pass.run_method_docs]] 297 298 docs_table = tabulate.tabulate( 299 tabular_data=pass_docs, 300 tablefmt="simple_grid", 301 stralign="left", 302 ).splitlines() 303 304 docs_offset = self._get_center(self.width, len(docs_table[0])) 305 306 for row in range(len(docs_table)): 307 self.pad.addstr( 308 row + self._start_row, 309 docs_offset, 310 docs_table[row][: self.width - 1], 311 ) 312 self._start_row += len(docs_table) 313 314 def _add_circuit(self): 315 """Add the circuit diagram to the pad 316 317 Args: 318 None 319 """ 320 self._start_row += 2 321 self._display_header("Circuit Diagram"[: self.width - 1]) 322 self._start_row += 1 323 if self.transpiler_pass.circuit_stats.depth < 300: 324 # only if <300 depth, we will get a circuit to draw 325 circ_string = [[self.circuit.draw(output="text", fold=100)]] 326 else: 327 circ_string = [ 328 [ 329 f"Circuit depth {self.transpiler_pass.circuit_stats.depth} too large to display" 330 ] 331 ] 332 circ_table = tabulate.tabulate( 333 tabular_data=circ_string, 334 tablefmt="simple_grid", 335 stralign="center", 336 numalign="center", 337 ).splitlines() 338 339 circ_offset = self._get_center(self.width, len(circ_table[0])) 340 for index, row in enumerate(circ_table): 341 self.pad.addstr(index + self._start_row, circ_offset, row) 342 343 self._start_row += len(circ_table) 344 345 def _add_logs(self): 346 """Add the logs to the pad 347 348 Args: 349 None 350 """ 351 self._start_row += 2 352 self._display_header("Logs"[: self.width - 1]) 353 self._start_row += 1 354 355 if not self.log_data: 356 self.log_data = [] 357 for entry in self.transpiler_pass.logs: 358 log_string = f"{datetime.fromtimestamp(entry.time).strftime('%H:%M:%S.%f')[:-3]} | " 359 360 log_string += f"{entry.levelname} \n {entry.msg}" % entry.args 361 362 self.log_data.append([log_string]) 363 364 if not self.log_data: 365 self.log_data = [["This pass does not display any Logs."]] 366 367 log_table = tabulate.tabulate( 368 tabular_data=self.log_data, 369 tablefmt="simple_grid", 370 stralign="left", 371 numalign="center", 372 ).splitlines() 373 374 logs_offset = self._get_center(self.width, len(log_table[0])) 375 for index, row in enumerate(log_table): 376 self.pad.addstr(index + self._start_row, logs_offset, row[: self.width - 1]) 377 self._start_row += len(log_table) 378 379 def build_pad(self): 380 """Build the pad view""" 381 382 self._add_title() 383 self._add_information() 384 self._add_statistics() 385 self._add_property_set() 386 self._add_original_qubits() 387 self._add_layout("layout") 388 # self._add_layout("final_layout") 389 self._add_circuit() 390 self._add_documentation() 391 self._add_logs()
TranspilerPassPad(step, circuit, property_set, height, width, pad_obj)
10 def __init__(self, step, circuit, property_set, height, width, pad_obj): 11 """Pass Pad for the CLI Debugger 12 13 Args: 14 step (TranspilationStep): The transpilation step to be displayed 15 circuit (): Text circuit diagram 16 property_set (default dict): The property set to be displayed 17 height (int)): The height of the pad 18 width (int): The width of the pad 19 pad_obj (curses.Window): The curses pad object 20 """ 21 self.transpiler_pass = step 22 self.circuit = circuit 23 self.property_set = property_set 24 self.log_data = [] 25 self.height = height 26 self.width = width 27 self.pad = pad_obj 28 self._start_row = 0
Pass Pad for the CLI Debugger
Args: step (TranspilationStep): The transpilation step to be displayed circuit (): Text circuit diagram property_set (default dict): The property set to be displayed height (int)): The height of the pad width (int): The width of the pad pad_obj (curses.Window): The curses pad object
def
build_pad(self):
379 def build_pad(self): 380 """Build the pad view""" 381 382 self._add_title() 383 self._add_information() 384 self._add_statistics() 385 self._add_property_set() 386 self._add_original_qubits() 387 self._add_layout("layout") 388 # self._add_layout("final_layout") 389 self._add_circuit() 390 self._add_documentation() 391 self._add_logs()
Build the pad view