Repository: qutip/qutip

Issue:
Quantum Fourier Transform error
Hello, i discovered an error in the implementation of the QFT. Namely when i want to obtain the gate sequence. The is when tha code runs this 

if swapping is True:
            for i in range(N // 2):
                qc.add_gate(r"SWAP", targets=[i], controls=[N - 1 - i, i])

it gives an error because the swap  gate needs two targets and it is only passing one.

Here is a test code

qft.qft_gate_sequence(N=2)


Discussion:
I solved the problem by changing

qc.add_gate(r"SWAP", targets=[i], controls=[N - 1 - i, i])

to

qc.add_gate(r"SWAP", targets=[N-i-1, i])

Resolving patch:
diff --git a/qutip/qip/algorithms/qft.py b/qutip/qip/algorithms/qft.py
--- a/qutip/qip/algorithms/qft.py
+++ b/qutip/qip/algorithms/qft.py
@@ -101,7 +101,7 @@ def qft_steps(N=1, swapping=True):
                 U_step_list.append(cphase(np.pi / (2 ** (i - j)), N,
                                           control=i, target=j))
             U_step_list.append(snot(N, i))
-        if swapping is True:
+        if swapping:
             for i in range(N // 2):
                 U_step_list.append(swap(N, [N - i - 1, i]))
 
@@ -135,12 +135,12 @@ def qft_gate_sequence(N=1, swapping=True):
     else:
         for i in range(N):
             for j in range(i):
-                qc.add_gate(r"CPHASE", targets=[j], controls=[i],
+                qc.add_gate("CPHASE", targets=[j], controls=[i],
                             arg_label=r"{\pi/2^{%d}}" % (i - j),
                             arg_value=np.pi / (2 ** (i - j)))
             qc.add_gate("SNOT", targets=[i])
-        if swapping is True:
+        if swapping:
             for i in range(N // 2):
-                qc.add_gate(r"SWAP", targets=[i], controls=[N - 1 - i])
+                qc.add_gate("SWAP", targets=[N - i - 1, i])
 
     return qc
diff --git a/qutip/qip/circuit.py b/qutip/qip/circuit.py
--- a/qutip/qip/circuit.py
+++ b/qutip/qip/circuit.py
@@ -85,9 +85,9 @@ def __init__(self, name, targets=None, controls=None, arg_value=None,
         if name in ["SWAP", "ISWAP", "SQRTISWAP", "SQRTSWAP", "BERKELEY",
                     "SWAPalpha"]:
             if len(self.targets) != 2:
-                raise ValueError("Gate %s requires two target" % name)
+                raise ValueError("Gate %s requires two targets" % name)
             if self.controls is not None:
-                raise ValueError("Gate %s does not require a control" % name)
+                raise ValueError("Gate %s cannot have a control" % name)
 
         if name in ["CNOT", "CSIGN", "CRX", "CRY", "CRZ"]:
             if self.targets is None or len(self.targets) != 1:


Test patch:
diff --git a/qutip/tests/test_qft.py b/qutip/tests/test_qft.py
--- a/qutip/tests/test_qft.py
+++ b/qutip/tests/test_qft.py
@@ -31,8 +31,8 @@
 #    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ###############################################################################
 
-from numpy.testing import assert_, run_module_suite
-from qutip.qip.algorithms.qft import qft, qft_steps
+from numpy.testing import assert_, assert_equal, assert_string_equal, run_module_suite
+from qutip.qip.algorithms.qft import qft, qft_steps, qft_gate_sequence
 from qutip.qip.gates import gate_sequence_product
 
 
@@ -50,6 +50,38 @@ def testQFTComparison(self):
             U2 = gate_sequence_product(qft_steps(N))
             assert_((U1 - U2).norm() < 1e-12)
 
+    def testQFTGateSequenceNoSwapping(self):
+        """
+        qft: Inspect key properties of gate sequences of length N,
+        with swapping disabled.
+        """
+        for N in range(1, 6):
+            circuit = qft_gate_sequence(N, swapping=False)
+            assert_equal(circuit.N, N)
+
+            totsize = N * (N + 1) / 2
+            assert_equal(len(circuit.gates), totsize)
+
+            snots = sum(g.name == "SNOT" for g in circuit.gates)
+            assert_equal(snots, N)
+
+            phases = sum(g.name == "CPHASE" for g in circuit.gates)
+            assert_equal(phases, N * (N - 1) / 2)
+
+    def testQFTGateSequenceWithSwapping(self):
+        """
+        qft: Inspect swap gates added to gate sequences if
+        swapping is enabled.
+        """
+        for N in range(1, 6):
+            circuit = qft_gate_sequence(N, swapping=True)
+
+            phases = int(N * (N + 1) / 2)
+            swaps = int(N // 2)
+            assert_equal(len(circuit.gates), phases + swaps)
+
+            for i in range(phases, phases + swaps):
+                assert_string_equal(circuit.gates[i].name, "SWAP")
 
 if __name__ == "__main__":
     run_module_suite()