Source code for qutip_qip.algorithms.qft

"""
This module provides the circuit implementation for Quantum Fourier Transform.
"""

import numpy as np
from qutip import Qobj
from qutip_qip.typing import IntSequence
from qutip_qip.circuit import QubitCircuit
from qutip_qip.decompose import decompose_one_qubit_gate
from qutip_qip.operations import expand_operator
from qutip_qip.operations.gates import H, RZ, CX, CPHASE, SWAP


[docs] def qft(N: int = 1) -> Qobj: """ Quantum Fourier Transform operator on N qubits. Parameters ---------- N : int Number of qubits. (default = 1) Returns ------- QFT : Qobj Quantum Fourier transform operator. """ if N < 1: raise ValueError("Minimum value of N can be 1") N2 = 1 << N phase = 2.0j * np.pi / N2 arr = np.arange(N2) L, M = np.meshgrid(arr, arr) L = phase * (L * M) L = np.exp(L) dims = [[2] * N, [2] * N] return Qobj(1.0 / np.sqrt(N2) * L, dims=dims)
[docs] def qft_steps(N: int = 1, swapping: bool = True) -> list[Qobj]: """ Quantum Fourier Transform operator on N qubits returning the individual steps as unitary matrices operating from left to right. Parameters ---------- N : int Number of qubits. swapping : bool, optional Flag indicating sequence of swap gates to be applied at the end or not. Returns ------- U_step_list : list of Qobj List of Hadamard and controlled rotation gates implementing QFT. """ if N < 1: raise ValueError("Minimum value of N can be 1") U_step_list = [] if N == 1: U_step_list.append(H.get_qobj()) else: for i in range(N): for j in range(i): U_step_list.append( expand_operator( CPHASE(np.pi / (2 ** (i - j))).get_qobj(), dims=[2] * N, targets=[i, j], ) ) U_step_list.append(expand_operator(H.get_qobj(), dims=[2] * N, targets=i)) if swapping: for i in range(N // 2): U_step_list.append( expand_operator( SWAP.get_qobj(), dims=[2] * N, targets=[N - i - 1, i] ) ) return U_step_list
[docs] def qft_gate_sequence( N: int = 1, swapping: bool = True, to_cnot: bool = False ) -> QubitCircuit: """ Quantum Fourier Transform operator on N qubits returning the gate sequence. Parameters ---------- N : int Number of qubits. swapping : bool, optional Flag indicating sequence of swap gates to be applied at the end or not (default: True). to_cnot : bool, optional Flag to decompose controlled phase gates to CNOT gates (default: False). Returns ------- qc : :class:`.QubitCircuit` Gate sequence of Hadamard and controlled rotation gates implementing QFT. """ if N < 1: raise ValueError("Minimum value of N can be 1") qc = QubitCircuit(N) if N == 1: qc.add_gate(H, targets=[0]) else: for i in range(N): for j in range(i): if not to_cnot: qc.add_gate( CPHASE( arg_value=np.pi / (2 ** (i - j)), arg_label=r"{\pi/2^{%d}}" % (i - j), ), targets=[j], controls=[i], ) else: _cphase_to_cnot([j], [i], np.pi / (2 ** (i - j)), qc) qc.add_gate(H, targets=[i]) if swapping: for i in range(N // 2): qc.add_gate(SWAP, targets=[N - i - 1, i]) return qc
def _cphase_to_cnot( targets: int | IntSequence, controls: int | IntSequence, arg_value: float, qc: QubitCircuit, ) -> None: rotation = Qobj([[1.0, 0.0], [0.0, np.exp(1.0j * arg_value)]]) decomposed_gates = list(decompose_one_qubit_gate(rotation, method="ZYZ_PauliX")) qc.add_gate(decomposed_gates[0], targets=targets) qc.add_gate(CX, targets=targets, controls=controls) qc.add_gate(decomposed_gates[4], targets=targets) qc.add_gate(CX, targets=targets, controls=controls) qc.add_gate(RZ(arg_value / 2), targets=controls) gate = decomposed_gates[7] # This is a GLOBALPHASE Gate gate.arg_value = gate.arg_value[0] + arg_value / 4 qc.add_gate(gate, targets=targets)