Source code for pennylane.templates.subroutines.aqft
# Copyright 2018-2023 Xanadu Quantum Technologies Inc.# Licensed under the Apache License, Version 2.0 (the "License");# you may not use this file except in compliance with the License.# You may obtain a copy of the License at# http://www.apache.org/licenses/LICENSE-2.0# Unless required by applicable law or agreed to in writing, software# distributed under the License is distributed on an "AS IS" BASIS,# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.# See the License for the specific language governing permissions and# limitations under the License."""This submodule contains the template for AQFT."""importwarningsimportnumpyasnpimportpennylaneasqmlfrompennylane.operationimportOperation
[docs]classAQFT(Operation):r"""AQFT(order, wires) Apply an approximate quantum Fourier transform (AQFT). The `AQFT <https://arxiv.org/abs/1803.04933>`_ method helps to reduce the number of ``ControlledPhaseShift`` operations required for QFT by only using a maximum of ``order`` number of ``ControlledPhaseShift`` gates per qubit. .. seealso:: :class:`~.QFT` Args: order (int): the order of approximation wires (int or Iterable[Number, str]]): the wire(s) the operation acts on **Example** The approximate quantum Fourier transform is applied by specifying the corresponding wires and the order of approximation: .. code-block:: wires = 3 dev = qml.device('default.qubit', wires=wires) @qml.qnode(dev) def circuit_aqft(): qml.X(0) qml.Hadamard(1) qml.AQFT(order=1,wires=range(wires)) return qml.state() .. code-block:: pycon >>> circuit_aqft() [ 0.5 +0.j -0.25-0.25j 0. +0.j -0.25+0.25j 0.5 +0.j -0.25-0.25j 0. +0.j -0.25+0.25j] .. details:: :title: Usage Details **Order** The order of approximation must be a whole number less than :math:`n-1` where :math:`n` is the number of wires the operation is being applied on. This creates four cases for different ``order`` values: * ``order`` :math:`< 0` This will raise a ``ValueError`` * ``order`` :math:`= 0` This will warn the user that only a Hadamard transform is being applied. .. code-block:: @qml.qnode(dev) def circ(): qml.AQFT(order=0, wires=range(6)) return qml.probs() The resulting circuit is: >>> print(qml.draw(circ, level='device')()) UserWarning: order=0, applying Hadamard transform warnings.warn("order=0, applying Hadamard transform") 0: ──H─╭SWAP─────────────┤ ╭Probs 1: ──H─│─────╭SWAP───────┤ ├Probs 2: ──H─│─────│─────╭SWAP─┤ ├Probs 3: ──H─│─────│─────╰SWAP─┤ ├Probs 4: ──H─│─────╰SWAP───────┤ ├Probs 5: ──H─╰SWAP─────────────┤ ╰Probs * :math:`0 <` ``order`` :math:`< n-1` This is the intended AQFT use case. .. code-block:: @qml.qnode(dev) def circ(): qml.AQFT(order=2, wires=range(4)) return qml.probs() The resulting circuit is: >>> print(qml.draw(circ, level='device')()) 0: ──H─╭Rϕ(1.57)─╭Rϕ(0.79)────────────────────────────────────────╭SWAP───────┤ ╭Probs 1: ────╰●────────│──────────H─╭Rϕ(1.57)─╭Rϕ(0.79)─────────────────│─────╭SWAP─┤ ├Probs 2: ──────────────╰●───────────╰●────────│──────────H─╭Rϕ(1.57)────│─────╰SWAP─┤ ├Probs 3: ─────────────────────────────────────╰●───────────╰●─────────H─╰SWAP───────┤ ╰Probs * ``order`` :math:`\geq n-1` Using the QFT class is recommended in this case. The AQFT operation here is equivalent to QFT. """def__init__(self,order,wires=None,id=None):n_wires=len(wires)ifnotisinstance(order,int):warnings.warn(f"The order must be an integer. Using order = {round(order)}")order=round(order)iforder>=n_wires-1:warnings.warn(f"The order ({order}) is >= to the number of wires - 1 ({n_wires-1}). Using the QFT class is recommended in this case.")order=n_wires-1iforder<0:raiseValueError("Order can not be less than 0")iforder==0:warnings.warn("order=0, applying Hadamard transform")self.hyperparameters["order"]=ordersuper().__init__(wires=wires,id=id)@propertydefnum_params(self):return0
[docs]@staticmethoddefcompute_decomposition(wires,order):# pylint: disable=arguments-differr"""Representation of the operator as a product of other operators (static method). .. math:: O = O_1 O_2 \dots O_n. .. seealso:: :meth:`~.AQFT.decomposition`. Args: wires (Iterable, Wires): wires that the operator acts on order (int): order of approximation Returns: list[Operator]: decomposition of the operator **Example:** >>> qml.AQFT.compute_decomposition((0, 1, 2), order=1) [H(0), ControlledPhaseShift(1.5707963267948966, wires=[1, 0]), H(1), ControlledPhaseShift(1.5707963267948966, wires=[2, 1]), H(2), SWAP(wires=[0, 2])] """n_wires=len(wires)shifts=[2*np.pi*2**-iforiinrange(2,n_wires+1)]decomp_ops=[]fori,wireinenumerate(wires):decomp_ops.append(qml.Hadamard(wire))counter=0forshift,control_wireinzip(shifts[:len(shifts)-i],wires[i+1:]):ifcounter>=order:breakop=qml.ControlledPhaseShift(shift,wires=[control_wire,wire])decomp_ops.append(op)counter=counter+1first_half_wires=wires[:n_wires//2]last_half_wires=wires[-(n_wires//2):]forwire1,wire2inzip(first_half_wires,reversed(last_half_wires)):swap=qml.SWAP(wires=[wire1,wire2])decomp_ops.append(swap)returndecomp_ops