Testing and Debugging Quantum Circuits

This paper introduces a process framework for debugging quantum circuits, focusing on three distinct types of circuit blocks: Amplitude Permutation, Phase Modulation, and Amplitude Redistribution circuit blocks. Our research addresses the critical need for specialized debugging approaches tailored to the unique properties of each circuit type. For Amplitude Permutation Circuits, we propose techniques to correct amplitude permutations mimicking classical operations. In phase modulation circuits, our proposed strategy targets the precise calibration of phase alterations essential for quantum computations. The most complex Amplitude Redistribution Circuits demand advanced methods to adjust probability amplitudes. This research bridges a vital gap in current methodologies and lays the groundwork for future advancements in quantum circuit debugging. Our contributions are twofold: We present a comprehensive unit testing tool (Cirquo) and debugging approaches tailored to the unique demands of quantum computing, and we provide empirical evidence of its effectiveness in optimizing quantum circuit performance. This work is a crucial step toward realizing robust quantum computing systems and their applications in various domains.

INDEX TERMS Quantum Programs, Quantum Software, Debugging, Testing.

I. INTRODUCTION
During the past several decades, quantum computing has moved from an idea in scientists' minds to the actual systems we have today.Today, quantum computers exist on a small and error-prone level [2], [3] known as NISQ (Noisy Intermediate Scale Quantum computers).Through that journey, researchers in maths, physics, and computer science worked together to develop algorithms that can harness the strength quantum computers can provide in the future [4].Even though quantum technology has advanced rapidly, both the hardware and software aspects of quantum computing are still in their early stages.Hence, scalability is one of the main challenges we need to overcome on both the hardware and the software sides.We need bigger computers, fault-tolerant qubits, and stable software engineering approaches to build real-life, valuable applications on quantum computers [5].
In classical software, the development process follows a mature cycle.Two critical stages of the cycle are testing and debugging, and maintaining the application.The application's abstract aspects may be tested with formal specifications, pseudocode, modeling tools, etc. Bugs arise from errors in the specification of a program, in translating the specification into code, or, sometimes, from bugs in the tools themselves.Currently, there are many approaches to testing classical software, both formal and informal [6]- [8].Approaches such as unit testing, regression testing, continuous integration, and path coverage testing make building and supporting systems as complex as tens of millions of lines of code, such as the Linux kernel, possible [9], [10].
Like the classical software development cycle, the quantum software development cycle shown in Figure 1 describes the process of developing software for quantum computers as proposed in [11].Since quantum computers can operate on the superposition of values (each with a complex amplitude [12], [13]), the exponential growth in the state space poses a fundamental problem in testing and debugging quantum programs.
When we want to test a quantum circuit, we often have to consider the behavior of all possible inputs as a set.That exponential growth in the input state space poses fundamental challenges during the testing and debugging process.
The first and perhaps most important challenge is the principle on which quantum algorithms operate.Often, the goal of quantum algorithms is not to find a solution to a problem but rather to build interference patterns that amplify the amplitude of correct answers at the expense of the incorrect ones.
FIGURE 1: A general life cycle of classical vs. quantum software as described in [11].
Today, developers can use different approaches to transform their ideas and algorithms into quantum programs [14], [15].If they can develop and implement their algorithms efficiently, leading to small-scale circuits, they can try executing them on actual quantum hardware.Otherwise, they can implement a smaller version of the algorithm and try to extrapolate its behavior for larger instances of the problem.Today's approaches can be categorized into four categories based on the programming model.
• High-level quantum programming language (QPL) supporting the developer's quantum intuition such as Silq [16], Q# [17], and Quipper [18].• Gate-level programming In this option, the developer translates their idea into a sequence of gates and then simulates this circuit, visualizes it, or runs it on a hardware device.Developers can use this approach in different ways: -Building the circuit using code often using a classical-language-supported library or package, such as Qiskit [19], Cirq [20], Tket [21], and PyQuil [22] which are Python Packages.-Using a drag-and-drop tool to build the circuit, simulate the results, and view them visually.These tools include QUI [23], the IBM Circuit Composer [24], and Quirk [25].
-Using the Quantum Assembly language or QASM [26].• Building the circuit using a low-level approach such pulses and signals to control the quantum hardware directly.The main example is OpenPulse [19].A summary of some of the most widely used quantum software tools can be seen in Table 1.All of these tools mainly focus on the current generation of hardware, small programs, and the critical problems of optimization and mapping to specific processors [27]- [31], as well as on designing and implementing programs for hybrid or adaptive algorithms [32]- [36].
The responsibility typically falls on developers to thoughtfully plan and manually execute algorithms, as well as to develop tests for checking their outputs using simulators or by reevaluating the underlying mathematics.Yet, this strategy proves impractical when the circuit complexity grows, the current hardware cannot execute them without high error rates, or when classical computers are unable to simulate them effectively.
In this work, we extend upon the tool proposed in [1] and offer strategies to debug different quantum circuit types.The ideas of this work are built using Qiskit and Python.Cirquo (the unit-testing package used in this paper) includes a slicer that allows developers to divide their circuits into smaller chunks, categorize, and test them.
The rest of this paper is organized as follows: • Section II addresses the possible types of bugs that can occur in quantum programs.• Section III introduces the different types of quantum circuits and the characteristics of each of those types.• Section IV offers an approach to testing and locating bugs in the different types of circuits.• Section V wraps up the paper with a discussion of the limitations and challenges of the proposed ideas and approaches and how we can challenge limitations to benefit from these approaches the most.

II. THE SOURCES OF BUGS IN QUANTUM PROGRAMS
Since understanding the flow of quantum programs and the causes of errors is essential for the ability to debug quantum circuits, researchers focused on categorizing reproducible bugs in quantum programs [44]- [46].In these studies, researchers found that bugs in quantum programs can occur for two reasons: the platform used or the developer's implementation.Platform-related errors arise due to a fault in the implementation of the core functionality of the platform, such as deprecation errors, math errors in function implementations, and mistakes in data handling.Paltenghi et al. look in-depth at the bugs introduced by the quantum platform [47].On the other hand, bugs introduced by the developer cover incidents such as the wrong type/ordering of the gates or misuse of the package functions.Both categories will either throw a runtime exception, which is easy to catch and fix, or lead to the wrong answer, making them potentially more challenging to locate and fix.[19] Gate-level 2017 IBM Python Package Q# [17] Gate-level 2017 Microsoft Quantum PL QX Simulator [38] QASM-based 2017 QuTech QASM Ocean SDK [39] Gate-level 2018 D:Wave Python Package Cirq [20] Gate-level 2018 Google (not an official product) Python Package Pyquil [22] Gate-level 2018 Rigetti Python Package QUI [23] Drag and Drop 2018 Hollenberg Group at the University of Melbourne Quantum PL PennyLane [40] Gate-level 2018 Xanadu Python Package Q.js [41] Drag and Drop 2020 Stewart Smith JavaScript Package Silq [16] High-level 2020 ETH Zurich Quantum PL Amazon-Braket [42] Gate-level 2020 Amazon Python Package TKET [21] Gate-level 2021 Quantinuum Python Package Intel SDK [43] Gate-level 2023 Intel C++ Library A quantum bug, at a high level, is an error in creating the correct interference patterns, which can happen due to different reasons depending on the algorithm the programmer is implementing.For example, suppose the programmer is writing an implementation for Grover or Shor's algorithms.In that case, the cause of interference pattern errors can be due to failure in cleaning or detangling the ancilla qubits, a mistake in marking the correct state/s, an improper implementation of the diffusion operator, or, possibly, a combination of all the above.On the other hand, if the programmer implements a quantum chemistry or physics simulation, the errors are "mathematical" due to using the wrong Hamiltonian.Moreover, if the programmer is implementing a variational quantum algorithm (VQA), such as Variational QUantum Eigensolver (VQE) or Quantum Approximate Optimization Algorithm (QAOA), then the source of error could be the wrong ansatz or a mistake in setting the parameters of the classical optimizer.
Though all these bugs manifest as wrong interference patterns, on a circuit level, they translate to using the wrong gate types/ order, applying the wrong phases, or a combination of both.Section IV covers different types of bugs and how Cirquo can assist in locating them.

III. THE DIFFERENT TYPES OF QUANTUM CIRCUITS
Classical debugging tools result from decades of research, trials, and developments in software development [48], [49].The most basic and well-known concept of testing and debugging classical software is program slicing [50].Program slicing is an approach to dividing a larger program into smaller chunks-slices-to make examining and analyzing it more manageable.
Classically, slices are formed in two ways: manually using breakpoints [51] or automatic/semiautomatic slicing.In manual slicing, the programmer inserts breakpoints in various locations in the code so that the debugger can divide the code accordingly.

A. CIRCUIT SLICING
Considering the general structure of most quantum algorithms, we notice that they tend to follow a set of steps to solve a problem.Many quantum algorithms start by preparing the working qubits in a specific state or uniform superposition, performing some arithmetic calculations [52], then redistributing the amplitudes and measuring the results.In the case of some algorithms, we may need to repeat the arithmetic and amplitude distribution steps.Moreover, in most cases quantum algorithms are accompanied by classical pre-processing or post-processing after the measurement procedure (Figure 2).For example, Grover's algorithm consists of three main algorithmic steps: preparing the qubits in a uniform superposition, followed by a problem-specific oracle, and then a diffusion operator.In the algorithm, the oracle and diffusion will be repeated multiple times until the amplitude of the answer is predicted to be maximized.Because of this clear distinction between the algorithmic steps, we can test and examine these steps individually when testing the implementation of an algorithm.Then, put them together to form the target algorithm.
We can use a similar approach to program slicing clas-sically.We will refer to that as a circuit slicer.The circuit slicer will divide a large circuit into smaller, executable (or simulatable) subcircuits to demonstrate the functionality of the circuit using both NISQ (Noisy Intermediate-scale Quantum Computers) [2] devices and fault-tolerant quantum computers.In Cirquo's manual circuit slicer, the user inserts breakpoints (in the case of quantum circuits, breakbarriers) in the circuit and then simulates the resultant slices or runs them on an actual device to observe their behavior.Considering that quantum circuits are two-dimensional, the slicer can slice the circuits on two axes, the gate axis (vertically) or the qubits/registers axis (horizontally) to remove unused qubits.

1) Vertical Slicing
To explain the methodology and concept of slicing, let us think of a circuit corresponding to Grover's algorithm [53].We can use breakbarriers to divide the circuit into slices based on each algorithmic step: the initial state preparation, an oracle, and the diffusion operator.To keep things simple, assume that the Grover's algorithm we are slicing consists of one iteration.We will insert two breakbarriers to slice this circuit, one after the state preparation and one after the oracle.This will result in three subcircuits, each performing a specific step in the overall algorithm.

2) Horizontal Slicing
Sometimes, after slicing the circuit vertically, we may end up with a slice that contains some unused qubits.Since our goal of slicing the circuit is to create smaller, simulatable, executable circuits, having unused qubits is redundant.Hence, we can do horizontal slicing to remove these unused qubits from the slice.The current version of the tool only allows for the automatic slicing of unused qubits.Future expansion will allow users to manually insert horizontal breakbarriers in the case of slices with two independent registers or if the user wants only to include a specific set of qubits.
One main challenge of slicing quantum circuits horizontally is cross-register entanglement before the slice; a way to address that uses the Kronecker product to overcome the challenge of considering the effect of the slice.For example, if we cut only one wire, we get a 4 k Kronecker product, where k is the number of qubit wires cut.The math used to develop CutQC [54] indicates that the probability of the measurement of an input state |ψ⟩ for the unsliced circuit must be equal to the sum of possibilities of the same state for the slices following Equation 1, where N is the number of subcircuits resultant from the slicing.
If the programmer uses a NISQ machine to execute the slices and the original circuit, they need to use an efficient number of shots to achieve good coverage of the possibilities of measuring the different states.

B. CATEGORIZING CIRCUITS
Considering the construction of quantum algorithms, we can see they consist of three types of building blocks: • Amplitude-Permutation (AP) Blocks permute the amplitudes of quantum states.These circuits mimic the operation of reversible classical logic within the quantum realm.Hence, only rearranging the amplitudes associated with the quantum states without redistributing them or altering their phases.An example is a quantum adder or Grover's oracle.Those blocks are essentially classical reversible logic [55], [56].Mathematically, for set of states α j |j⟩, an AP block can be defined as Where Π(j) is a permutation function.A permutation matrix has exactly one 1 in each row and column.An example of a 2-qubit AP block unitary is • Phase-Modulation (PM) Blocks Quantum circuits that focus exclusively on altering the phases of quantum states without changing their amplitudes.The primary function of these circuits is to introduce phase shifts based on values of certain qubits.Mathematically, for set of states α j |j⟩, a PM block can be defined as where f (j) is a function that calculates the phase shift of a state θ j , f (j) ∈ R. The unitary of a PM block will be a diagonal matrix D with D jj = e iπθj .• Amplitude-Redistribution (AR) Blocks Unlike the Amplitude-Permutation Circuits, these circuits redistribute the amplitudes across various quantum states, thereby harnessing the full potential of quantum superposition and entanglement.An example of an AR block is the Quantum Fourier Transform (QFT).An AR block contains gates that alter interference patterns and create or destroy superposition.AR blocks can be represented as Where Here, U is a unitary matrix applied to the qubits.Often, we can run the AP and PM blocks without the states being in superposition.An example is applying a NOT gate on the least significant qubit (LSQB) in a two-qubit register shown in Figure 4-A (details about reading a Q-sphere are in Appendix B).This will only permute the amplitude of the states but not affect the superposition or the interference patterns.Similarly, if we apply a T gate on the LSQB of a

Grover's Oracle
Slice 1+2  3: A generic Grover's algorithm circuit is sliced using both stand-alone slicing and accumulated slicing, then one of the slices is horizontally sliced to remove unused qubits.two-qubit system, it will only affect the phase of the states (Figure 4-B).Though Grover's oracle is a PM block, Grover's iterator (the combination of the oracle and the diffusion operator) would be an AR block.Figure 4-C shows the Q-sphere before and after applying Grover's iterator to a 3-qubit circuit.

IV. TESTING DIFFERENT CIRCUIT TYPES
To build a framework for testing and debugging quantum programs, first, we must consider the steps of testing a quantum circuit.Testing a quantum circuit involves several steps, each of which plays a vital role in ensuring the functionality and accuracy of the computations.We can set the needed steps as follows: 1) Writing Code: This step involves creating the quantum circuit using the specialized quantum programming languages or quantum packages supported by classical programming languages (Section I).2) Writing Tests: Creating test vectors for the circuit and specific parts.This step includes several sub-steps.
• Slicing the Circuit: Dividing the circuit into smaller segments for efficient testing.• Categorizing Slices: Categorizing the slices based on their functionality within the circuit.• Choosing Optimal Number of Shots: Determining the number of circuit executions to balance accuracy and computational resource usage is discussed below.4) Integration: Resolving issues arise when a slice, which works independently, fails upon integration.5) Running Tests: Executing the developed test cases against the slices of the quantum circuit and comparing the actual behavior with the expected one.This step can be done on a simulator (if the slice size allows) or an actual device.6) Error Isolation and Additional Testing: If an error is detected, the problematic slice is isolated and subjected to further focused testing to pinpoint and understand the bug.
These steps provide a systematic approach to this section's testing and debugging process.
As discussed in Section III-A.3, we divided quantum circuits into three types with entirely different properties, making the process of testing and debugging them significantly different.Moreover, testing and debugging the same type will vary depending on its size and the type of instructions it contains.
AP blocks behave like classical programs; hence, we can use classical approaches when testing them.Therefore, the challenge when testing them would primarily be the difficulty of generating test cases that can provide full coverage.For example, for an adder, we can test a few simple inputs using single amplitudes (no superposition), including overflow cases, and reason by induction for the rest.Unfortunately, that approach cannot be extended when we deal with AR and PM blocks because they contain quantum properties that are hard to address using traditional testing and debugging techniques.
Although creating test vectors for AR and PM blocks is not as simple as doing so for the AP blocks, creating test vectors for simple AR and PM blocks should be slightly more straightforward than the complex ones.For example, creating test vectors for a 4-qubit block that contains only 4 Hadamard gates is more straightforward than creating test vectors for a circuit of 20 qubits and 60 different gates.
The size of the block and the types of instructions in it are not the only challenges we face when testing and debugging AR and PM blocks.
To explain the different strategies for debugging the blocks, we will use the testing functions offered by Cirquo (the complete functionality can be found in Appendix A).
Before we discuss the different approaches for each type, we need to discuss an approach to testing PM blocks.To do that, we must define a few important terms: • U DU T : Device Under Test, which refers to the slice we are testing/ debugging.• U T V i : Test Vector i, is the circuit corresponding to applying test vector i to U DU T .The results of this is |ψ⟩ T Oi , where Because this is specific to a single test vector, it will be substantially simpler than U DU T .
Figure 5 shows an approach to testing any quantum circuit (regardless of its type).Essentially, what we want to answer is the question: Does |ψ⟩ T Oi = |ψ⟩ EOi ?If the slice we are testing is correct, these two states are equal; if not, we can conclude that something is incorrect in the test circuit and proceed with the debugging process.The debugging process will then differ based on the circuit block we target.

A. TESTING AND DEBUGGING AMPLITUDE PERMUTATION (AP) BLOCKS
As explained in Section III, AP blocks are quantum circuits that mimic the behavior of reversible classic logic.When creating test vectors for an AP block, we follow the same approach for creating test vectors for classical programs.Often, when we create test vectors, the approach follows systematically, covering all possible input combinations and edge cases to verify their functionality thoroughly.
However, as our target circuits grow, creating test vectors for all possible cases will be increasingly challenging.There, we can focus on some practical cases and edge cases.
One example of an AP block is the quantum full adder.The full adder is a 4-qubit system, where the inputs are |A⟩, |B⟩, |C in ⟩, and |0⟩.|A⟩ and |B⟩ are the qubits we wish to add and |C in ⟩ is the carry-in.The outputs of the full adder are |A⟩, |B⟩, |S⟩, and |C out ⟩ (Listing 1, Figure 6).
1 def Quant_full_adder(qc, in_qbits,zero_qubit): [1],in_qbits [2],zero_qubit) 5 qc.cx(in_qbits [1],in_qbits [2]) The full adder has three inputs A, B, and C in , resulting in a total of 2 3 = 8 possible input states.Optimally, we can create 8 test vectors for all possible cases.This will ensure every possible state is checked, including edge cases such as all inputs being 0 or all being 1 and transitions between these states.We will test our circuit on the five test vectors in Listing 2. Listing 2: Test vectors for the full adder.
Running the circuit for these test vectors using Cirquo's pClassTester(qc, test_cases) results in a PASS for all the tests.Now, we introduce a simple bug to this program.Assume the programmer inadvertently added an extra Toffoli gate at the end of the circuit qc.ccx(in_qbits[0],in_qbits [1],zero_qubit).The first step is running the same tests from before to the program containing the bug.This will lead to two test vectors having a FAIL status, as seen in Listing 3.
When we examine the results, we see that the error occurs only when both qubits |A⟩ and |B⟩ are 1.
1 Testing test 1:  In this case, since the error only occurs when the first two qubits are 1, we might guess that they are the control of the gate causing the error.We can locate the multi-qubit gates applied to these two qubits using the gateLoc(qc,' cx', qubits=['q[0]','q[1]']) function, which will lead us to two Toffoli gates, and then we can remove each of them and test the circuit again.Doing so points out that the last Toffoli gate is the source of the error.
AP blocks are deterministic, so only a single shot is required for each test vector (on an FT system).Test vectors should be selected for larger circuit blocks to provide good logic coverage.For example, an n-qubit adder often is designed to execute |a⟩|b⟩|0⟩ → |a⟩|a + b mod 2 n ⟩|0⟩ (where the last register is ancillae that must be cleaned) [57].We might choose to confirm that adding zero, adding one, carrying within a register, and carry out of the register all work properly.Thus, a reasonable set of test vectors for n = 4 might be |0000⟩|1111⟩|0⟩, |0001⟩|0011⟩|0⟩, and |0001⟩|1111⟩|0⟩.

B. TESTING AND DEBUGGING PHASE MODULATION (PM) BLOCKS
Testing and debugging AP blocks were relatively straightforward; however, moving on to the PM and AR blocks gets more challenging.This subsection will consider a strategy for debugging a PM block.The most straightforward PM block would be a circuit containing any phase gate, such as a T, Z, CZ, or S gate.
The challenge in creating test vectors for PM blocks is choosing the correct tests to detect subtle phase shifts.These shifts, often representing the core computational output of the circuit, require high precision in both the generation and measurement phases.The approach typically involves initializing the circuit in a superposition state where the effects of phase modulation can be maximally observed.Cirquo's fQuantTester(circuit, test_vectors) allows users to use their test vectors as state vectors to perform unit testing on PM and AR blocks.
Though the test in Figure 5 can tell us whether an error in the circuit exists, it can not provide further information about that error.However, we can use other approaches to get more information about the possible error.
The strategy we propose here is to use the swap test [58].The swap test is a fundamental quantum computing procedure used to determine the similarity between two quantum states.It is beneficial for measuring the inner product of two states, which can then be utilized to calculate their fidelity or similarity.
Consider two quantum states |ψ⟩ and |ϕ⟩ that we want to compare.The swap test involves an ancillary qubit (the control qubit) initialized in the state |0⟩ and the two states |ψ⟩ and |ϕ⟩.The process of the swap test involves the following steps: 1) Apply a Hadamard gate to the control qubit, putting it into the superposition The outcome of the measurement gives us information about the similarity of the two states.If the states are identical, the probability of measuring |0⟩ in the control qubit will be 1.If they are orthogonal, the probability will be 1  2 .We can further analyze the swap test results for more information about the phase difference.To do that, consider |ψ⟩ = |0⟩ + e iθ1 |1⟩ and |ϕ⟩ = |0⟩ + e iθ2 |1⟩.We can then recalculate the probability of measuring 1 or 0 as a function of θ 1 and θ 2 as follows: The inner product of these two states is We need to find the magnitude squared of this inner product.Since e i(θ2−θ1) can be expressed as cos(θ 2 − θ 1 ) + i sin(θ 2 − θ 1 ), and ∆θ = θ 2 − θ 1 we get 1 + e i(∆θ) (7) The probability P (0) is given by Substituting the magnitude squared into this, we get Since P (1) = 1 − P (0), we substitute our expression for P (0) and simplify After implementing the swap test in Qiskit (Listing 4), we calculate the squared inner product using the number of shots using the equation s = 1 − 2 N B. s is the squared inner product, N is the total number of shots, and B is the number of times 1 was measured.
To see this better, assume we have the circuit shown in Figure 7.
In testing the circuit, the programmer will first use the technique in Figure 5. Assuming that test returns something other than |0⟩, meaning U DU T U T V i ̸ = U † EOi , the next step is to attempt to isolate the bug.It is useful to find the angle of the extra (or missing) angle, as well as to find the qubit(s) with the extra gate.
We can denote that phase error as a gate P applied to |ϕ⟩ then use the swap test to determine that phase.To do that we use Cirquo's applySwapTest(circuit, k, reg1_index, reg2_index, nshots), with nshots = 8192.In this example, let us say that we found s = 0.76.The function will also return the value of ∆θ calculated according to In our example, we get ∆θ = π 3 .From that we can infer the presence of an extraneous Z( π 3 ) gate.
Two common errors will be (a) applying the correct phase shift to the wrong qubit, and (b) applying the wrong phase shift to the right qubit (including omitting a needed gate).(For simplicity, we omit controlled phase gates here.)Test vectors need to be prepared to help us distinguish these two cases.For example, the unitary for a three-qubit phase slice is shown in Figure 8.

U = FIGURE 8:
The unitary for a three-qubit phase slice.The colored boxes delineate terms affected by errors in the highorder (red), middle (blue), and low-order (green) qubits.
A phase gate on the high-order qubit will be reflected in the values in the red box, the middle qubit in the blue boxes, and the low-order qubit in the green boxes.Testing the input |000⟩ + |111⟩ will tell us if the sum of the phase shifts on all three qubits is correct.If it is not correct, enough shots of the test can tell us the incorrect angle but do not tell us where to look.For independent, single-qubit gates, testing the cases |000⟩ + |001⟩, |000⟩ + |010⟩, and |000⟩ + |100⟩ can isolate the qubit with the error.If the slice contains controlled phase gates, we may need a larger set of test vectors, e.g., |110⟩ + |111⟩.With careful test vector design, we can test a small number of cases, hopefully, O(n) or Õ(n) to develop high confidence in the behavior of the entire slice, which has 2 n angles θ i , each potentially different.

C. TESTING AND DEBUGGING AMPLITUDE REDISTRIBUTION (AR) BLOCKS
Testing and debugging AR blocks can be quite challenging.However, once we differentiate between PM and AR blocks, we can use different approaches to test and debug them.We just discussed how the swap test could be utilized to debug PM blocks.Though we can still use the swap test or the approach in Figure 5 to validate the results from AR blocks, they will not provide much information that we can use except for the degree of difference between the expected and resultant states.
In most cases, AR blocks will be functions offered by the package the user decides to use.Hence, they often will not need to build it from scratch.However, it is essential to address how developers can create helpful test vectors for AR blocks.
The primary challenge here is the exponential increase in complexity with the number of qubits, which makes exhaustive testing impractical for larger circuits.AP and PM circuits allowed us to work with single amplitudes for each test, but AR circuits depend on interference, and can change the number of non-zero amplitudes, substantially complicating tests, especially in terms of interpreting test outputs.Additionally, since amplitude redistribution can result in highly entangled states, ensuring that the generated test vectors adequately reflect the potential entanglement patterns is crucial for thorough testing.
Simulation, induction or inference from smaller cases, and sampling techniques to assess distributions become essential, with the aim of capturing the most significant aspects of amplitude redistribution with a manageable number of test vectors.
Consider the Quantum Fourier Transform (QFT), a fundamental operation in quantum computing, pivotal for algorithms like Shor's algorithm [59] for factoring and quantum phase estimation.Ensuring its correct implementation is vital for the success of these quantum algorithms.The QFT on an n-qubit state is defined as A general implementation using Qiskit can be seen in Listing 5.The code here offers an important clue to debugging AR circuits: the code is parameterized in n, the number of qubits in the QFT.Thus, the programmer can test and debug their code using small values of n and develop confidence in the behavior of larger instances.We can use simulators as well as Cirquo's functions for examining the code to test propositions about the circuit.
"""Applies QFT on the first n qubits in circuit""" for j in range(n): for j in range(n//2): Listing 5: An Implementation of the QFT using Qiskit.
One approach to creating efficient test vectors is to focus on the properties of the QFT, such as linear shift-invariance and parallelism.
In this example, we will focus on the linear shift-invariant aspect of the QFT.This result of applying the QFT on a periodic state shows the periodicity and phase relations encoded by the original state transformed into a new superposition reflecting these frequency domain properties.A periodic nqubit state (|ψ(n, r, l)⟩) is a state that shows a periodic behavior and can be defined by its period r and its shift l.We can express that as where c k are the coefficients of the computational basis states |k⟩, and they reflect the periodicity and shift of the state.Specifically, c k is non-zero for states |k⟩ that satisfy (k − l) mod r = 0.For example, consider |ψ(3, 2, 1)⟩ We can now apply the QFT to state |ψ(3, 2, 1)⟩ and observe how it preserves the period while transforming it to the frequency domain.For a 3-qubit system (n = 3), the QFT equation simplifies to We can see the circuit for a 3-qubit QFT in Figure 9. Applying the QFT to |ψ(2, 1)⟩ gives After simplifying this equation, we get The calculation demonstrates how the QFT reveals the periodicity and phase relationships encoded in the original state |ψ(n, r, l)⟩, transforming it into a new superposition that reflects these properties in the frequency domain.That effect can be seen in Figure 9-A.
Consider the QFT for n = 1024; full simulation of this circuit is well beyond classical capabilities.For a faulttolerant machine, we expect to use it frequently.In Shor's algorithm, the QFT is far less expensive than the modular exponentiation portion of the circuit, and so the execution cost will be reasonable.As a first test, the programmer can run the full QFT circuit on a chosen test vector or set of test vectors using the approach of Figure 5.If this test returns an error, the next step is to reduce the scale of the tests to something that can be simulated.
Assume that the user forgot to apply a Hadamard gate to qubit 0 at the beginning of the algorithm's implementation.(This kind of error can be expected to be common, as a result of off-by-one programming mistakes in loops, as in Listing 5.) Simulating the circuit for |ψ(3, 2, 1)⟩ will lead to the results shown in Figure 10-B.We can see that the output does not match our expected results but we do not know what might be causing the error.Because the most common error when implementing quantum algorithms is often a missing/extra gate, we can get the gates count using Qiskit's count_ops().However, this will only return the total count, including the measurement, which can be helpful to use with Cirquo's gateLoc() to get the specific qubit and line of code where a gate was added.
We know that an n-qubit QFT includes n Hadamard gates, n(n−1) 2 controlled phase rotations are required, and n 2 SWAP gates.These two functions allow us to discover that qubit 0 has no Hadamard gates applied; adding one (or correcting the loop conditions) and executing the circuit again fixes the error.Repeating the smaller tests up to the limit of simulation, followed by re-testing the full circuit on the FT computer, increases our confidence in the overall circuit.
In the prior subsections, we worked with single ampli-tudes in test vectors.Because AR blocks modify the set of amplitudes, the output of a single-amplitude input will be a multiple-amplitude output.With many amplitudes, testing results will be stochastic, and reconstructing the amplitude distribution will be difficult.An alternative would be to engineer an input test vector to generate a single amplitude on output.We could do this, for example, by taking a desired output, directly calculating the inverse of the AR block, and using the output of that as the initial input test vector.Unfortunately, in many cases, the direct creation of that input vector will be as complicated as the full AR block.However, the approaches shown in Figures 5 and 7 can be used, for example, to confirm that a new implementation of the QFT produces the same output as a standard library implementation.Working entirely from scratch will be difficult, but once bootstrapped comparing versions with new optimizations or features can be more straightforward using these techniques.

V. DISCUSSION
One significant challenge in quantum program testing is the complexity of quantum programs.Unlike classical programs, quantum programs often involve entangled states and superpositions, making isolating and identifying bugs difficult.Techniques from classical debugging, such as binary search debugging, can be extended and adapted for quantum computing.This involves dividing the quantum program into smaller sections, testing them individually, and eliminating those without bugs [60]- [62].Though that can be beneficial in some cases, quantum-specific challenges, such as crossregister entanglement, require novel solutions.

A. RELATED WORK
Some classical approaches can be adapted on the quantum side, such as "slicing."Quantum circuits can be sliced horizontally and vertically into smaller sections that are easier to test and debug.This, however, is not as straightforward as the classical slicing, as we need to address the entanglement within the circuit.This can be done using the Kronecker product as discussed by CutQC [63].Other approaches include hypothesis testing, a statistical method adapted to observe and analyze the behavior of quantum circuits under different inputs [64], [65].In addition to runtime testing and debugging of quantum circuits using statistical methods [11], [66]- [68].
The most complete quantum development tool is Microsoft's Q#, which offers unit testing functionality for quantum circuits for NISQ-era quantum program [69].However, writing efficient test cases for quantum circuits can be challenging, especially if the type of circuit is unknown.Q# recently added a visual quantum resource estimation so users can track the execution of their programs on the hardware.
IBM has made a similar effort with Qiskit's Trebugger [70].The Trebugger is a debugger for the transpiler offered by Qiskit.Though both the Q# resource estimation and Qiskit's Trebugger can be used to find errors in the VOLUME 4, 2016 code, both aim to make the circuit optimization process more efficient for specific hardware and not to debug the software.

B. CHALLENGES AND LIMITATIONS
At a high level, debugging quantum circuits is essentially performing process tomography.We have an expectation of how the state of the system evolves over time, and the goal of our testing is to determine if the system is following these expectations.In Section IV, we proposed different strategies to use when testing and debugging the various types of blocks, such as using the swap test for PM blocks or targeting the algorithm's properties to create test vectors for AR circuits.Though these approaches are theoretically valid to test and debug these circuits, they still have limitations.

1) Creating useful test vectors
Testing AR and PM blocks such as the Quantum Fourier Transform (QFT) poses unique challenges.The probabilistic outcomes of quantum states require statistical methods for validation, diverging from the deterministic testing used in classical computing.Entanglement further complicates testing, as the state of one qubit is interdependent with others, obscuring individual analysis.One way to approach this is by creating test vectors that prove the properties of the block under test, similar to what we did in Section IV.Using basic test vectors (applying the block for different bases) can provide the user with information to assist them in the debugging process.

2) The increase in needed resources
The swap test circuit looks fairly simple, but its complexity is directly tied to the size of the states being compared.For two quantum states, each consisting of n qubits, the circuit complexity C swap test = n, where C swap test denotes the number of controlled-SWAP gates needed.
Each CSWAP gate has a significant cost in terms of quantum resources.Implementing a CSWAP gate typically involves multiple elementary quantum gates, such as CNOT and single-qubit gates, depending on the architecture of the quantum processor.
Therefore, the resource cost and potential error rates increase with the number of CSWAP gates used.As n grows, the swap test circuit becomes more complex and more challenging to execute accurately due to increased gate operations and the associated error rates.
A similar argument can be made for implementing and executing process tomography (QPT) [71], [72].
QPT aims to reconstruct the complete quantum process, represented by a superoperator acting on a density matrix.The complexity of QPT scales exponentially with the number of qubits n in the system [73].The number of experimental configurations required for full reconstruction grows [74] is In contrast, Selective Process Tomography (SQPT) [75], [76] focuses on reconstructing only specific elements of the process matrix.The number of experimental configurations in SQPT depends on the number of elements being selectively measured.This selective approach reduces the scaling, often to a polynomial relation with the number of qubits, depending on the targeted elements.Thus, for a subset of elements k [77], the scaling is The difference in scaling between QPT and SQPT has significant implications for their applicability in large quantum systems.
3) Estimating the optimal number of shots needed Estimating the required number of shots in quantum circuit simulations depends on the type of circuit we are testing/ executing.For the AP blocks, we only need one shot to get the results, however, that is not the case when we examine PM and AR blocks.These blocks need more shots to have a higher accuracy.The swap test, for example, involves considerations about statistical accuracy, computational resources, and the specifics of the quantum states being compared.The relation between the number of shots and the standard deviation (σ) of the measurement outcome can be described by where p is the probability of measuring a particular outcome, and N is the number of shots.While there is no simple formula to calculate the optimal number directly, we can determine a suitable number of shots based on the requirements for statistical accuracy.We can use the σ with a specific accuracy value Z to calculate the confidence interval (CI) of the number of shots needed using the formula 4) Distinguishing between hardware and software errors A critical aspect of quantum program testing is acknowledging the differences in debugging on simulators, NISQ machines, and fault-tolerant quantum computers.Limitations in program size and hardware-related errors in NISQ machines pose significant challenges.While these issues might be resolved with fault-tolerant quantum computers, classical computers will still play a vital role in debugging and testing quantum programs.Developing a deep understanding of the behavior of the circuits, identifying sources of errors, and creating effective test cases are essential for building the quantum intuition necessary to advance the field toward the fault-tolerant era.

VI. CONCLUSION
Testing and debugging quantum programs represent both an opportunity and an obstacle in quantum computing, filled with unique challenges and limitations.While significant progress has been made in developing methodologies like Quantum Process Tomography and Selective Process Tomography, the inherent complexities of quantum mechanics continue to pose substantial obstacles.
One of the primary challenges is the exponential scaling of system complexity with the number of qubits.This not only makes the execution of quantum programs more resourceintensive but also exponentially increases the difficulty of debugging and error correction.Furthermore, the no-cloning theorem and the probabilistic nature of quantum computing add complexity to debugging, as they prevent the straightforward replication and observation of quantum states.
Additionally, the current quantum hardware stage, often called NISQ devices, introduces practical limitations.These devices are prone to errors and have limited coherence times, which restrict the reliability and scalability of quantum programs.Implementing effective error correction and noise mitigation strategies thus remains a crucial area of ongoing research.
Despite these challenges, the field of quantum computing holds immense potential.The development of more sophisticated testing and debugging tools and advancements in quantum hardware will pave the way for more robust and reliable quantum programs.As the field continues to mature, it is expected that many of the current limitations will be overcome, unlocking the full potential of quantum computing in solving complex problems beyond the reach of classical computers.
In summary, the journey towards fully harnessing the power of quantum computing is just beginning.The challenges and limitations in testing and debugging quantum programs are significant, yet they provide a fertile ground for innovation and discovery in the field.

FIGURE 2 :
FIGURE 2: The different steps needed to implement and execute most numerical quantum algorithms assuming mid-circuit measurements.

FIGURE 4 :
FIGURE 4: Examples of AP, PM, and AR block.A (left) A random amplitude distribution of a 2-qubit state (right) The amplitudes are permuted after applying the NOT gate to the LSQB.B (left) A two-qubit superposition.(right) The phase is modulated after applying a Z gate to the LSQB.C (left) A uniform superposition of 3 qubits (right) The probability amplitude after applying Grover's iterator to mark the correct answer |101⟩.

FIGURE 5 :FIGURE 6 :
FIGURE 5: One approach to testing quantum circuits, where U DU T is the Device Under Test (full circuit/ slice).U T V i is the circuit corresponding to a test vector i.U EOi is the circuit corresponding to the expected behavior for test vector i.If |ψ⟩ T Oi = |ψ⟩ EOi the output will be |0⟩.

Listing 1 :
A simple Python and Qiskit implementation of the full adder.

Listing 3 :
Failed test results when running the test vectors of the full adder program containing the bug.

8 9FIGURE 7 :
FIGURE 7: Using the swap test to detect the phase difference in a circuit containing a phase error p. U DU T is the Device Under Test (the full circuit/slice).U T V i is the circuit corresponding to test vector i.U EOi is the expected behaviour for T V i .

TABLE 1 :
A summary of some widely used current quantum software tools.