Skip to content

Commit 12a3e1a

Browse files
authored
Update Shor to use the circuit library's QFT (qiskit-community/qiskit-aqua#932)
* shor uses cirlib qft * fix num qubit setting * add changelog on QFT
1 parent 29d9e5c commit 12a3e1a

File tree

1 file changed

+45
-104
lines changed
  • qiskit/aqua/algorithms/factorizers

1 file changed

+45
-104
lines changed

qiskit/aqua/algorithms/factorizers/shor.py

Lines changed: 45 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,8 @@
1111
# Any modifications or derivative works of this code must retain this
1212
# copyright notice, and modified files need to carry a notice indicating
1313
# that they have been altered from the originals.
14-
"""
15-
The Shor's Factoring algorithm. This implementation is based on the following paper:
16-
Stephane Beauregard, "Circuit for Shor's algorithm using 2n+3 qubits",
17-
Quantum Information and Computation, Vol. 3, No. 2 (2003) pp. 175-185
18-
"""
14+
15+
"""Shor's factoring algorithm."""
1916

2017
from typing import Optional, Union
2118
import math
@@ -25,12 +22,12 @@
2522
import numpy as np
2623

2724
from qiskit import ClassicalRegister, QuantumCircuit, QuantumRegister
25+
from qiskit.circuit.library import QFT
2826
from qiskit.providers import BaseBackend
2927
from qiskit.aqua import QuantumInstance
3028
from qiskit.aqua.utils.arithmetic import is_power
3129
from qiskit.aqua.utils import get_subsystem_density_matrix
3230
from qiskit.aqua.algorithms import QuantumAlgorithm
33-
from qiskit.aqua.circuits import FourierTransformCircuits as ftc
3431
from qiskit.aqua.utils import summarize_circuits
3532
from qiskit.aqua.utils.validation import validate_min
3633

@@ -40,8 +37,7 @@
4037

4138

4239
class Shor(QuantumAlgorithm):
43-
"""
44-
The Shor's Factoring algorithm.
40+
"""Shor's factoring algorithm.
4541
4642
Shor's Factoring algorithm is one of the most well-known quantum algorithms and finds the
4743
prime factors for input integer :math:`N` in polynomial time.
@@ -65,6 +61,7 @@ def __init__(self,
6561
N: The integer to be factored, has a min. value of 3.
6662
a: A random integer that satisfies a < N and gcd(a, N) = 1, has a min. value of 2.
6763
quantum_instance: Quantum Instance or Backend
64+
6865
Raises:
6966
ValueError: Invalid input
7067
"""
@@ -95,10 +92,11 @@ def __init__(self,
9592
logger.info('The input integer is a power: %s=%s^%s.', N, b, p)
9693
self._ret['factors'].append(b)
9794

95+
self._qft = QFT(do_swaps=False)
96+
self._iqft = self._qft.inverse()
97+
9898
def _get_angles(self, a):
99-
"""
100-
Calculate the array of angles to be used in the addition in Fourier Space
101-
"""
99+
"""Calculate the array of angles to be used in the addition in Fourier Space."""
102100
s = bin(int(a))[2:].zfill(self._n + 1)
103101
angles = np.zeros([self._n + 1])
104102
for i in range(0, self._n + 1):
@@ -109,18 +107,16 @@ def _get_angles(self, a):
109107
return angles
110108

111109
def _phi_add(self, circuit, q, inverse=False):
112-
"""
113-
Creation of the circuit that performs addition by a in Fourier Space
114-
Can also be used for subtraction by setting the parameter inverse=True
110+
"""Creation of the circuit that performs addition by a in Fourier Space.
111+
112+
Can also be used for subtraction by setting the parameter ``inverse=True``.
115113
"""
116114
angle = self._get_angles(self._N)
117115
for i in range(0, self._n + 1):
118116
circuit.u1(-angle[i] if inverse else angle[i], q[i])
119117

120118
def _controlled_phi_add(self, circuit, q, ctl, inverse=False):
121-
"""
122-
Single controlled version of the _phi_add circuit
123-
"""
119+
"""Single controlled version of the _phi_add circuit."""
124120
angles = self._get_angles(self._N)
125121
for i in range(0, self._n + 1):
126122
angle = (-angles[i] if inverse else angles[i]) / 2
@@ -132,96 +128,54 @@ def _controlled_phi_add(self, circuit, q, ctl, inverse=False):
132128
circuit.u1(angle, q[i])
133129

134130
def _controlled_controlled_phi_add(self, circuit, q, ctl1, ctl2, a, inverse=False):
135-
"""
136-
Doubly controlled version of the _phi_add circuit
137-
"""
131+
"""Doubly controlled version of the _phi_add circuit."""
138132
angle = self._get_angles(a)
139133
for i in range(self._n + 1):
140134
# ccphase(circuit, -angle[i] if inverse else angle[i], ctl1, ctl2, q[i])
141135
circuit.mcu1(-angle[i] if inverse else angle[i], [ctl1, ctl2], q[i])
142136

143137
def _controlled_controlled_phi_add_mod_N(self, circuit, q, ctl1, ctl2, aux, a):
144-
"""
145-
Circuit that implements doubly controlled modular addition by a
146-
"""
138+
"""Circuit that implements doubly controlled modular addition by a."""
139+
qubits = [q[i] for i in reversed(range(self._n + 1))]
140+
147141
self._controlled_controlled_phi_add(circuit, q, ctl1, ctl2, a)
148142
self._phi_add(circuit, q, inverse=True)
149-
ftc.construct_circuit(
150-
circuit=circuit,
151-
qubits=[q[i] for i in reversed(range(self._n + 1))],
152-
do_swaps=False,
153-
inverse=True
154-
)
143+
144+
circuit.compose(self._iqft, qubits, inplace=True)
155145
circuit.cx(q[self._n], aux)
156-
ftc.construct_circuit(
157-
circuit=circuit,
158-
qubits=[q[i] for i in reversed(range(self._n + 1))],
159-
do_swaps=False
160-
)
146+
circuit.compose(self._qft, qubits, inplace=True)
161147
self._controlled_phi_add(circuit, q, aux)
162148

163149
self._controlled_controlled_phi_add(circuit, q, ctl1, ctl2, a, inverse=True)
164-
ftc.construct_circuit(
165-
circuit=circuit,
166-
qubits=[q[i] for i in reversed(range(self._n + 1))],
167-
do_swaps=False,
168-
inverse=True
169-
)
150+
circuit.compose(self._iqft, qubits, inplace=True)
170151
circuit.u3(np.pi, 0, np.pi, q[self._n])
171152
circuit.cx(q[self._n], aux)
172153
circuit.u3(np.pi, 0, np.pi, q[self._n])
173-
ftc.construct_circuit(
174-
circuit=circuit,
175-
qubits=[q[i] for i in reversed(range(self._n + 1))],
176-
do_swaps=False
177-
)
154+
circuit.compose(self._qft, qubits, inplace=True)
178155
self._controlled_controlled_phi_add(circuit, q, ctl1, ctl2, a)
179156

180157
def _controlled_controlled_phi_add_mod_N_inv(self, circuit, q, ctl1, ctl2, aux, a):
181-
"""
182-
Circuit that implements the inverse of doubly controlled modular addition by a
183-
"""
158+
"""Circuit that implements the inverse of doubly controlled modular addition by a."""
159+
qubits = [q[i] for i in reversed(range(self._n + 1))]
160+
184161
self._controlled_controlled_phi_add(circuit, q, ctl1, ctl2, a, inverse=True)
185-
ftc.construct_circuit(
186-
circuit=circuit,
187-
qubits=[q[i] for i in reversed(range(self._n + 1))],
188-
do_swaps=False,
189-
inverse=True
190-
)
162+
circuit.compose(self._iqft, qubits, inplace=True)
191163
circuit.u3(np.pi, 0, np.pi, q[self._n])
192164
circuit.cx(q[self._n], aux)
193165
circuit.u3(np.pi, 0, np.pi, q[self._n])
194-
ftc.construct_circuit(
195-
circuit=circuit,
196-
qubits=[q[i] for i in reversed(range(self._n + 1))],
197-
do_swaps=False
198-
)
166+
circuit.compose(self._qft, qubits, inplace=True)
199167
self._controlled_controlled_phi_add(circuit, q, ctl1, ctl2, a)
200168
self._controlled_phi_add(circuit, q, aux, inverse=True)
201-
ftc.construct_circuit(
202-
circuit=circuit,
203-
qubits=[q[i] for i in reversed(range(self._n + 1))],
204-
do_swaps=False,
205-
inverse=True
206-
)
169+
circuit.compose(self._iqft, qubits, inplace=True)
207170
circuit.cx(q[self._n], aux)
208-
ftc.construct_circuit(
209-
circuit=circuit,
210-
qubits=[q[i] for i in reversed(range(self._n + 1))],
211-
do_swaps=False
212-
)
171+
circuit.compose(self._qft, qubits, inplace=True)
213172
self._phi_add(circuit, q)
214173
self._controlled_controlled_phi_add(circuit, q, ctl1, ctl2, a, inverse=True)
215174

216175
def _controlled_multiple_mod_N(self, circuit, ctl, q, aux, a):
217-
"""
218-
Circuit that implements single controlled modular multiplication by a
219-
"""
220-
ftc.construct_circuit(
221-
circuit=circuit,
222-
qubits=[aux[i] for i in reversed(range(self._n + 1))],
223-
do_swaps=False
224-
)
176+
"""Circuit that implements single controlled modular multiplication by a."""
177+
qubits = [aux[i] for i in reversed(range(self._n + 1))]
178+
circuit.compose(self._qft, qubits, inplace=True)
225179

226180
for i in range(0, self._n):
227181
self._controlled_controlled_phi_add_mod_N(
@@ -232,12 +186,7 @@ def _controlled_multiple_mod_N(self, circuit, ctl, q, aux, a):
232186
aux[self._n + 1],
233187
(2 ** i) * a % self._N
234188
)
235-
ftc.construct_circuit(
236-
circuit=circuit,
237-
qubits=[aux[i] for i in reversed(range(self._n + 1))],
238-
do_swaps=False,
239-
inverse=True
240-
)
189+
circuit.compose(self._iqft, qubits, inplace=True)
241190

242191
for i in range(0, self._n):
243192
circuit.cswap(ctl, q[i], aux[i])
@@ -257,11 +206,7 @@ def egcd(a, b):
257206
return x % m
258207

259208
a_inv = modinv(a, self._N)
260-
ftc.construct_circuit(
261-
circuit=circuit,
262-
qubits=[aux[i] for i in reversed(range(self._n + 1))],
263-
do_swaps=False
264-
)
209+
circuit.compose(self._qft, qubits, inplace=True)
265210

266211
for i in reversed(range(self._n)):
267212
self._controlled_controlled_phi_add_mod_N_inv(
@@ -272,25 +217,22 @@ def egcd(a, b):
272217
aux[self._n + 1],
273218
math.pow(2, i) * a_inv % self._N
274219
)
275-
ftc.construct_circuit(
276-
circuit=circuit,
277-
qubits=[aux[i] for i in reversed(range(self._n + 1))],
278-
do_swaps=False,
279-
inverse=True
280-
)
281-
282-
def construct_circuit(self, measurement=False):
220+
circuit.compose(self._iqft, qubits, inplace=True)
221+
222+
def construct_circuit(self, measurement: bool = False) -> QuantumCircuit:
283223
"""Construct circuit.
284224
285225
Args:
286-
measurement (bool): Boolean flag to indicate if measurement
287-
should be included in the circuit.
226+
measurement: Boolean flag to indicate if measurement should be included in the circuit.
227+
288228
Returns:
289-
QuantumCircuit: quantum circuit.
229+
Quantum circuit.
290230
"""
291231

292232
# Get n value used in Shor's algorithm, to know how many qubits are used
293233
self._n = math.ceil(math.log(self._N, 2))
234+
self._qft.num_qubits = self._n + 1
235+
self._iqft.num_qubits = self._n + 1
294236

295237
# quantum register where the sequential QFT is performed
296238
self._up_qreg = QuantumRegister(2 * self._n, name='up')
@@ -318,7 +260,8 @@ def construct_circuit(self, measurement=False):
318260
)
319261

320262
# Apply inverse QFT
321-
ftc.construct_circuit(circuit=circuit, qubits=self._up_qreg, do_swaps=True, inverse=True)
263+
iqft = QFT(len(self._up_qreg), inverse=True)
264+
circuit.compose(iqft, qubits=self._up_qreg)
322265

323266
if measurement:
324267
up_cqreg = ClassicalRegister(2 * self._n, name='m')
@@ -330,9 +273,7 @@ def construct_circuit(self, measurement=False):
330273
return circuit
331274

332275
def _get_factors(self, output_desired, t_upper):
333-
"""
334-
Apply the continued fractions to find r and the gcd to find the desired factors.
335-
"""
276+
"""Apply the continued fractions to find r and the gcd to find the desired factors."""
336277
x_value = int(output_desired, 2)
337278
logger.info('In decimal, x_final value for this result is: %s.', x_value)
338279

0 commit comments

Comments
 (0)