Processing math: 100%

Dan's Blog

Quantum circuit for addition

Introduction

In this post we will be implementing a quantum adder circuit using Qelvin. The circuit is presented in this paper written by L. Ruiz-Perez and J. C. Garcia-Escartin and it takes advantage of the Quantum Fourier Transform (QFT).

Theory

Quantum Fourier Transform

In a n qubit system, the Quantum Fourier Transform acting on an orthonormal basis state |j, n=1,2,...,n can be expressed as

j12n2n1k=0ei2πkj2n|k,

and the corresponding inverse QFT takes form

k12n2n1j=0ei2πkj2n|j.

QFT adder

Consider integers 0a,b2n1 represented by n qubit states |a and |b respectively. The total number of qubits in the adder circuit totals to 2n+1, n qubits for each state representing a integer and one additional qubit for the carry bit. Thus the whole register the circuit operates on is

a1a2...an|0|b1b2...bn,

where a1a2...an=a120+a221+...+an2n and b1b2...bn=b120+b221+...+bn2n are the binary representations of a and b. Not that the register stores the integers in big-endian format.

The next part focuses on register |a1a2...an|0. We first apply a QFT to obtain state (no SWAP gates applied)

a1a2...an|0QFT12n+12nk=0ei2πka2n+1|k=(|0+ei2πa2n+1|1)(|0+ei2πa2n|1)...(|0+ei2πa21|1)=|ϕn+1(a)|ϕn(a)...|ϕ1(a),

where ϕk(a)=12(|0+ei2πa2k|1). Note that

ei2πa2k=ei2πa120+a221+...+an2n12k=ei2π(a12k+a22k+1+..+ak20)=ei2π0.akak1...a1,

where 0.akak1...a1 is the binary fraction. This implies that ϕk(a) contains the lower k binary digits of a. Next we define a controlled rotation gate

Rj=[100001000010000ei2π2j].

For each |ϕk(a), 0<k<n we apply k controlled rotation gates where R1 is controlled by |bk, R2 by |bk1 and so on. To state ϕn+1(a) we apply n controlled rotation gates such that R2 controlled by |bn, R3 controlled by |bn1 and so on.

Let us examine how applying these gates affects |ϕk(a). Let Rbij be a rotation gate controlled by bi. We get

Rb1k...Rbk12Rbk1|ϕk(a)=Rb1k...Rbk1212(|0+ei2π(0.akak1...a1+bk21)|1)...=12(|0+ei2π(0.akak1...a1+bk21+bk122+...+b12k)|1)=12(|0+ei2π(0.akak1...a1+0.bkbk1...b1)|1)=ϕk(a+b).

Now by applying the described procedure to every state in the QFT register we end up with state

ϕn+1(a+b)|ϕn(a+b)...ϕ1(a+b),

and by applying the inverse QFT on the register we end up with state |a+b.

Implementation

Say we want to add integers a=1=102 and b=3=112 (big-endian notation). We initialize a state |10|0|11.


import numpy as np
from qelvin import QRegister, QCircuit
# number of qubits representing b
N_b = 2
# number of qubits representing a + one qubit representing the carry bit
N_fft = 3
N = N_b + N_fft
psi = QRegister(N, 0b10011) # |a|0|b|=|10|0|11
circ = QCircuit(psi)
			

Next we perform QFT on |a|0.


for j in range(N_b, N):
    for k in range(N_b, j):
        circ.cp(np.pi/float(2**(j-k)), j, k)
    circ.h(j)
print(circ)
circ.run()
			

Below is the circuit produced by this snippet. H is the Hadamard gate and Rj is represented by P(2.0*pi/2**j).


                                                                           
q0-------------------------------------------------------------------------
                                                                           
                                                                           
                                                                           
                                                                           
q1-------------------------------------------------------------------------
                                                                           
                                                                           
      ---------  ---------             ---------                           
     |         ||         |           |         |                          
q2---|    H    ||P(+1.571)|-----------|P(+0.785)|--------------------------
     |         ||         |           |         |                          
      ---------  ---------             ---------                           
                     |      ---------      |      ---------                
                     |     |         |     |     |         |               
q3-------------------o-----|    H    |-----|-----|P(+1.571)|---------------
                           |         |     |     |         |               
                            ---------      |      ---------                
                                           |          |      ---------     
                                           |          |     |         |    
q4-----------------------------------------o----------o-----|    H    |----
                                                            |         |    
                                                             ---------     
			

After this we apply the controlled rotation gates.


for j in range(0, N_b+1):
    for k in range(0, N_b):
        theta = 2.0*np.pi*2**(-(k+1+N_b-j+1-N_b))
        circ.cp(theta, k, N_b+j)
print(circ)
circ.run()
			

Below is the circuit produced by this snippet.


q0--------o---------------------o---------------------o--------------------
          |                     |                     |                    
          |                     |                     |                    
          |                     |                     |                    
          |                     |                     |                    
q1--------|----------o----------|----------o----------|----------o---------
          |          |          |          |          |          |         
          |          |          |          |          |          |         
      ---------  ---------      |          |          |          |         
     |         ||         |     |          |          |          |         
q2---|P(+1.571)||P(+0.785)|-----|----------|----------|----------|---------
     |         ||         |     |          |          |          |         
      ---------  ---------      |          |          |          |         
                            ---------  ---------      |          |         
                           |         ||         |     |          |         
q3-------------------------|P(+3.142)||P(+1.571)|-----|----------|---------
                           |         ||         |     |          |         
                            ---------  ---------      |          |         
                                                  ---------  ---------     
                                                 |         ||         |    
q4-----------------------------------------------|P(+0.000)||P(+3.142)|----
                                                 |         ||         |    
                                                  ---------  ---------     
			

Finally we apply the inverse QFT on state |ϕ(a+b).


for j in reversed(range(N_b, N)):
    circ.h(j)
    for k in reversed(range(N_b, j)):
        circ.cp(-np.pi/float(2**(j-k)), j, k)
print(circ)
circ.run()
			

Below is the circuit produced by this snippet.


                                                                           
q0-------------------------------------------------------------------------
                                                                           
                                                                           
                                                                           
                                                                           
q1-------------------------------------------------------------------------
                                                                           
                                                                           
                            ---------             ---------  ---------     
                           |         |           |         ||         |    
q2-------------------------|P(-0.785)|-----------|P(-1.571)||    H    |----
                           |         |           |         ||         |    
                            ---------             ---------  ---------     
                 ---------      |      ---------      |                    
                |         |     |     |         |     |                    
q3--------------|P(-1.571)|-----|-----|    H    |-----o--------------------
                |         |     |     |         |                          
                 ---------      |      ---------                           
      ---------      |          |                                          
     |         |     |          |                                          
q4---|    H    |-----o----------o------------------------------------------
     |         |                                                           
      ---------                                                            
			

Let us now print the final state.


psi_out = circ.state()
print("Final state:")
print(psi_out)
(real, imag) = psi_out[0b00111]
prob = real*real + imag*imag
print(f"Probability for state |a+b|b|=|001|11|: {prob}")
			

Printed state is presented below.


Final state:
[ 0.000+0.000*j  0.000+0.000*j  0.000+0.000*j  -0.000+0.000*j  0.000+0.000*j 
 0.000+0.000*j  0.000+0.000*j  1.000-0.000*j  0.000+0.000*j  0.000+0.000*j 
 0.000+0.000*j  -0.000+0.000*j  0.000+0.000*j  0.000+0.000*j  0.000+0.000*j 
 0.000+0.000*j  0.000+0.000*j  0.000+0.000*j  0.000+0.000*j  -0.000+0.000*j 
 0.000+0.000*j  0.000+0.000*j  0.000+0.000*j  0.000+0.000*j  0.000+0.000*j 
 0.000+0.000*j  0.000+0.000*j  -0.000+0.000*j  0.000+0.000*j  0.000+0.000*j 
 0.000+0.000*j  0.000+0.000*j ]
Probability for state |a+b|b|=|001|11|: 1.0000000000000004
			

And there we have it! We have succesfully computed the sum a+b=1+3=4=0012.