Skip to content
This repository was archived by the owner on Dec 7, 2021. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 26 additions & 25 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,47 +33,47 @@ Added
- OptimizationAlgorithm: A base class for optimization algorithm
- OptimizationResult: A base class for optimization results
- Summary of the optimization algorithms:
- MinimumEigenOptimizer: An optimization algorithm using a minimum eigen solver, such as VQE (or a classical
- MinimumEigenOptimizer: An optimization algorithm using a minimum eigen solver, such as VQE (or a classical
alternative). See the MinimumEigenSolver algorithms in Aqua.
- GroverOptimizer: The Grover Adaptive Search algorithm (Gilliam et al.)
- ADMMOptimizer: The ADMM-based heuristic (Gambella et al.)
- RecursiveMinimumEigenOptimizer: A meta-algorithm applying recursive optimization on top of a
- RecursiveMinimumEigenOptimizer: A meta-algorithm applying recursive optimization on top of a
MinimumEigenOptimizer (Bravyi et al.)
- CobylaOptimizer: Wrapping of SciPy’s COBYLA subroutine as optimization algorithm
- CplexOptimizer: Wrapping the CPLEX API as optimization algorithm
- A set of converters to translate different problem representations
- InequalityToEquality: Converts inequality constraints to equality constraints by adding slack variables
- IntegerToBinary: Converts integer variables to binary variables
- LinearEqualityToPenalty: Converts linear equality constraints to quadratic penalty terms that are added
- LinearEqualityToPenalty: Converts linear equality constraints to quadratic penalty terms that are added
to the objective
- QuadraticProgramToOperator: Converts a QuadraticProgram to an Aqua operator
- QuadraticProgramToNegativeValueOracle: Converts a QuadraticProgram to a negative-value oracle used for
- QuadraticProgramToNegativeValueOracle: Converts a QuadraticProgram to a negative-value oracle used for
Grover Adaptive Search
- QuadraticProgramToQubo: Converts a QuadraticProgram to a QUBO problem, a convenience converter wrapping the
- QuadraticProgramToQubo: Converts a QuadraticProgram to a QUBO problem, a convenience converter wrapping the
functionality of the IntegerToBinary and LinearEqualityToPenalty converters
- Operator flow, a set of tools for constructing Physically-intuitive quantum computations using State functions,
- Operator flow, a set of tools for constructing Physically-intuitive quantum computations using State functions,
Operators, and Measurements, and relying on Terra's Operator objects as computational primitives (#852)
- `OperatorBase`: A base class for Operators, State functions, Measurements, and combinations thereof
- `primitive_ops`: Classes for representing basic Operator building blocks, backed by computational
- `primitive_ops`: Classes for representing basic Operator building blocks, backed by computational
primitives in Terra. Includes `PrimitiveOp` (base and factory), `PauliOp`, `MatrixOp`, and `CircuitOp`
- `list_ops`: Classes for representing composite Operators, State functions, and Measurements constructed
from others, including `ListOp` (*non-abstract* parent), `SummedOp`, `ComposedOp`, and `TensoredOp`
- `state_fns`: Classes for representing State function and Measurement building blocks, backed by
primitives in Terra (other than `DictStateFn`, which is back by a `dict`). Includes
`StateFn` (base and factory), `DictStateFn`, `CircuitStateFn`, `VectorStateFn`, and `OperatorStateFn`
- `operator_globals`: A set of convenient immutable building block `OperatorBase` instances, including
single-qubit Paulis (`X`, `Y`, `Z`, `I`), basic gates (`H`, `CX`, `T`, `S`, `Swap`, `CZ`), and
- `list_ops`: Classes for representing composite Operators, State functions, and Measurements constructed
from others, including `ListOp` (*non-abstract* parent), `SummedOp`, `ComposedOp`, and `TensoredOp`
- `state_fns`: Classes for representing State function and Measurement building blocks, backed by
primitives in Terra (other than `DictStateFn`, which is back by a `dict`). Includes
`StateFn` (base and factory), `DictStateFn`, `CircuitStateFn`, `VectorStateFn`, and `OperatorStateFn`
- `operator_globals`: A set of convenient immutable building block `OperatorBase` instances, including
single-qubit Paulis (`X`, `Y`, `Z`, `I`), basic gates (`H`, `CX`, `T`, `S`, `Swap`, `CZ`), and
single-qubit states (`Zero`, `One`, `Plus`, `Minus`)
- `converters`: Classes for manipulating and modifying Operators, including `ConverterBase` (base),
- `converters`: Classes for manipulating and modifying Operators, including `ConverterBase` (base),
`CircuitSampler`, `PauliBasisChange`, `DictToCircuitSum`, and `AbelianGrouper`
- `expectations`: Converters for changing measurements of Observables to be more efficient or tractable,
- `expectations`: Converters for changing measurements of Observables to be more efficient or tractable,
including `ExpectationBase` (base), `ExpectationFactory` (factory), `PauliExpectation`,
`MatrixExpectation`, and `AerPauliExpectation`
- `evolutions`: Converters for changing Unitary evolutions of Hamiltonian Operators into
`CircuitOps` approximating or equalling the exponentiation e^(-iHt). Includes
`EvolutionBase` (base), `EvolutionFactory` (factory), `EvolvedOp` (lazy placeholder
Operator for evolution), `PauliTrotterEvolution`, `MatrixEvolution`,
`TrotterizationBase` (base), `TrotterizationFactory` (factory), `Trotter`,
`MatrixExpectation`, and `AerPauliExpectation`
- `evolutions`: Converters for changing Unitary evolutions of Hamiltonian Operators into
`CircuitOps` approximating or equalling the exponentiation e^(-iHt). Includes
`EvolutionBase` (base), `EvolutionFactory` (factory), `EvolvedOp` (lazy placeholder
Operator for evolution), `PauliTrotterEvolution`, `MatrixEvolution`,
`TrotterizationBase` (base), `TrotterizationFactory` (factory), `Trotter`,
`Suzuki`, and `QDrift`
- The QDrift Trotterization algorithm (#852)
- Operator evolution using Terra's `HamiltonianGate` for improved performance (#852)
Expand All @@ -90,10 +90,10 @@ Changed
- If ibmq-provider is used and job limit is reached, `run_circuit` now waits for a previous job
to finish before submitting the next one. (#906)
- Deprecate using `FeatureMap` and `VariationalForm` in VQC and QSVM (#905)
- The Eigensolvers and MinimumEigensolvers now accept `OperatorBase` (Operator flow) Observables
- The Eigensolvers and MinimumEigensolvers now accept `OperatorBase` (Operator flow) Observables
in addition to the existing Operators (#852).
- The `BaseOperator` was renamed `LegacyBaseOperator` to avoid confusion with the new
Operator flow `OperatorBase` (#852).
- The `BaseOperator` was renamed `LegacyBaseOperator` to avoid confusion with the new
Operator flow `OperatorBase` (#852).

Removed
-------
Expand All @@ -103,6 +103,7 @@ Removed
- multi-controlled Toffoli, U1 and Pauli rotation gates (including tests) (#833)
- arithmetic circuits in qiskit/aqua/circuits (#895)
- boolean logic gates (#896)
- quantum Fourier transformation (#909)

Fixed
-----
Expand Down
149 changes: 45 additions & 104 deletions qiskit/aqua/algorithms/factorizers/shor.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,8 @@
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.
"""
The Shor's Factoring algorithm. This implementation is based on the following paper:
Stephane Beauregard, "Circuit for Shor's algorithm using 2n+3 qubits",
Quantum Information and Computation, Vol. 3, No. 2 (2003) pp. 175-185
"""

"""Shor's factoring algorithm."""

from typing import Optional, Union
import math
Expand All @@ -25,12 +22,12 @@
import numpy as np

from qiskit import ClassicalRegister, QuantumCircuit, QuantumRegister
from qiskit.circuit.library import QFT
from qiskit.providers import BaseBackend
from qiskit.aqua import QuantumInstance
from qiskit.aqua.utils.arithmetic import is_power
from qiskit.aqua.utils import get_subsystem_density_matrix
from qiskit.aqua.algorithms import QuantumAlgorithm
from qiskit.aqua.circuits import FourierTransformCircuits as ftc
from qiskit.aqua.utils import summarize_circuits
from qiskit.aqua.utils.validation import validate_min

Expand All @@ -40,8 +37,7 @@


class Shor(QuantumAlgorithm):
"""
The Shor's Factoring algorithm.
"""Shor's factoring algorithm.

Shor's Factoring algorithm is one of the most well-known quantum algorithms and finds the
prime factors for input integer :math:`N` in polynomial time.
Expand All @@ -65,6 +61,7 @@ def __init__(self,
N: The integer to be factored, has a min. value of 3.
a: A random integer that satisfies a < N and gcd(a, N) = 1, has a min. value of 2.
quantum_instance: Quantum Instance or Backend

Raises:
ValueError: Invalid input
"""
Expand Down Expand Up @@ -95,10 +92,11 @@ def __init__(self,
logger.info('The input integer is a power: %s=%s^%s.', N, b, p)
self._ret['factors'].append(b)

self._qft = QFT(do_swaps=False)
self._iqft = self._qft.inverse()

def _get_angles(self, a):
"""
Calculate the array of angles to be used in the addition in Fourier Space
"""
"""Calculate the array of angles to be used in the addition in Fourier Space."""
s = bin(int(a))[2:].zfill(self._n + 1)
angles = np.zeros([self._n + 1])
for i in range(0, self._n + 1):
Expand All @@ -109,18 +107,16 @@ def _get_angles(self, a):
return angles

def _phi_add(self, circuit, q, inverse=False):
"""
Creation of the circuit that performs addition by a in Fourier Space
Can also be used for subtraction by setting the parameter inverse=True
"""Creation of the circuit that performs addition by a in Fourier Space.

Can also be used for subtraction by setting the parameter ``inverse=True``.
"""
angle = self._get_angles(self._N)
for i in range(0, self._n + 1):
circuit.u1(-angle[i] if inverse else angle[i], q[i])

def _controlled_phi_add(self, circuit, q, ctl, inverse=False):
"""
Single controlled version of the _phi_add circuit
"""
"""Single controlled version of the _phi_add circuit."""
angles = self._get_angles(self._N)
for i in range(0, self._n + 1):
angle = (-angles[i] if inverse else angles[i]) / 2
Expand All @@ -132,96 +128,54 @@ def _controlled_phi_add(self, circuit, q, ctl, inverse=False):
circuit.u1(angle, q[i])

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

def _controlled_controlled_phi_add_mod_N(self, circuit, q, ctl1, ctl2, aux, a):
"""
Circuit that implements doubly controlled modular addition by a
"""
"""Circuit that implements doubly controlled modular addition by a."""
qubits = [q[i] for i in reversed(range(self._n + 1))]

self._controlled_controlled_phi_add(circuit, q, ctl1, ctl2, a)
self._phi_add(circuit, q, inverse=True)
ftc.construct_circuit(
circuit=circuit,
qubits=[q[i] for i in reversed(range(self._n + 1))],
do_swaps=False,
inverse=True
)

circuit.compose(self._iqft, qubits, inplace=True)
circuit.cx(q[self._n], aux)
ftc.construct_circuit(
circuit=circuit,
qubits=[q[i] for i in reversed(range(self._n + 1))],
do_swaps=False
)
circuit.compose(self._qft, qubits, inplace=True)
self._controlled_phi_add(circuit, q, aux)

self._controlled_controlled_phi_add(circuit, q, ctl1, ctl2, a, inverse=True)
ftc.construct_circuit(
circuit=circuit,
qubits=[q[i] for i in reversed(range(self._n + 1))],
do_swaps=False,
inverse=True
)
circuit.compose(self._iqft, qubits, inplace=True)
circuit.u3(np.pi, 0, np.pi, q[self._n])
circuit.cx(q[self._n], aux)
circuit.u3(np.pi, 0, np.pi, q[self._n])
ftc.construct_circuit(
circuit=circuit,
qubits=[q[i] for i in reversed(range(self._n + 1))],
do_swaps=False
)
circuit.compose(self._qft, qubits, inplace=True)
self._controlled_controlled_phi_add(circuit, q, ctl1, ctl2, a)

def _controlled_controlled_phi_add_mod_N_inv(self, circuit, q, ctl1, ctl2, aux, a):
"""
Circuit that implements the inverse of doubly controlled modular addition by a
"""
"""Circuit that implements the inverse of doubly controlled modular addition by a."""
qubits = [q[i] for i in reversed(range(self._n + 1))]

self._controlled_controlled_phi_add(circuit, q, ctl1, ctl2, a, inverse=True)
ftc.construct_circuit(
circuit=circuit,
qubits=[q[i] for i in reversed(range(self._n + 1))],
do_swaps=False,
inverse=True
)
circuit.compose(self._iqft, qubits, inplace=True)
circuit.u3(np.pi, 0, np.pi, q[self._n])
circuit.cx(q[self._n], aux)
circuit.u3(np.pi, 0, np.pi, q[self._n])
ftc.construct_circuit(
circuit=circuit,
qubits=[q[i] for i in reversed(range(self._n + 1))],
do_swaps=False
)
circuit.compose(self._qft, qubits, inplace=True)
self._controlled_controlled_phi_add(circuit, q, ctl1, ctl2, a)
self._controlled_phi_add(circuit, q, aux, inverse=True)
ftc.construct_circuit(
circuit=circuit,
qubits=[q[i] for i in reversed(range(self._n + 1))],
do_swaps=False,
inverse=True
)
circuit.compose(self._iqft, qubits, inplace=True)
circuit.cx(q[self._n], aux)
ftc.construct_circuit(
circuit=circuit,
qubits=[q[i] for i in reversed(range(self._n + 1))],
do_swaps=False
)
circuit.compose(self._qft, qubits, inplace=True)
self._phi_add(circuit, q)
self._controlled_controlled_phi_add(circuit, q, ctl1, ctl2, a, inverse=True)

def _controlled_multiple_mod_N(self, circuit, ctl, q, aux, a):
"""
Circuit that implements single controlled modular multiplication by a
"""
ftc.construct_circuit(
circuit=circuit,
qubits=[aux[i] for i in reversed(range(self._n + 1))],
do_swaps=False
)
"""Circuit that implements single controlled modular multiplication by a."""
qubits = [aux[i] for i in reversed(range(self._n + 1))]
circuit.compose(self._qft, qubits, inplace=True)

for i in range(0, self._n):
self._controlled_controlled_phi_add_mod_N(
Expand All @@ -232,12 +186,7 @@ def _controlled_multiple_mod_N(self, circuit, ctl, q, aux, a):
aux[self._n + 1],
(2 ** i) * a % self._N
)
ftc.construct_circuit(
circuit=circuit,
qubits=[aux[i] for i in reversed(range(self._n + 1))],
do_swaps=False,
inverse=True
)
circuit.compose(self._iqft, qubits, inplace=True)

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

a_inv = modinv(a, self._N)
ftc.construct_circuit(
circuit=circuit,
qubits=[aux[i] for i in reversed(range(self._n + 1))],
do_swaps=False
)
circuit.compose(self._qft, qubits, inplace=True)

for i in reversed(range(self._n)):
self._controlled_controlled_phi_add_mod_N_inv(
Expand All @@ -272,25 +217,22 @@ def egcd(a, b):
aux[self._n + 1],
math.pow(2, i) * a_inv % self._N
)
ftc.construct_circuit(
circuit=circuit,
qubits=[aux[i] for i in reversed(range(self._n + 1))],
do_swaps=False,
inverse=True
)

def construct_circuit(self, measurement=False):
circuit.compose(self._iqft, qubits, inplace=True)

def construct_circuit(self, measurement: bool = False) -> QuantumCircuit:
"""Construct circuit.

Args:
measurement (bool): Boolean flag to indicate if measurement
should be included in the circuit.
measurement: Boolean flag to indicate if measurement should be included in the circuit.

Returns:
QuantumCircuit: quantum circuit.
Quantum circuit.
"""

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

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

# Apply inverse QFT
ftc.construct_circuit(circuit=circuit, qubits=self._up_qreg, do_swaps=True, inverse=True)
iqft = QFT(len(self._up_qreg), inverse=True)
circuit.compose(iqft, qubits=self._up_qreg)

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

def _get_factors(self, output_desired, t_upper):
"""
Apply the continued fractions to find r and the gcd to find the desired factors.
"""
"""Apply the continued fractions to find r and the gcd to find the desired factors."""
x_value = int(output_desired, 2)
logger.info('In decimal, x_final value for this result is: %s.', x_value)

Expand Down