Skip to content

Commit f05c699

Browse files
full code upload
1 parent f314e19 commit f05c699

7 files changed

+370
-2
lines changed

README.md

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,43 @@
1-
# quantum-arithmetic
2-
Public repository of research codes on quantum arithmetic algorithms
1+
# Register-by-Constant QFT Addition Algorithm - by Filipe Chagas Ferraz
2+
3+
4+
## Presentation
5+
6+
This is a quantum algorithm I created that can be considered a simplified version of Draper's adder. This algorithm is described as a unitary operator $U_+(c)$ such that $U_+(c)|a\rangle \mapsto | a + c \pmod{2^N}\rangle$, where $|a\rangle$ is the initial state of the $N$-qubit register. This state can be defined for natural number as:
7+
8+
$$|a\rangle = |a_N,...,a_2,a_1\rangle, \quad a = \sum_{j=1}^N a_j 2^{j-1}$$
9+
10+
This state can also be defined for (signed) integer numbers using the two's complement notation.
11+
12+
The operator $U_+(c)$ is defined as $U_+(c) = U_\text{QFT}^\dagger \times U_{\phi(+)}(c) \times U_\text{QFT}$, where $U_{\phi(+)}(c) = \text{diag}[1, \omega^{c}, \omega^{2c}, \omega^{3c},...,\omega^{(2^N-1)c}]$. This operator can be implemented as the following quantum circuit:
13+
14+
![reg-by-const QFT adder](img/QAdder.png)
15+
16+
## Organization
17+
18+
This repository is organized as follows:
19+
20+
* The file **qiskit_quantum_fourier_transform.py** contains a function that gives the QFT gate. As the filename says, this function uses Qiskit.
21+
* The file **qiskit_reg_by_const_qft_adder.py** has functions that gives Qiskit gates of the operators $U_+(c)$ and $U_{\phi(+)}(c)$.
22+
* The file **qiskit_reg_by_const_qft_adder_test.ipynb** is a Jupyter notebook made for test the functions in *qiskit_reg_by_const_qft_adder.py*. This notebook contains the results of some tests.
23+
24+
* The file **numeric_systems.py** has functions that convert natural numbers and integers into sequences of bits. These functions are used for testing.
25+
26+
* The file **test_tools.py** contains functions that are used for testing.
27+
28+
## Citation
29+
30+
This algorithm is described in detail in the paper *"Quantum Algorithm based on Quantum Fourier Transform for Register-by-Constant Addition"* (https://doi.org/10.48550/arXiv.2207.05309). If you use this algorithm in your research, please cite it as follows:
31+
32+
```
33+
@misc{ferraz_22,
34+
doi = {10.48550/ARXIV.2207.05309},
35+
url = {https://arxiv.org/abs/2207.05309},
36+
author = {Ferraz, Filipe Chagas},
37+
keywords = {Quantum Physics (quant-ph), FOS: Physical sciences, FOS: Physical sciences},
38+
title = {Quantum Algorithm based on Quantum Fourier Transform for Register-by-Constant Addition},
39+
publisher = {arXiv},
40+
year = {2022},
41+
copyright = {Creative Commons Attribution 4.0 International}
42+
}
43+
```

img/QAdder.png

18.1 KB
Loading

numeric_systems.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
#By Filipe Chagas
2+
#Mar 2022
3+
4+
from typing import *
5+
6+
def natural_to_binary(x: int, n: int) -> List[bool]:
7+
"""Returns x in the binary system.
8+
9+
:param x: Natural (including zero) to convert.
10+
:type x: int
11+
:param n: Number of bits.
12+
:type n: int
13+
:return: List of bits. Each bit is a bool. Most significant bit last.
14+
:rtype: List[bool]
15+
"""
16+
assert n > 0
17+
assert x >= 0
18+
assert x < 2**n
19+
return [bool((x//2**i)%2) for i in range(n)]
20+
21+
def binary_to_natural(x: List[bool]) -> int:
22+
"""Returns x as a natural number (including zero).
23+
24+
:param x: List of bits. Most significant bit last.
25+
:type x: List[bool]
26+
:return: Natural number (including zero).
27+
:rtype: int
28+
"""
29+
n = len(x)
30+
return sum([(2**i)*int(x[i]) for i in range(n)])
31+
32+
def two_complement(x: List[bool]) -> List[bool]:
33+
"""Returns the 2's complement for x.
34+
35+
:param x: List of bits. Most significant bit last.
36+
:type x: List[bool]
37+
:return: 2's complement of x. List of bits. Most significant bit last.
38+
:rtype: List[bool]
39+
"""
40+
n = len(x)
41+
one_complement = [not x_i for x_i in x]
42+
return natural_to_binary(binary_to_natural(one_complement) + 1, n)
43+
44+
def integer_to_binary(x: int, n: int) -> List[bool]:
45+
"""Returns x in the binary system using 2's complement notation.
46+
47+
:param x: Integer value to convert.
48+
:type x: int
49+
:param n: Number of bits.
50+
:type n: int
51+
:return: List of bits. Less significant bit fist. Sign bit last.
52+
:rtype: List[bool]
53+
"""
54+
assert n > 0
55+
assert x < 2**(n-1)
56+
assert x >= -2**(n-1)
57+
return natural_to_binary(x, n) if x >= 0 else two_complement(natural_to_binary(-x, n))
58+
59+
def binary_to_integer(x: List[bool]) -> int:
60+
"""Returns x as an integer number.
61+
62+
:param x: List of bits. Less significant bit fist. Sign bit last.
63+
:type x: List[bool]
64+
:return: Integer number.
65+
:rtype: int
66+
"""
67+
n = len(x)
68+
return binary_to_natural(x) if x[n-1] == False else -binary_to_natural(two_complement(x))

qiskit_quantum_fourier_transform.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#By Filipe Chagas
2+
#2022
3+
4+
import qiskit
5+
from math import *
6+
7+
def qft(n: int) -> qiskit.circuit.Gate:
8+
"""Returns a QFT gate for n qubits.
9+
10+
:param n: Number of target qubits.
11+
:type n: int
12+
:return: QFT gate.
13+
:rtype: qiskit.circuit.Gate
14+
"""
15+
def rotations(my_circuit: qiskit.circuit.Gate, m: int):
16+
if m == 0:
17+
return my_circuit
18+
else:
19+
my_circuit.h(m-1) #Add a Haddamard gate to the most significant qubit
20+
21+
for i in range(m-1):
22+
my_circuit.crz(pi/(2**(m-1-i)), i, m-1)
23+
24+
rotations(my_circuit, m-1)
25+
26+
my_circuit = qiskit.QuantumCircuit(n, name='QFT')
27+
28+
rotations(my_circuit, n)
29+
30+
for m in range(n//2):
31+
my_circuit.swap(m, n-m-1)
32+
33+
return my_circuit.to_gate()

qiskit_reg_by_const_qft_adder.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
#By Filipe Chagas
2+
#2022
3+
4+
import qiskit
5+
from math import *
6+
from qiskit_quantum_fourier_transform import qft
7+
from numeric_systems import *
8+
9+
def reg_by_const_fourier_basis_adder(n: int, c: int) -> qiskit.circuit.Gate:
10+
"""
11+
Register-by-constant addition gate in Fourier basis.
12+
Get a gate to perform an addition of a constant $c$ to an integer register in Fourier basis.
13+
No ancillary qubits needed.
14+
15+
[see https://doi.org/10.48550/arXiv.2207.05309]
16+
17+
:param n: Number of target qubits.
18+
:type n: int
19+
:param c: Constant to add.
20+
:type c: int
21+
:return: $U_{\phi(+)}(c)$ gate.
22+
:rtype: qiskit.circuit.Gate
23+
"""
24+
assert n > 0
25+
26+
my_circuit = qiskit.QuantumCircuit(n, name=f'$U_{{\\phi(+)}}({c})$')
27+
28+
for i in range(n):
29+
theta = c * (pi / (2**(n-i-1)))
30+
my_circuit.rz(theta, i)
31+
32+
return my_circuit.to_gate()
33+
34+
def reg_by_const_qft_adder(n: int, c: int) -> qiskit.circuit.Gate:
35+
"""
36+
Register-by-constant QFT addition gate.
37+
Get a gate to perform an addition of a constant $c$ to a integer register.
38+
No ancillary qubits needed.
39+
40+
[see https://doi.org/10.48550/arXiv.2207.05309]
41+
42+
:param n: Number of target qubits.
43+
:type n: int
44+
:param c: Constant to add.
45+
:type c: int
46+
:return: $U_{+}(c)$ gate.
47+
:rtype: qiskit.circuit.Gate
48+
"""
49+
assert n > 0
50+
51+
my_circuit = qiskit.QuantumCircuit(n, name=f'$U_{{+}}({c})$')
52+
53+
my_qft = qft(n)
54+
my_circuit.append(my_qft, list(range(n)))
55+
my_circuit.append(reg_by_const_fourier_basis_adder(n, c), list(range(n)))
56+
my_circuit.append(my_qft.inverse(), list(range(n)))
57+
58+
return my_circuit.to_gate()
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "code",
5+
"execution_count": 1,
6+
"metadata": {},
7+
"outputs": [],
8+
"source": [
9+
"import qiskit\n",
10+
"from qiskit_reg_by_const_qft_adder import reg_by_const_qft_adder\n",
11+
"from numeric_systems import *\n",
12+
"from typing import *\n",
13+
"from test_tools import *"
14+
]
15+
},
16+
{
17+
"cell_type": "code",
18+
"execution_count": 2,
19+
"metadata": {},
20+
"outputs": [
21+
{
22+
"name": "stdout",
23+
"output_type": "stream",
24+
"text": [
25+
"a=-4, c=-4, result=-8\n",
26+
"a=-4, c=-3, result=-7\n",
27+
"a=-4, c=-2, result=-6\n",
28+
"a=-4, c=-1, result=-5\n",
29+
"a=-4, c=0, result=-4\n",
30+
"a=-4, c=1, result=-3\n",
31+
"a=-4, c=2, result=-2\n",
32+
"a=-3, c=-4, result=-7\n",
33+
"a=-3, c=-3, result=-6\n",
34+
"a=-3, c=-2, result=-5\n",
35+
"a=-3, c=-1, result=-4\n",
36+
"a=-3, c=0, result=-3\n",
37+
"a=-3, c=1, result=-2\n",
38+
"a=-3, c=2, result=-1\n",
39+
"a=-2, c=-4, result=-6\n",
40+
"a=-2, c=-3, result=-5\n",
41+
"a=-2, c=-2, result=-4\n",
42+
"a=-2, c=-1, result=-3\n",
43+
"a=-2, c=0, result=-2\n",
44+
"a=-2, c=1, result=-1\n",
45+
"a=-2, c=2, result=0\n",
46+
"a=-1, c=-4, result=-5\n",
47+
"a=-1, c=-3, result=-4\n",
48+
"a=-1, c=-2, result=-3\n",
49+
"a=-1, c=-1, result=-2\n",
50+
"a=-1, c=0, result=-1\n",
51+
"a=-1, c=1, result=0\n",
52+
"a=-1, c=2, result=1\n",
53+
"a=0, c=-4, result=-4\n",
54+
"a=0, c=-3, result=-3\n",
55+
"a=0, c=-2, result=-2\n",
56+
"a=0, c=-1, result=-1\n",
57+
"a=0, c=0, result=0\n",
58+
"a=0, c=1, result=1\n",
59+
"a=0, c=2, result=2\n",
60+
"a=1, c=-4, result=-3\n",
61+
"a=1, c=-3, result=-2\n",
62+
"a=1, c=-2, result=-1\n",
63+
"a=1, c=-1, result=0\n",
64+
"a=1, c=0, result=1\n",
65+
"a=1, c=1, result=2\n",
66+
"a=1, c=2, result=3\n",
67+
"a=2, c=-4, result=-2\n",
68+
"a=2, c=-3, result=-1\n",
69+
"a=2, c=-2, result=0\n",
70+
"a=2, c=-1, result=1\n",
71+
"a=2, c=0, result=2\n",
72+
"a=2, c=1, result=3\n",
73+
"a=2, c=2, result=4\n"
74+
]
75+
}
76+
],
77+
"source": [
78+
"for a in range(-4, 3):\n",
79+
" for c in range(-4, 3):\n",
80+
" #Create the quantum circuit\n",
81+
" my_circuit = qiskit.QuantumCircuit(4)\n",
82+
"\n",
83+
" #Initialize register with $a$\n",
84+
" a_binary = integer_to_binary(a, 4)\n",
85+
" for i in range(4):\n",
86+
" if a_binary[i] == True:\n",
87+
" my_circuit.x(i)\n",
88+
"\n",
89+
" #Create gate\n",
90+
" g = reg_by_const_qft_adder(4, c)\n",
91+
"\n",
92+
" #Append gate to the circuit\n",
93+
" my_circuit.append(g, list(range(4)))\n",
94+
"\n",
95+
" #Append measurements\n",
96+
" my_circuit.measure_all()\n",
97+
"\n",
98+
" #Simulation\n",
99+
" result_binary = one_shot_simulation(my_circuit)\n",
100+
" result_integer = binary_to_integer(result_binary)\n",
101+
" print(f'a={a}, c={c}, result={result_integer}')"
102+
]
103+
}
104+
],
105+
"metadata": {
106+
"kernelspec": {
107+
"display_name": "Python 3",
108+
"language": "python",
109+
"name": "python3"
110+
},
111+
"language_info": {
112+
"codemirror_mode": {
113+
"name": "ipython",
114+
"version": 3
115+
},
116+
"file_extension": ".py",
117+
"mimetype": "text/x-python",
118+
"name": "python",
119+
"nbconvert_exporter": "python",
120+
"pygments_lexer": "ipython3",
121+
"version": "3.8.5"
122+
}
123+
},
124+
"nbformat": 4,
125+
"nbformat_minor": 4
126+
}

test_tools.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# By Filipe Chagas
2+
# 2022
3+
4+
import qiskit
5+
from numeric_systems import *
6+
from typing import *
7+
8+
def result_string_to_list(result: str) -> List[bool]:
9+
"""Convert a string result to a list of bits.
10+
11+
:param result: String result from Qiskit.
12+
:type result: str
13+
:return: List of bits. Most significant bit last.
14+
:rtype: List[bool]
15+
"""
16+
return [(True if c == '1' else False) for c in result[::-1]]
17+
18+
def extract_register_from_result(result: List[bool], register: List[int]) -> List[bool]:
19+
"""Extract a register from a list of bits.
20+
21+
:param result: List of bits from Qiskit result. Most significant bit last.
22+
:type result: List[bool]
23+
:param register: List of register's qubits indexes. Most significant bit last.
24+
:type register: List[int]
25+
:return: List of bits. Most significant bit last.
26+
:rtype: List[bool]
27+
"""
28+
return [result[i] for i in register]
29+
30+
def one_shot_simulation(circuit: qiskit.QuantumCircuit) -> List[bool]:
31+
"""Do a one-shot simulation with Qiskit and return it's result as a list of bits.
32+
33+
:param circuit: Qiskit quantum circuit.
34+
:type circuit: qiskit.QuantumCircuit
35+
:return: List of bits. Most significant bit last.
36+
:rtype: List[bool]
37+
"""
38+
backend = qiskit.BasicAer.get_backend('qasm_simulator')
39+
job = qiskit.execute(circuit, backend, shots=1)
40+
counts = job.result().get_counts()
41+
result_string = list(counts.keys())[0]
42+
return result_string_to_list(result_string)

0 commit comments

Comments
 (0)