import math
from qibo import gates
from qibo.config import raise_error
from qibo.models.circuit import Circuit
[docs]def QFT(nqubits: int, with_swaps: bool = True, accelerators=None, **kwargs) -> Circuit:
"""Creates a circuit that implements the Quantum Fourier Transform.
Args:
nqubits (int): number of qubits in the circuit.
with_swaps (bool, optional): If ``True``, uses :class:`qibo.gates.SWAP` gates
at the end of the circuit so that the qubit order in the final
state is the same as the initial state. Defauts to ``True``.
accelerators (dict, optional): Accelerator device dictionary in order to use a
distributed circuit. If ``None``, a simple (non-distributed)
circuit will be used.
kwargs (dict, optional): Additional arguments used to initialize
:class:`qibo.models.Circuit`. For details, see the documentation
of :class:`qibo.models.circuit.Circuit`.
Returns:
:class:`qibo.models.Circuit`: implementation of the Quantum Fourier Transform.
Example:
.. testcode::
import numpy as np
from qibo.models import QFT
nqubits = 6
circuit = QFT(nqubits)
# Random normalized initial state vector
init_state = np.random.random(2 ** nqubits) + 1j * np.random.random(2 ** nqubits)
init_state = init_state / np.sqrt((np.abs(init_state)**2).sum())
# Execute the circuit
final_state = circuit(init_state)
"""
if accelerators is not None:
if not with_swaps:
raise_error(
NotImplementedError,
"Distributed QFT is only implemented " "with SWAPs.",
)
return _DistributedQFT(nqubits, accelerators, **kwargs)
circuit = Circuit(nqubits, **kwargs)
for i1 in range(nqubits):
circuit.add(gates.H(i1))
for i2 in range(i1 + 1, nqubits):
theta = math.pi / 2 ** (i2 - i1)
circuit.add(gates.CU1(i2, i1, theta))
if with_swaps:
for i in range(nqubits // 2):
circuit.add(gates.SWAP(i, nqubits - i - 1))
return circuit
def _DistributedQFT(nqubits, accelerators=None, **kwargs):
"""QFT with the order of gates optimized for reduced multi-device communication."""
circuit = Circuit(nqubits, accelerators, **kwargs)
icrit = nqubits // 2 + nqubits % 2
if accelerators is not None:
circuit.global_qubits = range(circuit.nlocal, nqubits) # pylint: disable=E1101
if icrit < circuit.nglobal: # pylint: disable=E1101
raise_error(
NotImplementedError,
f"Cannot implement QFT for {nqubits} qubits "
+ f"using {circuit.nglobal} global qubits.",
) # pylint: disable=E1101
for i1 in range(nqubits):
if i1 < icrit:
i1eff = i1
else:
i1eff = nqubits - i1 - 1
circuit.add(gates.SWAP(i1, i1eff))
circuit.add(gates.H(i1eff))
for i2 in range(i1 + 1, nqubits):
theta = math.pi / 2 ** (i2 - i1)
circuit.add(gates.CU1(i2, i1eff, theta))
return circuit