Interactive Debugging¶
MQT Debugger provides various methods to interactively debug quantum programs. It can be used to step through the program and inspect the state of the system. This document further details the debugging capabilities provided by this framework.
As MQT Debugger currently only supports OpenQASM as input language, this document will give examples and details related to OpenQASM programs. However, due to the modular nature of this framework, it can be extended to support other languages as well.
Stepping Through the Program¶
The most basic debugging feature is stepping through the program. Like many typical interactive debuggers, this framework supports three types of steps:
Single Step: Executes the next instruction and stops afterwards. If the next instruction is a function call, it will step into the function.
Step Over: Executes the next instruction and stops afterwards. If the next instruction is a function call, it will execute the entire function at once.
Step Out: Continues execution until the current function returns.
However, due to the reversibility of quantum programs, the debugger can also step backward:
Single Step Backward: Reverts the last instruction and stops afterwards. If the last instruction was a function call, it will only stop at the last instruction of that function.
Step Over Backward: Reverts the last instruction and stops afterwards. If the last instruction was a function call, it will revert the entire function at once.
Step Out Backward: Reverts all instructions in the current function scope and stops at the instruction calling the function of the current scope.
Continuing and Pausing Execution¶
In contrast to individual steps, the debugger can also be used to continue the entire program execution, using the SimulationState::runSimulation/SimulationState.run_simulation method.
This will execute the program until the end or until a breakpoint or a failing assertion is reached.
Additionally, the SimulationState::runAll/SimulationState.run_all method can be used to run the program without stopping, instead counting how many failing assertions were encountered.
Furthermore, the SimulationState::pauseSimulation/SimulationState.pause_simulation method can be used to pause the execution at any point in time.
Inspecting the State¶
MQT Debugger distinguishes between classical variables and quantum variables. For OpenQASM, currently only boolean classical variables are supported.
The framework provides different methods to inspect the state of the system at runtime. Classical variables can be accessed using the SimulationState::getClassicalVariable/SimulationState.get_classical_variable method, passing the name of the desired variable, which returns an object representing the variable.
Quantum variables cannot be accessed directly, but the developer can instead access the statevector to inspect the quantum state at any point in time. SimulationState::getStateVectorFull/SimulationState.get_state_vector_full can be used to obtain the full statevector of the system. As this statevector can be very large, SimulationState::getStateVectorSub/SimulationState.get_state_vector_sub can be used to obtain a sub-statevector of the system, containing just a subset of all qubits. In this case, the qubits included in the sub-statevector must not be entangled with any qubits outside it.
Furthermore, the framework also allows to inspect individual amplitude values of the statevector using SimulationState::getAmplitudeIndex/SimulationState.get_amplitude_index or SimulationState::getAmplitudeBitstring/SimulationState.get_amplitude_bitstring. In these cases, the developer must identify the desired amplitude by passing either the index of the amplitude or the bitstring that represents the desired state.
Breakpoints¶
Breakpoints can be set to force execution to stop at a specific instruction. To be compatible with the typical protocols, setting a breakpoint requires the character index in the source code, at which the breakpoint should be set. MQT Debugger will then determine the instruction that corresponds to this location in the code and stop execution there in the future.
To set a breakpoint, the SimulationState::setBreakpoint/SimulationState.set_breakpoint method can be used, passing the desired character index. This method will return the instruction index at which the breakpoint was set (Python) or store it in the provided reference (C++).
To remove breakpoints, the SimulationState::clearBreakpoints/SimulationState.clear_breakpoints method can be used, removing all breakpoints.
When a program is paused during execution, the methods SimulationState::wasBreakpointHit/SimulationState.was_breakpoint_hit can be used to check whether the current pause was caused by a breakpoint. This allows developers to distinguish between pauses due to breakpoints and pauses due to other reasons, such as failed assertions.
Assertions¶
MQT Debugger supports assertions to check the state of the system at runtime. If an assertion fails, the debugger will pause execution before the failing instruction.
Any methods to step through the program will pause at a failing assertion. Continuing execution after hitting a failed assertion will skip the failing instruction and continue with the next one.
When a program is paused during execution, the methods SimulationState::didAssertionFail/SimulationState.did_assertion_fail can be used to check whether the current pause was caused by a failing assertion. This allows developers to distinguish between pauses due to assertions and pauses due to other reasons, such as breakpoints.