11
11
# Any modifications or derivative works of this code must retain this
12
12
# copyright notice, and modified files need to carry a notice indicating
13
13
# 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."""
19
16
20
17
from typing import Optional , Union
21
18
import math
25
22
import numpy as np
26
23
27
24
from qiskit import ClassicalRegister , QuantumCircuit , QuantumRegister
25
+ from qiskit .circuit .library import QFT
28
26
from qiskit .providers import BaseBackend
29
27
from qiskit .aqua import QuantumInstance
30
28
from qiskit .aqua .utils .arithmetic import is_power
31
29
from qiskit .aqua .utils import get_subsystem_density_matrix
32
30
from qiskit .aqua .algorithms import QuantumAlgorithm
33
- from qiskit .aqua .circuits import FourierTransformCircuits as ftc
34
31
from qiskit .aqua .utils import summarize_circuits
35
32
from qiskit .aqua .utils .validation import validate_min
36
33
40
37
41
38
42
39
class Shor (QuantumAlgorithm ):
43
- """
44
- The Shor's Factoring algorithm.
40
+ """Shor's factoring algorithm.
45
41
46
42
Shor's Factoring algorithm is one of the most well-known quantum algorithms and finds the
47
43
prime factors for input integer :math:`N` in polynomial time.
@@ -65,6 +61,7 @@ def __init__(self,
65
61
N: The integer to be factored, has a min. value of 3.
66
62
a: A random integer that satisfies a < N and gcd(a, N) = 1, has a min. value of 2.
67
63
quantum_instance: Quantum Instance or Backend
64
+
68
65
Raises:
69
66
ValueError: Invalid input
70
67
"""
@@ -95,10 +92,11 @@ def __init__(self,
95
92
logger .info ('The input integer is a power: %s=%s^%s.' , N , b , p )
96
93
self ._ret ['factors' ].append (b )
97
94
95
+ self ._qft = QFT (do_swaps = False )
96
+ self ._iqft = self ._qft .inverse ()
97
+
98
98
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."""
102
100
s = bin (int (a ))[2 :].zfill (self ._n + 1 )
103
101
angles = np .zeros ([self ._n + 1 ])
104
102
for i in range (0 , self ._n + 1 ):
@@ -109,18 +107,16 @@ def _get_angles(self, a):
109
107
return angles
110
108
111
109
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``.
115
113
"""
116
114
angle = self ._get_angles (self ._N )
117
115
for i in range (0 , self ._n + 1 ):
118
116
circuit .u1 (- angle [i ] if inverse else angle [i ], q [i ])
119
117
120
118
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."""
124
120
angles = self ._get_angles (self ._N )
125
121
for i in range (0 , self ._n + 1 ):
126
122
angle = (- angles [i ] if inverse else angles [i ]) / 2
@@ -132,96 +128,54 @@ def _controlled_phi_add(self, circuit, q, ctl, inverse=False):
132
128
circuit .u1 (angle , q [i ])
133
129
134
130
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."""
138
132
angle = self ._get_angles (a )
139
133
for i in range (self ._n + 1 ):
140
134
# ccphase(circuit, -angle[i] if inverse else angle[i], ctl1, ctl2, q[i])
141
135
circuit .mcu1 (- angle [i ] if inverse else angle [i ], [ctl1 , ctl2 ], q [i ])
142
136
143
137
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
+
147
141
self ._controlled_controlled_phi_add (circuit , q , ctl1 , ctl2 , a )
148
142
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 )
155
145
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 )
161
147
self ._controlled_phi_add (circuit , q , aux )
162
148
163
149
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 )
170
151
circuit .u3 (np .pi , 0 , np .pi , q [self ._n ])
171
152
circuit .cx (q [self ._n ], aux )
172
153
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 )
178
155
self ._controlled_controlled_phi_add (circuit , q , ctl1 , ctl2 , a )
179
156
180
157
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
+
184
161
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 )
191
163
circuit .u3 (np .pi , 0 , np .pi , q [self ._n ])
192
164
circuit .cx (q [self ._n ], aux )
193
165
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 )
199
167
self ._controlled_controlled_phi_add (circuit , q , ctl1 , ctl2 , a )
200
168
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 )
207
170
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 )
213
172
self ._phi_add (circuit , q )
214
173
self ._controlled_controlled_phi_add (circuit , q , ctl1 , ctl2 , a , inverse = True )
215
174
216
175
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 )
225
179
226
180
for i in range (0 , self ._n ):
227
181
self ._controlled_controlled_phi_add_mod_N (
@@ -232,12 +186,7 @@ def _controlled_multiple_mod_N(self, circuit, ctl, q, aux, a):
232
186
aux [self ._n + 1 ],
233
187
(2 ** i ) * a % self ._N
234
188
)
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 )
241
190
242
191
for i in range (0 , self ._n ):
243
192
circuit .cswap (ctl , q [i ], aux [i ])
@@ -257,11 +206,7 @@ def egcd(a, b):
257
206
return x % m
258
207
259
208
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 )
265
210
266
211
for i in reversed (range (self ._n )):
267
212
self ._controlled_controlled_phi_add_mod_N_inv (
@@ -272,25 +217,22 @@ def egcd(a, b):
272
217
aux [self ._n + 1 ],
273
218
math .pow (2 , i ) * a_inv % self ._N
274
219
)
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 :
283
223
"""Construct circuit.
284
224
285
225
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
+
288
228
Returns:
289
- QuantumCircuit: quantum circuit.
229
+ Quantum circuit.
290
230
"""
291
231
292
232
# Get n value used in Shor's algorithm, to know how many qubits are used
293
233
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
294
236
295
237
# quantum register where the sequential QFT is performed
296
238
self ._up_qreg = QuantumRegister (2 * self ._n , name = 'up' )
@@ -318,7 +260,8 @@ def construct_circuit(self, measurement=False):
318
260
)
319
261
320
262
# 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 )
322
265
323
266
if measurement :
324
267
up_cqreg = ClassicalRegister (2 * self ._n , name = 'm' )
@@ -330,9 +273,7 @@ def construct_circuit(self, measurement=False):
330
273
return circuit
331
274
332
275
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."""
336
277
x_value = int (output_desired , 2 )
337
278
logger .info ('In decimal, x_final value for this result is: %s.' , x_value )
338
279
0 commit comments