3

I've implemented a quantum adder and, when I build the results table, I'm having some trouble to understand what's going on. First, I'm using the adder quantum circuit proposed in this paper, which circuit is shown below:

Circuit from the quantum adder

This is my version, implemented in IBMQE, as shown below:

My adder circuit implemented in IBMQE

After building the following truth table, I've got the following results:

Truth table that was obtained by me.

One can verify that there are several wrong outputs from this circuit. My question is: What's wrong in this circuit? If there is nothing wrong, am I interpreting the outputs in a wrong way? How to interpret them correctly?

2 Answers2

4

The figure you included in your question references the paper Addition on a Quantum Computer by Draper. Qiskit has implemented this circuit natively, which you can construct as follows.

from qiskit.circuit.library import DraperQFTAdder

adder = DraperQFTAdder(2).decompose() adder.draw(output="text")

a_0: ─────────■──────■───────────────────────
              │      │                       
a_1: ─────────┼──────┼────────■──────────────
     ┌──────┐ │P(π)  │        │     ┌───────┐
b_0: ┤0     ├─■──────┼────────┼─────┤0      ├
     │  QFT │        │P(π/2)  │P(π) │  IQFT │
b_1: ┤1     ├────────■────────■─────┤1      ├
     └──────┘                       └───────┘

So, looking at your question, it seems like you misplaced the control qubit of a controlled-P qubit, as your second qubit is never acted on by any gate, but be careful to take into account Qiskit's endian convention when thinking about this.

Running this naively for all inputs, I got:

import itertools
from qiskit import QuantumCircuit, Aer, transpile
from qiskit.quantum_info import Statevector

backend = Aer.get_backend('qasm_simulator')

for l in list(itertools.product([0, 1], repeat=4)): qc = QuantumCircuit(4)

for i, bit in enumerate(l):
    if bit == 1: 
        qc.x(i)
qc.append(adder, [0, 1, 2, 3])
qc.measure_all()
qc = qc.reverse_bits()

job = backend.run(transpile(qc, backend), shots=1024)
print(f"Input: {l}. Result: {job.result().get_counts()}")

Input: (0, 0, 0, 0). Result: {'0000': 1024}
Input: (0, 0, 0, 1). Result: {'0001': 1024}
Input: (0, 0, 1, 0). Result: {'0010': 1024}
Input: (0, 0, 1, 1). Result: {'0011': 1024}
Input: (0, 1, 0, 0). Result: {'0101': 1024}
Input: (0, 1, 0, 1). Result: {'0100': 1024}
Input: (0, 1, 1, 0). Result: {'0111': 1024}
Input: (0, 1, 1, 1). Result: {'0110': 1024}
Input: (1, 0, 0, 0). Result: {'1010': 1024}
Input: (1, 0, 0, 1). Result: {'1011': 1024}
Input: (1, 0, 1, 0). Result: {'1001': 1024}
Input: (1, 0, 1, 1). Result: {'1000': 1024}
Input: (1, 1, 0, 0). Result: {'1111': 1024}
Input: (1, 1, 0, 1). Result: {'1110': 1024}
Input: (1, 1, 1, 0). Result: {'1100': 1024}
Input: (1, 1, 1, 1). Result: {'1101': 1024}

This, I think, is what you expected in your table if you take into account the endian notation for each register individually (so, e.g., the input (0, 1, 0, 1) is doing $(2 + 2) \mod 4 = 0$). But you can check the documentation for the adder in more detail to confirm.

epelaez
  • 2,985
  • 1
  • 9
  • 31
1

The correct way to interpret the number is using a compiler that follows the qubit mapping.

You can see how it is done in Classiq, for example, by running examples from the arithmetic library

To your case, you can run:

from classiq import *

@qfunc def main(a: Output[QNum[2, False,0]], b: Output[QNum[2,False,0]], res: Output[QNum]) -> None: allocate(2, a) allocate(2, b) hadamard_transform(a) hadamard_transform(b)

res |= a+b

qmod = create_model(main) qprog = synthesize(qmod) show(qprog)

job = execute(qprog) result = job.result()[0].value print(result.parsed_counts)

job.open_in_ide()

For more complex case, where the register represents a fraaction or signed number, you can use this qfunc instead:

@qfunc
def main(a: Output[QNum[3, True,2]], b: Output[QNum[4,False,1]], res: Output[QNum]) -> None:
    allocate(3, a)
    allocate(4, b)
    hadamard_transform(a)
    hadamard_transform(b)
res |= a+b

Will give you interpreted results:

     {'a': -0.25, 'b': 4.0, 'res': 3.75}: 23,
     {'a': 0.75, 'b': 0.0, 'res': 0.75}: 22,
 ...
 {'a': -0.75, 'b': 6.5, 'res': 5.75}: 13,
 {'a': 0.0, 'b': 1.5, 'res': 1.5}: 12,

... {'a': -0.25, 'b': 3.0, 'res': 2.75}: 11, {'a': -0.75, 'b': 7.5, 'res': 6.75}: 10, ... {'a': -1.0, 'b': 5.5, 'res': 4.5}: 5]

And in the IDE, you can hover on the bars and see that for every result, res=a+b enter image description here

Disclaimer - I am an engineer at Classiq

Ron Cohen
  • 1,512
  • 6
  • 24