qiskit_trebugger.debugger
Implements the main Debugger class. Raises: DebuggerError: if multiple quantum circuits supplied for debugging
1""" 2Implements the main Debugger class. 3Raises: 4 DebuggerError: if multiple quantum circuits supplied for debugging 5""" 6import curses 7from typing import Optional, Union 8import logging 9import warnings 10from IPython.display import display 11 12 13from qiskit import QuantumCircuit, transpile, Aer, __qiskit_version__ 14from qiskit.providers.backend import Backend, BackendV1, BackendV2 15from qiskit.transpiler.basepasses import AnalysisPass, TransformationPass 16 17 18from qiskit_trebugger.model import TranspilerLoggingHandler 19from qiskit_trebugger.model import TranspilerDataCollector 20from qiskit_trebugger.model import TranspilationSequence 21from qiskit_trebugger.views.widget.timeline_view import TimelineView 22from qiskit_trebugger.views.cli.cli_view import CLIView 23 24from .debugger_error import DebuggerError 25 26 27class Debugger: 28 """Main debugger class for thr qiskit timeline debugger. 29 30 Raises: 31 DebuggerError: if multiple quantum circuits are supplied 32 """ 33 34 @classmethod 35 def debug( 36 cls, 37 circuit: QuantumCircuit, 38 backend: Optional[Union[Backend, BackendV1, BackendV2]] = None, 39 optimization_level: Optional[int] = 0, 40 view_type: Optional[str] = "cli", 41 show: Optional[bool] = True, 42 **kwargs, 43 ): 44 """Calls the transpile method of qiskit with the given parameters 45 and populates the view of the widget with circuit diagram and 46 statistics. 47 48 Args: 49 circuit (QuantumCircuit): quantum circuit to debug 50 backend (Optional[Union[Backend, BackendV1, BackendV2]], optional): 51 Quantum Backend for execution. Defaults to None. 52 optimization_level (Optional[int], optional): 53 Optimization level of transpiler. Defaults to 0. 54 55 Raises: 56 DebuggerError: if multiple quantum circuits are supplied 57 """ 58 if view_type not in ["cli", "jupyter"]: 59 raise DebuggerError("Invalid view type supplied!") 60 61 if not isinstance(circuit, QuantumCircuit): 62 raise DebuggerError( 63 "Debugger currently supports single QuantumCircuit only!" 64 ) 65 if backend is None: 66 backend = Aer.get_backend("qasm_simulator") 67 68 if view_type == "cli": 69 if not cls._is_regular_interpreter(): 70 raise DebuggerError( 71 "Can not invoke CLI view in IPython or Juptyer Environment!" 72 ) 73 cls.view = CLIView() 74 else: 75 cls.view = TimelineView() 76 77 def on_step_callback(step): 78 cls.view.add_step(step) 79 80 # Prepare the model: 81 transpilation_sequence = TranspilationSequence(on_step_callback) 82 83 if isinstance(backend, BackendV2): 84 backend_name = backend.name 85 else: 86 backend_name = backend.name() 87 88 warnings.simplefilter("ignore") 89 90 transpilation_sequence.general_info = { 91 "backend": backend_name, 92 "optimization_level": optimization_level, 93 "qiskit version": __qiskit_version__["qiskit"], 94 "terra version": __qiskit_version__["qiskit-terra"], 95 } 96 97 transpilation_sequence.original_circuit = circuit 98 99 warnings.simplefilter("default") 100 101 Debugger.register_logging_handler(transpilation_sequence) 102 transpiler_callback = Debugger._get_data_collector(transpilation_sequence) 103 104 # Pass the model to the view: 105 cls.view.transpilation_sequence = transpilation_sequence 106 107 if view_type == "jupyter": 108 cls.view.update_params(**kwargs) 109 if show: 110 display(cls.view) 111 112 transpile( 113 circuit, 114 backend, 115 optimization_level=optimization_level, 116 callback=transpiler_callback, 117 **kwargs, 118 ) 119 120 if view_type == "jupyter": 121 cls.view.update_summary() 122 cls.view.add_class("done") 123 elif view_type == "cli": 124 curses.wrapper(cls.view.display) 125 126 @classmethod 127 def register_logging_handler(cls, transpilation_sequence): 128 """Registers logging handlers of different transpiler passes. 129 130 Args: 131 transpilation_sequence (TranspilationSequence): 132 data structure to store the transpiler 133 passes as a sequence of transpilation 134 steps 135 """ 136 137 # TODO: Do not depend on loggerDict 138 all_loggers = logging.Logger.manager.loggerDict 139 passes_loggers = { 140 key: value 141 for (key, value) in all_loggers.items() 142 if key.startswith("qiskit.transpiler.passes.") 143 } 144 145 loggers_map = {} 146 for _pass in AnalysisPass.__subclasses__(): 147 if _pass.__module__ in passes_loggers.keys(): 148 loggers_map[_pass.__module__] = _pass.__name__ 149 150 for _pass in TransformationPass.__subclasses__(): 151 if _pass.__module__ in passes_loggers.keys(): 152 loggers_map[_pass.__module__] = _pass.__name__ 153 154 handler = TranspilerLoggingHandler( 155 transpilation_sequence=transpilation_sequence, loggers_map=loggers_map 156 ) 157 logger = logging.getLogger("qiskit.transpiler.passes") 158 logger.setLevel(logging.DEBUG) 159 logger.addHandler(handler) 160 161 @classmethod 162 def _get_data_collector(cls, transpilation_sequence): 163 """Returns the data collector callback function for transpiler. 164 165 Args: 166 transpilation_sequence (list): List of transpilation steps 167 168 Returns: 169 function: Callback function for transpiler 170 """ 171 return TranspilerDataCollector(transpilation_sequence).transpiler_callback 172 173 @classmethod 174 def _is_regular_interpreter(cls): 175 """Checks if the interpreter is regular python interpreter or IPython 176 177 Returns: 178 bool: True if regular python interpreter, False otherwise 179 """ 180 try: 181 # The function get_ipython() is available on the global 182 # namespace by default when IPython is started. 183 _ = get_ipython().__class__.__name__ 184 185 # if this works, I am not in regular python 186 # interpreter 187 return False 188 except NameError: 189 return True
28class Debugger: 29 """Main debugger class for thr qiskit timeline debugger. 30 31 Raises: 32 DebuggerError: if multiple quantum circuits are supplied 33 """ 34 35 @classmethod 36 def debug( 37 cls, 38 circuit: QuantumCircuit, 39 backend: Optional[Union[Backend, BackendV1, BackendV2]] = None, 40 optimization_level: Optional[int] = 0, 41 view_type: Optional[str] = "cli", 42 show: Optional[bool] = True, 43 **kwargs, 44 ): 45 """Calls the transpile method of qiskit with the given parameters 46 and populates the view of the widget with circuit diagram and 47 statistics. 48 49 Args: 50 circuit (QuantumCircuit): quantum circuit to debug 51 backend (Optional[Union[Backend, BackendV1, BackendV2]], optional): 52 Quantum Backend for execution. Defaults to None. 53 optimization_level (Optional[int], optional): 54 Optimization level of transpiler. Defaults to 0. 55 56 Raises: 57 DebuggerError: if multiple quantum circuits are supplied 58 """ 59 if view_type not in ["cli", "jupyter"]: 60 raise DebuggerError("Invalid view type supplied!") 61 62 if not isinstance(circuit, QuantumCircuit): 63 raise DebuggerError( 64 "Debugger currently supports single QuantumCircuit only!" 65 ) 66 if backend is None: 67 backend = Aer.get_backend("qasm_simulator") 68 69 if view_type == "cli": 70 if not cls._is_regular_interpreter(): 71 raise DebuggerError( 72 "Can not invoke CLI view in IPython or Juptyer Environment!" 73 ) 74 cls.view = CLIView() 75 else: 76 cls.view = TimelineView() 77 78 def on_step_callback(step): 79 cls.view.add_step(step) 80 81 # Prepare the model: 82 transpilation_sequence = TranspilationSequence(on_step_callback) 83 84 if isinstance(backend, BackendV2): 85 backend_name = backend.name 86 else: 87 backend_name = backend.name() 88 89 warnings.simplefilter("ignore") 90 91 transpilation_sequence.general_info = { 92 "backend": backend_name, 93 "optimization_level": optimization_level, 94 "qiskit version": __qiskit_version__["qiskit"], 95 "terra version": __qiskit_version__["qiskit-terra"], 96 } 97 98 transpilation_sequence.original_circuit = circuit 99 100 warnings.simplefilter("default") 101 102 Debugger.register_logging_handler(transpilation_sequence) 103 transpiler_callback = Debugger._get_data_collector(transpilation_sequence) 104 105 # Pass the model to the view: 106 cls.view.transpilation_sequence = transpilation_sequence 107 108 if view_type == "jupyter": 109 cls.view.update_params(**kwargs) 110 if show: 111 display(cls.view) 112 113 transpile( 114 circuit, 115 backend, 116 optimization_level=optimization_level, 117 callback=transpiler_callback, 118 **kwargs, 119 ) 120 121 if view_type == "jupyter": 122 cls.view.update_summary() 123 cls.view.add_class("done") 124 elif view_type == "cli": 125 curses.wrapper(cls.view.display) 126 127 @classmethod 128 def register_logging_handler(cls, transpilation_sequence): 129 """Registers logging handlers of different transpiler passes. 130 131 Args: 132 transpilation_sequence (TranspilationSequence): 133 data structure to store the transpiler 134 passes as a sequence of transpilation 135 steps 136 """ 137 138 # TODO: Do not depend on loggerDict 139 all_loggers = logging.Logger.manager.loggerDict 140 passes_loggers = { 141 key: value 142 for (key, value) in all_loggers.items() 143 if key.startswith("qiskit.transpiler.passes.") 144 } 145 146 loggers_map = {} 147 for _pass in AnalysisPass.__subclasses__(): 148 if _pass.__module__ in passes_loggers.keys(): 149 loggers_map[_pass.__module__] = _pass.__name__ 150 151 for _pass in TransformationPass.__subclasses__(): 152 if _pass.__module__ in passes_loggers.keys(): 153 loggers_map[_pass.__module__] = _pass.__name__ 154 155 handler = TranspilerLoggingHandler( 156 transpilation_sequence=transpilation_sequence, loggers_map=loggers_map 157 ) 158 logger = logging.getLogger("qiskit.transpiler.passes") 159 logger.setLevel(logging.DEBUG) 160 logger.addHandler(handler) 161 162 @classmethod 163 def _get_data_collector(cls, transpilation_sequence): 164 """Returns the data collector callback function for transpiler. 165 166 Args: 167 transpilation_sequence (list): List of transpilation steps 168 169 Returns: 170 function: Callback function for transpiler 171 """ 172 return TranspilerDataCollector(transpilation_sequence).transpiler_callback 173 174 @classmethod 175 def _is_regular_interpreter(cls): 176 """Checks if the interpreter is regular python interpreter or IPython 177 178 Returns: 179 bool: True if regular python interpreter, False otherwise 180 """ 181 try: 182 # The function get_ipython() is available on the global 183 # namespace by default when IPython is started. 184 _ = get_ipython().__class__.__name__ 185 186 # if this works, I am not in regular python 187 # interpreter 188 return False 189 except NameError: 190 return True
Main debugger class for thr qiskit timeline debugger.
Raises: DebuggerError: if multiple quantum circuits are supplied
35 @classmethod 36 def debug( 37 cls, 38 circuit: QuantumCircuit, 39 backend: Optional[Union[Backend, BackendV1, BackendV2]] = None, 40 optimization_level: Optional[int] = 0, 41 view_type: Optional[str] = "cli", 42 show: Optional[bool] = True, 43 **kwargs, 44 ): 45 """Calls the transpile method of qiskit with the given parameters 46 and populates the view of the widget with circuit diagram and 47 statistics. 48 49 Args: 50 circuit (QuantumCircuit): quantum circuit to debug 51 backend (Optional[Union[Backend, BackendV1, BackendV2]], optional): 52 Quantum Backend for execution. Defaults to None. 53 optimization_level (Optional[int], optional): 54 Optimization level of transpiler. Defaults to 0. 55 56 Raises: 57 DebuggerError: if multiple quantum circuits are supplied 58 """ 59 if view_type not in ["cli", "jupyter"]: 60 raise DebuggerError("Invalid view type supplied!") 61 62 if not isinstance(circuit, QuantumCircuit): 63 raise DebuggerError( 64 "Debugger currently supports single QuantumCircuit only!" 65 ) 66 if backend is None: 67 backend = Aer.get_backend("qasm_simulator") 68 69 if view_type == "cli": 70 if not cls._is_regular_interpreter(): 71 raise DebuggerError( 72 "Can not invoke CLI view in IPython or Juptyer Environment!" 73 ) 74 cls.view = CLIView() 75 else: 76 cls.view = TimelineView() 77 78 def on_step_callback(step): 79 cls.view.add_step(step) 80 81 # Prepare the model: 82 transpilation_sequence = TranspilationSequence(on_step_callback) 83 84 if isinstance(backend, BackendV2): 85 backend_name = backend.name 86 else: 87 backend_name = backend.name() 88 89 warnings.simplefilter("ignore") 90 91 transpilation_sequence.general_info = { 92 "backend": backend_name, 93 "optimization_level": optimization_level, 94 "qiskit version": __qiskit_version__["qiskit"], 95 "terra version": __qiskit_version__["qiskit-terra"], 96 } 97 98 transpilation_sequence.original_circuit = circuit 99 100 warnings.simplefilter("default") 101 102 Debugger.register_logging_handler(transpilation_sequence) 103 transpiler_callback = Debugger._get_data_collector(transpilation_sequence) 104 105 # Pass the model to the view: 106 cls.view.transpilation_sequence = transpilation_sequence 107 108 if view_type == "jupyter": 109 cls.view.update_params(**kwargs) 110 if show: 111 display(cls.view) 112 113 transpile( 114 circuit, 115 backend, 116 optimization_level=optimization_level, 117 callback=transpiler_callback, 118 **kwargs, 119 ) 120 121 if view_type == "jupyter": 122 cls.view.update_summary() 123 cls.view.add_class("done") 124 elif view_type == "cli": 125 curses.wrapper(cls.view.display)
Calls the transpile method of qiskit with the given parameters and populates the view of the widget with circuit diagram and statistics.
Args: circuit (QuantumCircuit): quantum circuit to debug backend (Optional[Union[Backend, BackendV1, BackendV2]], optional): Quantum Backend for execution. Defaults to None. optimization_level (Optional[int], optional): Optimization level of transpiler. Defaults to 0.
Raises: DebuggerError: if multiple quantum circuits are supplied
127 @classmethod 128 def register_logging_handler(cls, transpilation_sequence): 129 """Registers logging handlers of different transpiler passes. 130 131 Args: 132 transpilation_sequence (TranspilationSequence): 133 data structure to store the transpiler 134 passes as a sequence of transpilation 135 steps 136 """ 137 138 # TODO: Do not depend on loggerDict 139 all_loggers = logging.Logger.manager.loggerDict 140 passes_loggers = { 141 key: value 142 for (key, value) in all_loggers.items() 143 if key.startswith("qiskit.transpiler.passes.") 144 } 145 146 loggers_map = {} 147 for _pass in AnalysisPass.__subclasses__(): 148 if _pass.__module__ in passes_loggers.keys(): 149 loggers_map[_pass.__module__] = _pass.__name__ 150 151 for _pass in TransformationPass.__subclasses__(): 152 if _pass.__module__ in passes_loggers.keys(): 153 loggers_map[_pass.__module__] = _pass.__name__ 154 155 handler = TranspilerLoggingHandler( 156 transpilation_sequence=transpilation_sequence, loggers_map=loggers_map 157 ) 158 logger = logging.getLogger("qiskit.transpiler.passes") 159 logger.setLevel(logging.DEBUG) 160 logger.addHandler(handler)
Registers logging handlers of different transpiler passes.
Args: transpilation_sequence (TranspilationSequence): data structure to store the transpiler passes as a sequence of transpilation steps