This paper was converted on www.awesomepapers.org from LaTeX by an anonymous user.
Want to know more? Visit the Converter page.

Using Quantum Computers to Speed Up Dynamic Testing of Software

Andriy Miranskyy
Abstract

Software under test can be analyzed dynamically, while it is being executed, to find defects. However, as the number and possible values of input parameters increase, the cost of dynamic testing rises.

This paper examines whether quantum computers (QCs) can help speed up the dynamic testing of programs written for classical computers (CCs). To accomplish this, an approach is devised involving the following three steps: (1) converting a classical program to a quantum program; (2) computing the number of inputs causing errors, denoted by KK, using a quantum counting algorithm; and (3) obtaining the actual values of these inputs using Grover’s search algorithm.

This approach can accelerate exhaustive and non-exhaustive dynamic testing techniques. On the CC, the computational complexity of these techniques is O(N)O(N), where NN represents the count of combinations of input parameter values passed to the software under test. In contrast, on the QC, the complexity is O(ε1N/K)O(\varepsilon^{-1}\sqrt{N/K}), where ε\varepsilon is a relative error of measuring KK.

The paper illustrates how the approach can be applied and discusses its limitations. Moreover, it provides a toy example executed on a simulator and an actual QC. This paper may be of interest to academics and practitioners as the approach presented in the paper may serve as a starting point for exploring the use of QC for dynamic testing of CC code.

1 Introduction

Dynamic testing is an essential part of the software development process. It helps to uncover and eliminate the software’s defects by executing the software and comparing actual and expected outputs.

The ideal scenario would be to test all possible execution paths in a software program using all possible inputs in order to detect defects. This approach is referred to as exhaustive testing. While such testing will not eliminate all defects, it will improve our chances of finding less obvious failure-inducing bugs (which is crucial for mission-critical software [17]). For a sufficiently large program, this approach is not feasible on a classical computer (CC), as the number of execution paths grows exponentially.

To reduce the number of paths we must execute, we use various testing techniques (e.g., equivalence partitioning, boundary value analysis, and orthogonal array testing [27]). We will refer to these techniques collectively as non-exhaustive testing. Although these techniques can help us detect some defects in a reasonable amount of time, they may miss some defects that would be found through exhaustive testing.

The contribution of this paper is to demonstrate that a quantum computer (QC) can accelerate dynamic testing111It was shown that various phases of the software development lifecycle, including testing, can be accelerated by QCs [22]. However, testing of execution paths was not addressed in [22]., both exhaustive and non-exhaustive. We will explore how Grover’s algorithm [15, 10] combined with a quantum counting algorithm [10, 11, 4] can help us accomplish this goal.

The rest of the paper is organized as follows. Section 2 introduces quantum algorithms required to find defects in CC software. Section 3 provides an overview of dynamic testing on a QC and illustrates it with examples. Section 4 discusses the limitations of this testing approach. Finally, Section 5 concludes the paper.

2 Required algorithms and tools

Let us explore algorithms and tools that enable dynamic software testing using QC.

2.1 Grover’s algorithm

Grover’s algorithm [15] is often described as a quantum algorithm for searching an unsorted database with NN entries for a single item. An unsorted database search on a CC requires O(N)O(N) computations. Grover’s algorithm requires only O(N)O(\sqrt{N}) computations on a QC; it is known that Grover’s algorithm is optimal up to a sub-constant factor [8]. This algorithm can be generalized to search for KK items requiring O(N/K)O(\sqrt{N/K}) calculations [10].

However, Grover’s algorithm is designed to solve a more generic problem. Instead of searching for an index of an element in a database, it finds (with a high probability) an input to function ff that produces a particular output value.

Grover’s algorithm requires a specific form for function ff. It is a boolean function with bit string input x={0,1}nx=\{0,1\}^{n} and a return value of 0 or 11. It is important to note that input xx can be interpreted as an integer (by mapping the bit string to an integer): x={0,1,,N1}x=\{0,1,\ldots,N-1\}, where N=2nN=2^{n}.

By convention, the search criterion is satisfied when f(x)=1f(x)=1. We are interested in finding specific values of xx that yield f(x)=1f(x)=1. We denote these values as ω\omega. We can think of the search as an inversion of f(x)=1f(x)=1, i.e., ω=f1(1)\omega=f^{-1}(1).

Then, we need to define a subroutine UωU_{\omega} (often called an oracle) that acts as follows:

Uω|x={|xifxω, i.e., f(x)=0,|xifx=ω, i.e., f(x)=1,U_{\omega}\lvert x\rangle=\begin{cases}\lvert x\rangle&\textrm{if}~{}x\neq\omega\textrm{, i.e., }f(x)=0,\\ -\lvert x\rangle&\textrm{if}~{}x=\omega\textrm{, i.e., }f(x)=1,\end{cases}

where UωU_{\omega} is a diagonal unitary matrix:

Uω=(1)f(x)=[(1)f(0)000(1)f(1)0000(1)f(N1)].U_{\omega}=(-1)^{f(x)}=\begin{bmatrix}(-1)^{f(0)}&0&\cdots&0\\ 0&(-1)^{f(1)}&\cdots&0\\ \vdots&0&\ddots&\vdots\\ 0&0&\cdots&(-1)^{f(N-1)}\end{bmatrix}.

To represent the oracle on a QC, we need only n=log2Nn=\lceil\log_{2}N\rceil qubits, where \lceil\cdot\rceil is the ceiling function. From here on, for simplicity’s sake, we will refer to f(x)f(x), rather than UωU_{\omega}, as an oracle.

Algorithm 1 shows the steps in Grover’s algorithm once the UωU_{\omega} is defined. Grover’s iteration count r(N,K)r(N,K) is given by

r(N,K)=π4NK,r(N,K)=\Bigg{\lceil}\frac{\pi}{4}\sqrt{\frac{N}{K}}\Bigg{\rceil},

where KK is the number of ω\omega values yielding f(x)=1f(x)=1. The computation of r(N,K)r(N,K) is trivial if KK is known. The next step is to figure out how to calculate KK without knowing it beforehand.

1 Initialize the QC to the uniform superposition over all states: |s=1Nx=0N1|x\lvert s\rangle=\frac{1}{\sqrt{N}}\sum_{x=0}^{N-1}{\lvert x\rangle};
2 for i1i\leftarrow 1 to r(N,K)r(N,K) do
       /* Compute "Grover iteration" */
3       Apply UωU_{\omega};
4       Apply the Grover diffusion operator Us=2|ss|IU_{s}=2\lvert s\rangle\langle s\rvert-I, where II denotes an identity matrix;
Measure the resulting quantum state.
Algorithm 1 Grover’s algorithm.

2.2 Quantum counting algorithm

If the value of KK is unknown, it can be estimated on a QC to within relative error ε\varepsilon using the quantum counting algorithm [10, 11], which combines ideas from Grover’s and Shor’s [31] algorithms. Quantum counting has a computational complexity of O(ε1N/K)O(\varepsilon^{-1}\sqrt{N/K}). Quantum counting takes the oracle as input. Another user-supplied input, which controls output quality, is ε\varepsilon. The algorithm returns a value of KK, which is N\leq N.

There exist several simplified versions of the counting algorithm (see [4] for a review). For example, [4] improved the algorithm by removing Shor’s-specific parts. Computational complexity of [4] changes to O(ε1log(δ1)N/K)O(\varepsilon^{-1}\log(\delta^{-1})\sqrt{N/K}), where δ\delta is another input parameter222Algorithm [4] returns K^\hat{K}, which “satisfies K(1ε)<K^<K(1+ε)K(1-\varepsilon)<\hat{K}<K(1+\varepsilon) with probability at least 1δ1-\delta” [4]..

2.3 Reduce software program to an f(x)f(x)

Now let us take a look at converting CC software into QC software. Assume that a classical function g(z)g(\vec{z}) represents an arbitrary CC software program. In order to integrate g(z)g(\vec{z}) into Grover’s algorithm, we must reduce it to f(x)f(x). Below, we will discuss how to alter the g(z)g(\vec{z}) body, inputs, and outputs.

2.3.1 Body of g(z)g(\vec{z})

It is theoretically possible to convert any CC program into a QC program (because QC implements a quantum Turing machine [7, 3]), but there are limitations and practical considerations (see Section 4). Essentially, a classical algorithm is converted into reversible circuits [20], which are then converted into quantum circuits [9]. These conversions can be done automatically.

Several nascent tools for converting classical to quantum circuits already exist. Qiskit, for example, allows compiling a classical function to a quantum circuit transparently (by adding the decorator @classical_function). Qiskit converts classical circuits to quantum circuits using the Tweedledum library [28]. Currently, the compilation is limited to binary inputs/outputs and logical operators (see Section 3.1.1 for an example). Another example is the staq toolkit, which can convert classical Verilog circuits to a quantum assembly language (QASM) [6]. Finally, StaffCC compiler [18] extension RKQC [16] is also capable of compiling classical circuits to QASM (including integer addition and multiplication operations [34]).

Hopefully, the abovementioned tools will evolve in the future to enable the conversion of any classical program.

2.3.2 Input to g(z)g(\vec{z})

Section 2.1 discussed the possibility of interpreting input xx into ff as a bit string. Furthermore, bit strings can represent arbitrary complex data structures. Thus, to convert z\vec{z} into xx, we must convert z\vec{z} into a bit string.

For example, imagine that z\vec{z} has two elements: an integer z1z_{1} and a 3-character string z2z_{2}, i.e., g(z)=g(z1,z2)g(\vec{z})=g(z_{1},z_{2}). Furthermore, suppose that storing an integer and a string character requires 6464 and 88 bits, respectively. We will need 88=64+3×888=64+3\times 8 bits to represent the input, i.e., N=288N=2^{88}.

2.3.3 Output of g(z)g(\vec{z})

Software programs may produce any output (or no output at all), whereas f(x)f(x) should return either zero or one. We can satisfy this requirement by wrapping333We can also leverage try-catch blocks in high-level programming languages. g(z)g(\vec{z}) in code that returns an exit code of 0 on success and 11 on error (similar to operating system exit status codes).

3 Dynamic testing

Algorithm 2 shows how QC can be used to test a software product dynamically. The algorithm leverages the “building blocks” covered in Section 2. We will discuss two cases of how to use the algorithm for exhaustive and non-exhaustive testing below.

Input : CC software g(z)g(\vec{z})
Output : A list of values of z\vec{z} causing g(z)g(\vec{z}) to return errors denoted by vv
1 Convert CC software g(z)g(\vec{z}) to f(x)f(x) as discussed in Sec. 2.3;
2 Compute KK using a quantum counting algorithm described in Sec. 2.2;
3 if K = 0 then
       vv\leftarrow empty list ;
        // all tests pass
4      
5else if K = N then
       vv\leftarrow all possible values of z\vec{z} ;
        // all tests fail
6      
7else
       /* some tests fail, i.e., 0<K<N0<K<N */
8       Find all ω\omega (values of xx causing bugs, i.e., those where f(x)=1f(x)=1) using Grover’s algorithm shown in Sec. 2.1;
9       vv\leftarrow convert ω\omega to z\vec{z} format (see example in Eq. 1).
10      
Algorithm 2 Using a QC to dynamically test software for a CC. Only Steps 2 and 2 are computed (mainly) on a QC; the rest are executed on a CC.

3.1 Exhaustive testing

Suppose we need to implement a function g(z)g(\vec{z}). We want to ensure that none of the possible values of z\vec{z} result in an error in our implementation of this function. We will follow the steps described in Algorithm 2 to accomplish this. Here is a toy example of using the algorithm.

3.1.1 Example

Suppose we implement a function g(z1,z2)g(z_{1},z_{2}), where z1z_{1} is a 2-bit integer and z2z_{2} is a boolean variable. The next step is to test our implementation of g(z1,z2)g(z_{1},z_{2}).

Suppose we inject two defects, e.g., g(z1,z2)g(z_{1},z_{2}) returns incorrect results when z1=3z_{1}=3 and z2=falsez_{2}=\textrm{false} or when z1=2z_{1}=2 and z2=truez_{2}=\textrm{true}. Algorithm 3 gives a trivial example of such code. Code review of Algorithm 3 immediately reveals the problem. Of course, in real-world scenarios, we would not know these values of z\vec{z} upfront; this simplification is for demonstration purposes only.

Input : z1z_{1}, z2z_{2}
Output : yy
1 if  (z1=3(z_{1}=3 and z2=false)z_{2}=\textrm{false}) or (z1=2(z_{1}=2 and z2=true)z_{2}=\textrm{true})  then
       /* Error-prone business logic goes here */
2       y1y\leftarrow 1
3else
       /* Correct business logic goes here */
4       y0y\leftarrow 0
Algorithm 3 Sample CC pseudocode under test.

Step 2 of Algorithm 2 converts g(z1,z2)g(z_{1},z_{2}) into f(x)f(x). As z1z_{1} and z2z_{2} can be represented by 3-bit strings, N=23=8N=2^{3}=8. The first two bits of the bit string store an integer z1z_{1}, while the last bit stores a boolean variable z2z_{2}.

We will implement our example using Qiskit; code listing can be found on Zenodo [21].

As was described in Section 2.3, converters from a classical to a quantum circuit are still in their infancy, and Qiskit operates only on binary variables. Thus, we must manually reduce the code in Algorithm 3 to the format understood by Qiskit (eventually, converters and compilers will do this automatically). Listing 1 shows the result of the conversion to f(x)f(x). Once in this form, Qiskit’s @classical_function decorator automatically converts f(x)f(x) to the quantum circuit (so-called bit-flip oracle [25]) shown in Figure 3.

@classical_function
# Int1 is Qiskits bit-level type
def oracle(z1_high_bit: Int1, z1_low_bit: Int1, z2: Int1) -> Int1:
return (z1_high_bit and z1_low_bit and not z2) or \ (z1_high_bit and not z1_low_bit and z2)
Figure 1: A bit-flip oracle obtained by converting g(z1,z2)g(z_{1},z_{2}) to f(x)f(x).

Using Grover’s algorithm requires a phase-flip oracle [25]. Bit-flip oracles are converted to phase-flip oracles by placing their return values between NOT and Hadamard gates as shown in Listing 2. The phase-flip oracle circuit, which we pass to the search algorithm, is shown in Figure 4.

def get_phase_flip_oracle(bitflip_oracle, n):
phase_oracle = QuantumCircuit(n+1)
phase_oracle.x(n)
phase_oracle.h(n)
phase_oracle.compose(bitflip_oracle.synth(), inplace=True)
phase_oracle.h(n)
phase_oracle.x(n)
return phase_oracle
input_qubits_count = 3
phase_flip_oracle = get_phase_flip_oracle(oracle, input_qubits_count)
Figure 2: Conversion of the bit-flip oracle from Listing 1 to a phase-flip oracle.
Refer to caption
(a) Circuit
OPENQASM 2.0;
include qelib1.inc”;
qreg q[4];
ccx q[0],q[1],q[3];
ccx q[0],q[2],q[3];
(b) Assembly code
Figure 3: The quantum circuit obtained by converting the bit-flip oracle in Listing 1. In OpenQASM, ccx denotes controlled-controlled-not (Toffoli) gate. q0q_{0} corresponds to high bit of z1z_{1}, q1q_{1} — to low bit of z1z_{1}, and q2q_{2} — to z2z_{2}. Oracle’s return value is stored in q3q_{3}.
Refer to caption
(a) Circuit
OPENQASM 2.0;
include qelib1.inc”;
qreg q[4];
x q[3];
h q[3];
ccx q[0],q[1],q[3];
ccx q[0],q[2],q[3];
h q[3];
x q[3];
(b) Assembly code
Figure 4: The quantum circuit obtained by converting the bit-flip oracle in Figure 3 to phase-flip oracle. In OpenQASM, x denotes NOT gate, h – Hadamard gate.

In Step 2 of Algorithm 2, we pass the oracle’s circuit to the quantum counting algorithm444Qiskit’s implementation of the quantum counting algorithm [11] is illustrated in [5, Sec. 3.9]., which returns KK, the number of inputs causing defects. In our case, K=2K=2. As K0K\neq 0 and KNK\neq N, we go to Step 2.

Step 2 of Algorithm 2 involves passing oracle’s circuit to Grover’s algorithm to find specific input values that cause failures. Using the KK value from Step 2, we can calculate the number of iterations of Grovers’ algorithm: r(N,K)=r(8,2)=2r(N,K)=r(8,2)=2.

Execution is performed on the Qiskit v.0.37.0 Aer simulator v.0.10.4 (providing an ideal noise-free QC) as well as on the IBM Quantum r4T Processor v.1.0.38 with five qubits, namely, ibmq_lima [2]. With ibmq_lima, we compare the output based on Qiskit’s simulator of ibmq_lima as well as the output from the actual QC.

The output of Grover’s algorithm can be seen in Figure 5. According to the simulators and the real QC, 110 and 101 are the top-two returned values of ω\omega. However, due to noise, the pp-values on the real QC are lower than those on the simulators.

Step 2 of Algorithm 2 converts ω\omega back to z\vec{z} values:

110ωsplit11z10z2from binary3z1falsez2,101ωsplit10z11z2from binary2z1truez2.\begin{split}\underbrace{110}_{\omega}\xrightarrow{\textrm{split}}\underbrace{11}_{z_{1}}\underbrace{0}_{z_{2}}\xrightarrow{\textrm{from binary}}\underbrace{3}_{z_{1}}\underbrace{\textrm{false}}_{z_{2}},\\ \underbrace{101}_{\omega}\xrightarrow{\textrm{split}}\underbrace{10}_{z_{1}}\underbrace{1}_{z_{2}}\xrightarrow{\textrm{from binary}}\underbrace{2}_{z_{1}}\underbrace{\textrm{true}}_{z_{2}}.\end{split} (1)

These are the values we expected. In other words, Algorithm 2 correctly identified two inputs that caused errors in software under test.

Refer to caption
(a) Qiskit Aer simulator
Refer to caption
(b) Qiskit simulator of ibmq_lima
Refer to caption
(c) Actual ibmq_lima
Figure 5: Results of Grover search. The expected outputs are 101 and 110. Probabilities are computed based on 10241024 shots for simulators and 40004000 shots for a real QC ibmq_lima (the term shot refers to a single experiment run). As expected, simulator of an ideal QC (Figure 5(a)) yields the most accurate results. Simulated ibmq_lima results (Figure 5(b)) are more optimistic than actual ibmq_lima results (Figure 5(c)). This can be explained by the actual QC’s performance fluctuating due to environmental factors.

3.1.2 Computational complexity

How laborious is Algorithm 2?

In Step 2, code written in a high-level language (e.g., C/C++ or Python) is compiled into a quantum circuit. Depending on the compiler, the complexity of this process may vary, but compiler designers are aiming for O(α2)O(\alpha^{2}), where α\alpha is the size of the input [13]. In practice, even for large code bases with millions of lines of code, compilation on modern CC is relatively fast.

The computation complexity of Steps 2 and 2 is O(ε1N/K)O(\varepsilon^{-1}\sqrt{N/K}) and O(N/K)O(\sqrt{N/K}), respectively [10, 11]. Complexity of Step 2 is proportional to the number of bits required to represent xx, i.e., O(log2N)O(\log_{2}{N}). Therefore, we estimate that the majority of time will be spent on Steps 2 and 2, with the dominant term O(ε1N/K)O(\varepsilon^{-1}\sqrt{N/K}).

When comparing exhaustive testing on CC and QC, QC is faster because exhaustive search on a CC requires O(N)=O(2n)O(N)=O(2^{n}) computations, while on a QC — only O(ε1N/K)=O(ε12n/2K1/2)O(\varepsilon^{-1}\sqrt{N/K})=O(\varepsilon^{-1}2^{n/2}K^{-1/2}) computations.

2n/22^{n/2} grows much slower555For example, suppose n=64n=64 bits. Then 2n=2642×10192^{n}=2^{64}\approx 2\times 10^{19}, while 2n/2=2324×1092^{n/2}=2^{32}\approx 4\times 10^{9}. than 2n2^{n}, but it still increases exponentially. Thus, if our software has input parameters requiring many bits, the search will become prohibitively expensive, even on a QC. Therefore, let us explore non-exhaustive testing methods.

3.2 Non-exhaustive testing

As discussed in Section 1, in the non-exhaustive case, we test a subset of input parameters NN. Essentially, we want to reduce NN and speed up testing.

An example of such an approach is the use of a tt-way combinatorial testing to explore different combinations of parameters [19]. A 11-way or 22-way test can catch most defects, but t>2t>2 is needed to expose some [19]. As tt increases, testing costs quickly rise. Nevertheless, it may be necessary to find these defects (e.g., in mission-critical software [17]).

When tt is large, we can use Algorithm 2 to accelerate tt-way testing. Step 2 of Algorithm 2 needs to be modified to map the values of z\vec{z} to xx. For example, a mapping function can be created by automatically generating a simple lookup table that will be encoded in the circuit.

3.2.1 Example

Let us consider the function g(z3)g(z_{3}), where z3z_{3} is a 6464-bit integer, i.e., n=64n=64). There are only three input values we want to test, e.g., z3={7,200,1005}z_{3}=\{7,200,1005\}.

We will refer to the number of inputs in a subset as NsN_{s}. In our example Ns=3N_{s}=3. To represent the input, we only need log2Ns=log23=2\lceil\log_{2}{N_{s}}\rceil=\lceil\log_{2}{3}\rceil=2 qubits rather than 6464 qubits. During compilation, we would add a data structure that mapped each of these three values to their 64-bit representations (note that we will still need 6464 auxiliary qubits to build oracle’s circuit, but we will only be measuring the two input qubits).

3.2.2 Computational complexity

We will get O(ε1Ns/K)=O(ε12ns/2K1/2)O(\varepsilon^{-1}\sqrt{N_{s}/K})=O(\varepsilon^{-1}2^{n_{s}/2}K^{-1/2}) computations, where Ns=2nsN_{s}=2^{n_{s}}, if we apply the complexity analysis logic discussed in Section 3.1.2. Therefore, as long as NNsN\gg N_{s}, the non-exhaustive test will be significantly faster than the exhaustive test. Moreover, non-exhaustive testing on a CC would require O(Ns)=O(2ns)O(N_{s})=O(2^{n_{s}}) computations, so QC will outperform CC.

As we need to add the code to map z\vec{z} to xx, the cost of executing the oracle increases compared to the exhaustive testing case. Nevertheless, such look-up tables can be constructed efficiently; e.g., a hash table’s search complexity is O(1)O(1). As a result, the computation time increase will be minimal.

4 Discussion

According to Section 3, dynamic testing might be faster on QC than on CC. Does this approach have any drawbacks? Section 4.1 discusses blocking issues that prevent the algorithm from becoming practical. Section 4.2 describes the limitations of this approach, including the types of programs that can be tested. Section 4.3 concludes with notes on tuning implementation of Algorithm 2.

4.1 Blocking issues

Creation of the oracle f(x)f(x)

The conversion of classical circuits to quantum circuits has been an active research area for at least two decades (see [29] for a review). Yet, more work must be done before practitioners can use them to convert arbitrary CC programs. Specifically, it will be difficult for practitioners to use our dynamic testing method without an efficient universal compiler. This goal can be accomplished with the help of academics and practitioners in the compiler community.

What if the time it takes to generate and compute Grover’s algorithm negates the savings from the search itself? This may happen if we simply load a database into a QC [32]. The testing method presented in this paper, however, does not explicitly search for database elements but instead computes the inverse of f(x)=1f(x)=1, thereby reducing the possibility of such an outcome [32].

Number of shots

A noisy intermediate-scale quantum (NISQ) computer requires a high number of shots to combat noise. Figure 5 illustrates the detrimental effects of noise (compare pp-values of correct answers on simulators and a real QC).

A fault-tolerant QC (FTQC) [25], which employs error-correcting schemes to operate on logical/ideal qubits (constructed from groups of physical qubits [12]), will require fewer shots than NISQ device. For example, theoretically, if K=1K=1, the correct answer will likely be obtained with one shot.

However, as KK increases, so does the number of shots (as every shot yields a single value of ω\omega). The number of shots on FTQC can be estimated by converting our problem to a classical Coupon Collector problem [14], which tries to determine how many coupons SS one needs to buy to collect KK distinct coupons (see [14] for review). In our case, to capture KK distinct inputs causing errors, we need to take, on average, SS shots. Assuming that the probability of observing a particular error-inducing input is 1/K1/K, the expected value of SS is given by

𝔼[S]=Ki=1K1i=Kln(K)+Kγ+12+O(1K),K+,\mathbb{E}[S]=K\sum_{i=1}^{K}{\frac{1}{i}}=K\ln(K)+K\gamma+\frac{1}{2}+O\left(\frac{1}{K}\right),K\to+\infty, (2)

where γ0.5772\gamma\approx 0.5772 is the Euler-Mascheroni constant (see [14, p. 5] for details).

Speed of quantum computers

In order for the oracle f(x)f(x) to be executed quickly, the QC should be able to run the circuit efficiently. Modern QCs are still relatively slow: e.g., currently, top IBM’s QC can process 14191419 Circuit Layer Operations Per Second (CLOPS) [33]. A future generation of QCs will resolve this engineering problem.

Timeline

Section 3.1.1 demonstrates that dynamic testing of QC may be possible even on a NISQ device. As with many other quantum algorithms applicable to software engineering tasks, we will need to wait for a device with a large number of qubits (preferably with good interconnectivity), high coherence, and high fidelity before the algorithms can be used in practice [22]. Small FTQCs with such characteristics may appear within ten years [30].

4.2 Limiting issues

CC program types

It is theoretically possible to convert any CC program into a QC program, as we discussed in Section 2.3.1. For single-threaded, single-process software, this should be relatively straightforward.

A multi-threaded, multi-process program, however, would be more challenging to convert since it would require implementation and conversion of the thread and process manager. One would need to load the code to be tested into a virtual machine and then load this combined codebase into the quantum circuit.

A similar problem will arise with programs implemented using the async/await pattern, as we need to convert the supporting libraries.

CC program structure

Estimates of computational complexity in Sections 3.1.2 and 3.2.2 are based on a critical assumption made by Grover: oracle f(x)f(x) “can be evaluated in unit time” for any value of xx [15]. This assumption governs the computational complexity of Steps 2 and 2 of Algorithm 2.

However, this assumption is not always valid. For example, f(x)f(x) may have a for-loop with xx iterations. Based on max(x)=N=2n\max(x)=N=2^{n}, the execution time of the Oracle, on both CC and QC, will grow exponentially with nn. Although exhaustive testing on the QC will still be faster than on CC, the execution time may be prohibitive666Hypothetically, some for-loops may be parallelized on a QC, see [35, Sec. 3.5] for review.. Thus, we may have to create a static analyzer that checks the code of the CC program g(z)g(\vec{z}) before conversion and warns the user if such pathological cases are found.

Note that this pathological code may be less problematic for non-exhaustive testing, because we can limit the number of parameter values passed to f(x)f(x).

Calls to external services

In many programs, external services (e.g., a database or a web service) must be called. We would not be able to call these services from a QC unless such services are implemented within the QC (and that is not going to happen soon [23, 24]). As an alternative, we can simulate the calls to external services using mock and stub objects (see [26, Ch. 4] for review). The mocked and stubbed code can easily be converted to quantum circuit as part of the oracle generation process.

4.3 Tuning of Algorithm 2

Count of inputs causing defects

Algorithm 2 can potentially be stopped at Step 2 and simply return KK (i.e., the count of inputs causing errors). As a result, the developer can see how many inputs resulted in errors. However, with this information alone, the developer cannot reproduce the failures (unless K=0K=0 or K=NK=N, indicating that all tests pass or fail, respectively). Thus, we conjecture that a practitioner would usually want to run all the steps of Algorithm 2 and obtain the actual values of inputs that cause errors.

Parallelism

Grover’s search in Step 2 of Algorithm 2 will need to be repeated multiple times (especially for large values of KK, see Eq. 2), since each call will return only one ω\omega value (error-generating input). We can parallelize Step 2 (since each shot is independent) by compiling Grover’s circuit and running it on multiple QCs.

5 Summary

This paper showed that dynamic testing of programs written for a CC can be sped up on a QC. Specifically, computational complexity decreases from O(N)O(N) to O(ε1N/K)O(\varepsilon^{-1}\sqrt{N/K}). Simulated and real QC outputs from a toy example were used to illustrate this approach. A discussion on the limitations of dynamically testing CC programs on a QC was conducted.

Two key issues must be solved to make the approach practical: (1) converters from classical to quantum circuits need to be improved, and (2) QCs need to become faster, larger, and more “robust.” These two issues can be resolved, but a significant effort will be required from the academic and industrial communities.

This work may serve as a starting point for exploring the use of QC for dynamic testing of CC code. Academics and practitioners are invited to explore this promising field of research further.

Acknowledgement

I would like to thank anonymous reviewers for their thoughtful comments and suggestions! This research is funded in part by NSERC Discovery Grant No. RGPIN-2022-03886.

References

  • [1]
  • ibm [2022] 2022. IBM Quantum. https://quantum-computing.ibm.com
  • Aaronson [2005] Scott Aaronson. 2005. Quantum computing, postselection, and probabilistic polynomial-time. Proceedings of the Royal Society A: Mathematical, Physical and Engineering Sciences 461, 2063 (2005), 3473–3482.
  • Aaronson and Rall [2020] Scott Aaronson and Patrick Rall. 2020. Quantum approximate counting, simplified. In Symposium on Simplicity in Algorithms. SIAM, 24–32.
  • Abbas et al. [2020] Amira Abbas, Stina Andersson, Abraham Asfaw, Antonio Corcoles, Luciano Bello, Yael Ben-Haim, Mehdi Bozzo-Rey, Sergey Bravyi, Nicholas Bronn, Lauren Capelluto, Almudena Carrera Vazquez, Jack Ceroni, Richard Chen, Albert Frisch, Jay Gambetta, Shelly Garion, Leron Gil, Salvador De La Puente Gonzalez, Francis Harkins, Takashi Imamichi, Pavan Jayasinha, Hwajung Kang, Amir h. Karamlou, Robert Loredo, David McKay, Alberto Maldonado, Antonio Macaluso, Antonio Mezzacapo, Zlatko Minev, Ramis Movassagh, Giacomo Nannicini, Paul Nation, Anna Phan, Marco Pistoia, Arthur Rattew, Joachim Schaefer, Javad Shabani, John Smolin, John Stenger, Kristan Temme, Madeleine Tod, Ellinor Wanzambi, Stephen Wood, and James Wootton. 2020. Learn Quantum Computation Using Qiskit. http://community.qiskit.org/textbook
  • Amy and Gheorghiu [2020] Matthew Amy and Vlad Gheorghiu. 2020. staq—A full-stack quantum processing toolkit. Quantum Science and Technology 5, 3 (2020), 034016.
  • Benioff [1980] Paul Benioff. 1980. The computer as a physical system: A microscopic quantum mechanical Hamiltonian model of computers as represented by Turing machines. Journal of statistical physics 22, 5 (1980), 563–591.
  • Bennett et al. [1997] Charles H Bennett, Ethan Bernstein, Gilles Brassard, and Umesh Vazirani. 1997. Strengths and weaknesses of quantum computing. SIAM journal on Computing 26, 5 (1997), 1510–1523.
  • Bojić [2014] Alan Bojić. 2014. An approach to source code conversion of classical programming languages into source code of quantum programming languages. Journal of Information and Organizational Sciences 38, 2 (2014), 75–82.
  • Boyer et al. [1998] Michel Boyer, Gilles Brassard, Peter Høyer, and Alain Tapp. 1998. Tight bounds on quantum searching. Fortschritte der Physik: Progress of Physics 46, 4-5 (1998), 493–505.
  • Brassard et al. [1998] Gilles Brassard, Peter Høyer, and Alain Tapp. 1998. Quantum counting. In International Colloquium on Automata, Languages, and Programming. Springer, 820–831.
  • Chao and Reichardt [2018] Rui Chao and Ben W Reichardt. 2018. Fault-tolerant quantum computation with few qubits. npj Quantum Information 4, 1 (2018), 1–8.
  • Cooper and Torczon [2011] Keith D Cooper and Linda Torczon. 2011. Engineering a compiler (2 ed.). Elsevier.
  • Ferrante and Saltalamacchia [2014] Marco Ferrante and Monica Saltalamacchia. 2014. The coupon collector’s problem. Materials matemàtics (2014), 1–35.
  • Grover [1996] Lov K Grover. 1996. A fast quantum mechanical algorithm for database search. In 28th annual ACM symposium on theory of computing. ACM, 212–219.
  • Holmes [2016] Adam Holmes. 2016. epiqc/RKQC: RKQC is a compiler for reversible logic circuitry. https://github.com/epiqc/RKQC
  • Hynninen et al. [2018] Timo Hynninen, Jussi Kasurinen, Antti Knutas, and Ossi Taipale. 2018. Software testing: Survey of the industry practices. In 41st International Convention on Information and Communication Technology, Electronics and Microelectronics (MIPRO). IEEE, 1449–1454.
  • JavadiAbhari et al. [2014] Ali JavadiAbhari, Shruti Patil, Daniel Kudrow, Jeff Heckey, Alexey Lvov, Frederic T Chong, and Margaret Martonosi. 2014. ScaffCC: A framework for compilation and analysis of quantum computing programs. In 11th ACM Conference on Computing Frontiers. ACM, 1–10.
  • Kuhn et al. [2004] D Richard Kuhn, Dolores R Wallace, and Albert M Gallo. 2004. Software fault interactions and implications for software testing. IEEE trans. on softw. eng. 30, 6 (2004), 418–421.
  • Miller et al. [2003] D Michael Miller, Dmitri Maslov, and Gerhard W Dueck. 2003. A transformation based algorithm for reversible logic synthesis. In Design automation conference. IEEE, 318–323.
  • Miranskyy [2022] Andriy Miranskyy. 2022. Supplementary material: code listing. https://doi.org/10.5281/zenodo.7065888
  • Miranskyy et al. [2022] Andriy Miranskyy, Mushahid Khan, Jean Paul Latyr Faye, and Udson C Mendes. 2022. Quantum Computing for Software Engineering: Prospects. arXiv preprint arXiv:2203.03575 (2022). To appear in Proceedings of the 1st International Workshop on Quantum Programming for Software Engineering.
  • Miranskyy and Zhang [2019] Andriy Miranskyy and Lei Zhang. 2019. On testing quantum programs. In 41st Int. Conf. on Softw. Eng.: New Ideas and Emerging Results (ICSE-NIER). IEEE, 57–60.
  • Miranskyy et al. [2021] Andriy Miranskyy, Lei Zhang, and Javad Doliskani. 2021. On testing and debugging quantum software. arXiv preprint arXiv:2103.09172 (2021).
  • Nielsen and Chuang [2010] Michael A. Nielsen and Isaac L. Chuang. 2010. Quantum Computation and Quantum Information: 10th Anniversary Edition. Cambridge Univ. Press.
  • Osherove [2013] Roy Osherove. 2013. The Art of Unit Testing: with examples in C# (2 ed.). Manning.
  • Pressman and Maxim [2015] Roger S Pressman and Bruce R. Maxim. 2015. Software engineering: a practitioner’s approach (8 ed.). McGraw Hill.
  • Schmitt and De Micheli [2022] Bruno Schmitt and Giovanni De Micheli. 2022. tweedledum: a compiler companion for quantum computing. In 2022 Design, Automation & Test in Europe Conference & Exhibition (DATE). IEEE, 7–12.
  • Seidel et al. [2021] Raphael Seidel, Colin Kai-Uwe Becker, Sebastian Bock, Nikolay Tcholtchev, Ilie-Daniel Gheorge-Pop, and Manfred Hauswirth. 2021. Automatic Generation of Grover Quantum Oracles for Arbitrary Data Structures. arXiv preprint arXiv:2110.07545 (2021).
  • Sevilla and Riedel [2020] Jaime Sevilla and C Jess Riedel. 2020. Forecasting timelines of quantum computing. arXiv preprint arXiv:2009.05045 (2020).
  • Shor [1994] Peter W Shor. 1994. Algorithms for quantum computation: discrete logarithms and factoring. In 35th annual symp. on foundations of comp. sci. IEEE, 124–134.
  • Viamontes et al. [2005] George F Viamontes, Igor L Markov, and John P Hayes. 2005. Is quantum search practical? Computing in science & engineering 7, 3 (2005), 62–70.
  • Wack et al. [2021] Andrew Wack, Hanhee Paik, Ali Javadi-Abhari, Petar Jurcevic, Ismael Faro, Jay M. Gambetta, and Blake R. Johnson. 2021. Scale, Quality, and Speed: three key attributes to measure the performance of near-term quantum computers. arXiv preprint arXiv:2110.14108 (2021).
  • Wang et al. [2016] Feng Wang, Mingxing Luo, Huiran Li, Zhiguo Qu, and Xiaojun Wang. 2016. Improved quantum ripple-carry addition circuit. Science China Information Sciences 59, 4 (2016), 1–8.
  • Zomorodi-Moghadam et al. [2014] Mariam Zomorodi-Moghadam, Mohammad-Amin Taherkhani, and Keivan Navi. 2014. Synthesis and optimization by quantum circuit description language. In Transactions on Computational Science XXIV. Springer, 74–91.