Repository: qutip/qutip

Issue:
More single qubit changes
Include the improvements made on #1208. These changes base from #1209 and #1212: 
- The controlled version of the gates
- Changes in QubitCircuit.propagator()
- Tests


Discussion:

Resolving patch:
diff --git a/qutip/qip/circuit.py b/qutip/qip/circuit.py
--- a/qutip/qip/circuit.py
+++ b/qutip/qip/circuit.py
@@ -38,8 +38,14 @@
 import numpy as np
 
 from qutip.qip import circuit_latex as _latex
-from qutip.qip.operations.gates import *
-from qutip.qip.qubits import qubit_states
+from qutip.qip.operations.gates import (rx, ry, rz, sqrtnot, snot, phasegate,
+                                        x_gate, y_gate, z_gate, cy_gate,
+                                        cz_gate, s_gate, t_gate, cs_gate,
+                                        ct_gate, cphase, cnot, csign,
+                                        berkeley, swapalpha, swap, iswap,
+                                        sqrtswap, sqrtiswap, fredkin,
+                                        toffoli, controlled_gate, globalphase,
+                                        expand_operator)
 
 try:
     from IPython.display import Image as DisplayImage, SVG as DisplaySVG
@@ -55,7 +61,7 @@ def DisplaySVG(data, *args, **kwargs):
 __all__ = ['Gate', 'QubitCircuit']
 
 
-class Gate(object):
+class Gate:
     """
     Representation of a quantum gate, with its required parametrs, and target
     and control qubits.
@@ -107,18 +113,20 @@ def __init__(self, name, targets=None, controls=None, arg_value=None,
             if self.controls is not None:
                 raise ValueError("Gate %s cannot have a control" % name)
 
-        elif name in ["CNOT", "CSIGN", "CRX", "CRY", "CRZ"]:
+        elif name in ["CNOT", "CSIGN", "CRX", "CRY", "CRZ", "CY", "CZ",
+                      "CS", "CT"]:
             if self.targets is None or len(self.targets) != 1:
                 raise ValueError("Gate %s requires one target" % name)
             if self.controls is None or len(self.controls) != 1:
                 raise ValueError("Gate %s requires one control" % name)
 
-        elif name in ["SNOT", "RX", "RY", "RZ", "PHASEGATE"]:
+        elif name in ["SNOT", "RX", "RY", "RZ", "PHASEGATE", "X", "Y",
+                      "Z", "S", "T"]:
             if self.controls is not None:
                 raise ValueError("Gate %s does not take controls" % name)
 
         elif name in ["RX", "RY", "RZ", "CPHASE", "SWAPalpha", "PHASEGATE",
-                            "GLOBALPHASE", "CRX", "CRY", "CRZ"]:
+                      "GLOBALPHASE", "CRX", "CRY", "CRZ"]:
             if arg_value is None:
                 raise ValueError("Gate %s requires an argument value" % name)
 
@@ -130,10 +138,10 @@ def __init__(self, name, targets=None, controls=None, arg_value=None,
         self.arg_label = arg_label
 
     def __str__(self):
-        s = "Gate(%s, targets=%s, controls=%s)" % (self.name,
-                                                   self.targets,
-                                                   self.controls)
-        return s
+        string_name = "Gate(%s, targets=%s, controls=%s)" % (self.name,
+                                                             self.targets,
+                                                             self.controls)
+        return string_name
 
     def __repr__(self):
         return str(self)
@@ -142,12 +150,16 @@ def _repr_latex_(self):
         return str(self)
 
 
-_gate_name_to_label = {
+_GATE_NAME_TO_LABEL = {
     'X': r'X',
     'Y': r'Y',
+    'CY': r'C_y',
     'Z': r'Z',
+    'CZ': r'C_z',
     'S': r'S',
+    'CS': r'C_s',
     'T': r'T',
+    'CT': r'C_t',
     'RX': r'R_x',
     'RY': r'R_y',
     'RZ': r'R_z',
@@ -174,19 +186,18 @@ def _repr_latex_(self):
 
 def _gate_label(name, arg_label):
 
-    if name in _gate_name_to_label:
-        gate_label = _gate_name_to_label[name]
+    if name in _GATE_NAME_TO_LABEL:
+        gate_label = _GATE_NAME_TO_LABEL[name]
     else:
         warnings.warn("Unknown gate %s" % name)
         gate_label = name
 
     if arg_label:
         return r'%s(%s)' % (gate_label, arg_label)
-    else:
-        return r'%s' % gate_label
+    return r'%s' % gate_label
 
 
-class QubitCircuit(object):
+class QubitCircuit:
     """
     Representation of a quantum program/algorithm, maintaining a sequence
     of gates.
@@ -210,8 +221,8 @@ class QubitCircuit(object):
     ...     mat = np.array([[1.,   0],
     ...                     [0., 1.j]])
     ...     return Qobj(mat, dims=[[2], [2]])
-    >>> qc.QubitCircuit(2, user_gates={"T":user_gate})
-    >>> qc.add_gate("T", targets=[0])
+    >>> qubit_circuit.QubitCircuit(2, user_gates={"T":user_gate})
+    >>> qubit_circuit.add_gate("T", targets=[0])
     """
 
     def __init__(self, N, input_states=None, output_states=None,
@@ -325,11 +336,12 @@ def add_1q_gate(self, name, start=0, end=None, qubits=None,
         arg_label : string
             Label for gate representation.
         """
-        if name not in ["RX", "RY", "RZ", "SNOT", "SQRTNOT", "PHASEGATE"]:
+        if name not in ["RX", "RY", "RZ", "SNOT", "SQRTNOT", "PHASEGATE",
+                        "X", "Y", "Z", "S", "T"]:
             raise ValueError("%s is not a single qubit gate" % name)
 
         if qubits is not None:
-            for i in range(len(qubits)):
+            for _, i in enumerate(qubits):
                 self.gates.append(Gate(name, targets=qubits[i], controls=None,
                                        arg_value=arg_value,
                                        arg_label=arg_label))
@@ -361,7 +373,11 @@ def add_circuit(self, qc, start=0):
             if gate.name in ["RX", "RY", "RZ", "SNOT", "SQRTNOT", "PHASEGATE"]:
                 self.add_gate(gate.name, gate.targets[0] + start, None,
                               gate.arg_value, gate.arg_label)
-            elif gate.name in ["CPHASE", "CNOT", "CSIGN", "CRX", "CRY", "CRZ"]:
+            elif gate.name in ["X", "Y", "Z", "S", "T"]:
+                self.add_gate(gate.name, gate.targets[0] + start, None,
+                              None, gate.arg_label)
+            elif gate.name in ["CPHASE", "CNOT", "CSIGN", "CRX", "CRY",
+                               "CRZ", "CY", "CZ", "CS", "CT"]:
                 self.add_gate(gate.name, gate.targets[0] + start,
                               gate.controls[0] + start, gate.arg_value,
                               gate.arg_label)
@@ -381,8 +397,8 @@ def add_circuit(self, qc, start=0):
                               gate.controls + start, None, None)
             elif gate.name in self.user_gates:
                 self.add_gate(
-                              gate.name, targets=gate.targets,
-                              arg_value=gate.arg_value)
+                    gate.name, targets=gate.targets,
+                    arg_value=gate.arg_value)
 
     def remove_gate(self, index=None, end=None, name=None, remove="first"):
         """
@@ -433,7 +449,7 @@ def reverse_circuit(self):
 
         Returns
         -------
-        qc : QubitCircuit
+        qubit_circuit : QubitCircuit
             Return QubitCircuit of resolved gates for the qubit circuit in the
             reverse order.
 
@@ -450,12 +466,10 @@ def resolve_gates(self, basis=["CNOT", "RX", "RY", "RZ"]):
         Unitary matrix calculator for N qubits returning the individual
         steps as unitary matrices operating from left to right in the specified
         basis.
-
         Parameters
         ----------
         basis : list.
             Basis of the resolved circuit.
-
         Returns
         -------
         qc : QubitCircuit
@@ -481,7 +495,7 @@ def resolve_gates(self, basis=["CNOT", "RX", "RY", "RZ"]):
                         "%s is not a valid basis gate" % gate)
             if len(basis_1q) == 1:
                 raise ValueError("Not sufficient single-qubit gates in basis")
-            elif len(basis_1q) == 0:
+            if len(basis_1q) == 0:
                 basis_1q = ["RX", "RY", "RZ"]
 
         else:  # only one 2q gate is given as basis
@@ -499,6 +513,10 @@ def resolve_gates(self, basis=["CNOT", "RX", "RY", "RZ"]):
                 temp_resolved.append(gate)
             elif gate.name == "RZ":
                 temp_resolved.append(gate)
+            elif gate.name in ("X", "Y", "Z", "S", "T"):
+                temp_resolved.append(gate)
+            elif gate.name in ("CY", "CZ", "CS", "CT"):
+                temp_resolved.append(gate)
             elif gate.name == "SQRTNOT":
                 temp_resolved.append(Gate("GLOBALPHASE", None, None,
                                           arg_value=np.pi / 4,
@@ -889,7 +907,7 @@ def adjacent_gates(self):
 
         Returns
         -------
-        qc : QubitCircuit
+        qubit_circuit : QubitCircuit
             Return QubitCircuit of the gates for the qubit circuit with the
             resolved non-adjacent gates.
 
@@ -980,11 +998,36 @@ def propagators(self):
 
         for gate in self.gates:
             if gate.name == "RX":
-                self.U_list.append(rx(gate.arg_value, self.N, gate.targets[0]))
+                self.U_list.append(rx(
+                    gate.arg_value, self.N, gate.targets[0]))
             elif gate.name == "RY":
-                self.U_list.append(ry(gate.arg_value, self.N, gate.targets[0]))
+                self.U_list.append(ry(
+                    gate.arg_value, self.N, gate.targets[0]))
             elif gate.name == "RZ":
-                self.U_list.append(rz(gate.arg_value, self.N, gate.targets[0]))
+                self.U_list.append(rz(
+                    gate.arg_value, self.N, gate.targets[0]))
+            elif gate.name == "X":
+                self.U_list.append(x_gate(self.N, gate.targets[0]))
+            elif gate.name == "Y":
+                self.U_list.append(y_gate(self.N, gate.targets[0]))
+            elif gate.name == "CY":
+                self.U_list.append(cy_gate(
+                    self.N, gate.controls[0], gate.targets[0]))
+            elif gate.name == "Z":
+                self.U_list.append(z_gate(self.N, gate.targets[0]))
+            elif gate.name == "CZ":
+                self.U_list.append(cz_gate(
+                    self.N, gate.controls[0], gate.targets[0]))
+            elif gate.name == "T":
+                self.U_list.append(t_gate(self.N, gate.targets[0]))
+            elif gate.name == "CT":
+                self.U_list.append(ct_gate(
+                    self.N, gate.controls[0], gate.targets[0]))
+            elif gate.name == "S":
+                self.U_list.append(s_gate(self.N, gate.targets[0]))
+            elif gate.name == "CS":
+                self.U_list.append(cs_gate(
+                    self.N, gate.controls[0], gate.targets[0]))
             elif gate.name == "SQRTNOT":
                 self.U_list.append(sqrtnot(self.N, gate.targets[0]))
             elif gate.name == "SNOT":
@@ -1052,8 +1095,7 @@ def propagators(self):
                     raise ValueError(
                         "gate function takes at most one parameters.")
                 self.U_list.append(expand_operator(
-                        oper, N=self.N,
-                        targets=gate.targets, dims=self.dims))
+                    oper, N=self.N, targets=gate.targets, dims=self.dims))
 
             else:
                 raise NotImplementedError(
@@ -1076,9 +1118,9 @@ def latex_code(self):
                             col.append(r" \qswap \qwx ")
 
                         elif ((self.reverse_states and
-                                n == max(gate.targets)) or
-                                (not self.reverse_states and
-                                    n == min(gate.targets))):
+                               n == max(gate.targets)) or
+                              (not self.reverse_states and
+                               n == min(gate.targets))):
                             col.append(r" \multigate{%d}{%s} " %
                                        (len(gate.targets) - 1,
                                         _gate_label(gate.name,
@@ -1090,6 +1132,14 @@ def latex_code(self):
 
                     elif gate.name == "CNOT":
                         col.append(r" \targ ")
+                    elif gate.name == "CY":
+                        col.append(r" \targ ")
+                    elif gate.name == "CZ":
+                        col.append(r" \targ ")
+                    elif gate.name == "CS":
+                        col.append(r" \targ ")
+                    elif gate.name == "CT":
+                        col.append(r" \targ ")
                     elif gate.name == "TOFFOLI":
                         col.append(r" \targ ")
                     else:
@@ -1097,9 +1147,10 @@ def latex_code(self):
                                    _gate_label(gate.name, gate.arg_label))
 
                 elif gate.controls and n in gate.controls:
-                    m = (gate.targets[0] - n) * (-1 if self.reverse_states
-                                                 else 1)
-                    col.append(r" \ctrl{%d} " % m)
+                    control_tag = (-1 if
+                                   self.reverse_states
+                                   else 1) * (gate.targets[0] - n)
+                    col.append(r" \ctrl{%d} " % control_tag)
 
                 elif (not gate.controls and not gate.targets):
                     # global gate
@@ -1118,7 +1169,7 @@ def latex_code(self):
             col.append(r" \qw ")
             rows.append(col)
 
-        input_states = ["\lstick{\ket{" + x + "}}" if x is not None
+        input_states = [r"\lstick{\ket{" + x + "}}" if x is not None
                         else "" for x in self.input_states]
 
         code = ""
diff --git a/qutip/qip/operations/__init__.py b/qutip/qip/operations/__init__.py
--- a/qutip/qip/operations/__init__.py
+++ b/qutip/qip/operations/__init__.py
@@ -31,9 +31,9 @@
 #    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ###############################################################################
 from qutip.qip.operations.gates import (
-    x_gate, y_gate, z_gate, s_gate, t_gate,
-    rx, ry, rz, sqrtnot, snot, phasegate, qrot,
-    cphase, cnot,
+    rx, ry, rz, x_gate, y_gate, z_gate, s_gate, t_gate,
+    cy_gate, cz_gate, cs_gate, ct_gate, sqrtnot, snot,
+    phasegate, qrot, cphase, cnot,
     csign, berkeley, swapalpha, swap, iswap, sqrtswap,
     sqrtiswap, fredkin, molmer_sorensen,
     toffoli, rotation, controlled_gate,
diff --git a/qutip/qip/operations/gates.py b/qutip/qip/operations/gates.py
--- a/qutip/qip/operations/gates.py
+++ b/qutip/qip/operations/gates.py
@@ -44,9 +44,9 @@
 from qutip.states import fock_dm
 
 
-__all__ = ['x_gate', 'y_gate', 'z_gate', 's_gate', 't_gate',
-           'rx', 'ry', 'rz', 'sqrtnot', 'snot', 'phasegate', 'qrot',
-           'cphase', 'cnot',
+__all__ = ['rx', 'ry', 'rz', 'sqrtnot', 'snot', 'phasegate', 'qrot',
+           'x_gate', 'y_gate', 'z_gate', 'cy_gate', 'cz_gate', 's_gate',
+           't_gate', 'cs_gate', 'ct_gate', 'cphase', 'cnot',
            'csign', 'berkeley', 'swapalpha', 'swap', 'iswap', 'sqrtswap',
            'sqrtiswap', 'fredkin', 'molmer_sorensen',
            'toffoli', 'rotation', 'controlled_gate',
@@ -71,8 +71,7 @@ def x_gate(N=None, target=0):
     """
     if N is not None:
         return gate_expand_1toN(x_gate(), N, target)
-    else:
-        return sigmax()
+    return sigmax()
 
 
 def y_gate(N=None, target=0):
@@ -87,8 +86,28 @@ def y_gate(N=None, target=0):
     """
     if N is not None:
         return gate_expand_1toN(y_gate(), N, target)
-    else:
-        return sigmay()
+    return sigmay()
+
+
+def cy_gate(N=None, control=0, target=1):
+    """Controlled Y gate.
+
+    Returns
+    -------
+    result : :class:`qutip.Qobj`
+        Quantum object for operator describing the rotation.
+
+    """
+    if (control == 1 and target == 0) and N is None:
+        N = 2
+
+    if N is not None:
+        return gate_expand_2toN(cy_gate(), N, control, target)
+    return Qobj([[1, 0, 0, 0],
+                 [0, 1, 0, 0],
+                 [0, 0, 0, -1j],
+                 [0, 0, 1j, 0]],
+                dims=[[2, 2], [2, 2]])
 
 
 def z_gate(N=None, target=0):
@@ -103,8 +122,28 @@ def z_gate(N=None, target=0):
     """
     if N is not None:
         return gate_expand_1toN(z_gate(), N, target)
-    else:
-        return sigmaz()
+    return sigmaz()
+
+
+def cz_gate(N=None, control=0, target=1):
+    """Controlled Z gate.
+
+    Returns
+    -------
+    result : :class:`qutip.Qobj`
+        Quantum object for operator describing the rotation.
+
+    """
+    if (control == 1 and target == 0) and N is None:
+        N = 2
+
+    if N is not None:
+        return gate_expand_2toN(cz_gate(), N, control, target)
+    return Qobj([[1, 0, 0, 0],
+                 [0, 1, 0, 0],
+                 [0, 0, 1, 0],
+                 [0, 0, 0, -1j]],
+                dims=[[2, 2], [2, 2]])
 
 
 def s_gate(N=None, target=0):
@@ -119,9 +158,29 @@ def s_gate(N=None, target=0):
     """
     if N is not None:
         return gate_expand_1toN(s_gate(), N, target)
-    else:
-        return Qobj([[1, 0],
-                    [0, 1j]])
+    return Qobj([[1, 0],
+                 [0, 1j]])
+
+
+def cs_gate(N=None, control=0, target=1):
+    """Controlled S gate.
+
+    Returns
+    -------
+    result : :class:`qutip.Qobj`
+        Quantum object for operator describing the rotation.
+
+    """
+    if (control == 1 and target == 0) and N is None:
+        N = 2
+
+    if N is not None:
+        return gate_expand_2toN(cs_gate(), N, control, target)
+    return Qobj([[1, 0, 0, 0],
+                 [0, 1, 0, 0],
+                 [0, 0, 1, 0],
+                 [0, 0, 0, 1j]],
+                dims=[[2, 2], [2, 2]])
 
 
 def t_gate(N=None, target=0):
@@ -135,9 +194,29 @@ def t_gate(N=None, target=0):
     """
     if N is not None:
         return gate_expand_1toN(t_gate(), N, target)
-    else:
-        return Qobj([[1, 0],
-                    [0, np.exp(1j*np.pi/4)]])
+    return Qobj([[1, 0],
+                 [0, np.exp(1j*np.pi/4)]])
+
+
+def ct_gate(N=None, control=0, target=1):
+    """Controlled T gate.
+
+    Returns
+    -------
+    result : :class:`qutip.Qobj`
+        Quantum object for operator describing the rotation.
+
+    """
+    if (control == 1 and target == 0) and N is None:
+        N = 2
+
+    if N is not None:
+        return gate_expand_2toN(ct_gate(), N, control, target)
+    return Qobj([[1, 0, 0, 0],
+                 [0, 1, 0, 0],
+                 [0, 0, 1, 0],
+                 [0, 0, 0, np.exp(1j * np.pi / 4)]],
+                dims=[[2, 2], [2, 2]])
 
 
 def rx(phi, N=None, target=0):
@@ -151,9 +230,8 @@ def rx(phi, N=None, target=0):
     """
     if N is not None:
         return gate_expand_1toN(rx(phi), N, target)
-    else:
-        return Qobj([[np.cos(phi / 2), -1j * np.sin(phi / 2)],
-                     [-1j * np.sin(phi / 2), np.cos(phi / 2)]])
+    return Qobj([[np.cos(phi / 2), -1j * np.sin(phi / 2)],
+                 [-1j * np.sin(phi / 2), np.cos(phi / 2)]])
 
 
 def ry(phi, N=None, target=0):
@@ -167,9 +245,8 @@ def ry(phi, N=None, target=0):
     """
     if N is not None:
         return gate_expand_1toN(ry(phi), N, target)
-    else:
-        return Qobj([[np.cos(phi / 2), -np.sin(phi / 2)],
-                     [np.sin(phi / 2), np.cos(phi / 2)]])
+    return Qobj([[np.cos(phi / 2), -np.sin(phi / 2)],
+                 [np.sin(phi / 2), np.cos(phi / 2)]])
 
 
 def rz(phi, N=None, target=0):
@@ -183,9 +260,8 @@ def rz(phi, N=None, target=0):
     """
     if N is not None:
         return gate_expand_1toN(rz(phi), N, target)
-    else:
-        return Qobj([[np.exp(-1j * phi / 2), 0],
-                     [0, np.exp(1j * phi / 2)]])
+    return Qobj([[np.exp(-1j * phi / 2), 0],
+                 [0, np.exp(1j * phi / 2)]])
 
 
 def sqrtnot(N=None, target=0):
@@ -199,9 +275,8 @@ def sqrtnot(N=None, target=0):
     """
     if N is not None:
         return gate_expand_1toN(sqrtnot(), N, target)
-    else:
-        return Qobj([[0.5 + 0.5j, 0.5 - 0.5j],
-                     [0.5 - 0.5j, 0.5 + 0.5j]])
+    return Qobj([[0.5 + 0.5j, 0.5 - 0.5j],
+                 [0.5 - 0.5j, 0.5 + 0.5j]])
 
 
 def snot(N=None, target=0):
@@ -224,9 +299,8 @@ def snot(N=None, target=0):
     """
     if N is not None:
         return gate_expand_1toN(snot(), N, target)
-    else:
-        return 1 / np.sqrt(2.0) * Qobj([[1, 1],
-                                        [1, -1]])
+    return 1 / np.sqrt(2.0) * Qobj([[1, 1],
+                                    [1, -1]])
 
 
 def phasegate(theta, N=None, target=0):
@@ -255,10 +329,9 @@ def phasegate(theta, N=None, target=0):
     """
     if N is not None:
         return gate_expand_1toN(phasegate(theta), N, target)
-    else:
-        return Qobj([[1, 0],
-                     [0, np.exp(1.0j * theta)]],
-                    dims=[[2], [2]])
+    return Qobj([[1, 0],
+                 [0, np.exp(1.0j * theta)]],
+                dims=[[2], [2]])
 
 
 def qrot(theta, phi, N=None, target=0):
@@ -284,12 +357,11 @@ def qrot(theta, phi, N=None, target=0):
     """
     if N is not None:
         return expand_operator(qrot(theta, phi), N=N, targets=target)
-    else:
-        return Qobj(
-            [
-                [np.cos(theta/2.), -1.j*np.exp(-1.j*phi)*np.sin(theta/2.)],
-                [-1.j*np.exp(1.j*phi)*np.sin(theta/2.), np.cos(theta/2.)]
-            ])
+    return Qobj(
+        [
+            [np.cos(theta/2.), -1.j*np.exp(-1.j*phi)*np.sin(theta/2.)],
+            [-1.j*np.exp(1.j*phi)*np.sin(theta/2.), np.cos(theta/2.)]
+        ])
 
 
 #
@@ -364,12 +436,11 @@ def cnot(N=None, control=0, target=1):
 
     if N is not None:
         return gate_expand_2toN(cnot(), N, control, target)
-    else:
-        return Qobj([[1, 0, 0, 0],
-                     [0, 1, 0, 0],
-                     [0, 0, 0, 1],
-                     [0, 0, 1, 0]],
-                    dims=[[2, 2], [2, 2]])
+    return Qobj([[1, 0, 0, 0],
+                 [0, 1, 0, 0],
+                 [0, 0, 0, 1],
+                 [0, 0, 1, 0]],
+                dims=[[2, 2], [2, 2]])
 
 
 def csign(N=None, control=0, target=1):
@@ -398,12 +469,11 @@ def csign(N=None, control=0, target=1):
 
     if N is not None:
         return gate_expand_2toN(csign(), N, control, target)
-    else:
-        return Qobj([[1, 0, 0, 0],
-                     [0, 1, 0, 0],
-                     [0, 0, 1, 0],
-                     [0, 0, 0, -1]],
-                    dims=[[2, 2], [2, 2]])
+    return Qobj([[1, 0, 0, 0],
+                 [0, 1, 0, 0],
+                 [0, 0, 1, 0],
+                 [0, 0, 0, -1]],
+                dims=[[2, 2], [2, 2]])
 
 
 def berkeley(N=None, targets=[0, 1]):
@@ -432,14 +502,13 @@ def berkeley(N=None, targets=[0, 1]):
 
     if N is not None:
         return gate_expand_2toN(cnot(), N, targets=targets)
-    else:
-        return Qobj([[np.cos(np.pi / 8), 0, 0, 1.0j * np.sin(np.pi / 8)],
-                     [0, np.cos(3 * np.pi / 8), 1.0j *
-                      np.sin(3 * np.pi / 8), 0],
-                     [0, 1.0j * np.sin(3 * np.pi / 8),
-                      np.cos(3 * np.pi / 8), 0],
-                     [1.0j * np.sin(np.pi / 8), 0, 0, np.cos(np.pi / 8)]],
-                    dims=[[2, 2], [2, 2]])
+    return Qobj([[np.cos(np.pi / 8), 0, 0, 1.0j * np.sin(np.pi / 8)],
+                 [0, np.cos(3 * np.pi / 8), 1.0j *
+                  np.sin(3 * np.pi / 8), 0],
+                 [0, 1.0j * np.sin(3 * np.pi / 8),
+                  np.cos(3 * np.pi / 8), 0],
+                 [1.0j * np.sin(np.pi / 8), 0, 0, np.cos(np.pi / 8)]],
+                dims=[[2, 2], [2, 2]])
 
 
 def swapalpha(alpha, N=None, targets=[0, 1]):
@@ -468,14 +537,13 @@ def swapalpha(alpha, N=None, targets=[0, 1]):
 
     if N is not None:
         return gate_expand_2toN(cnot(), N, targets=targets)
-    else:
-        return Qobj([[1, 0, 0, 0],
-                     [0, 0.5 * (1 + np.exp(1.0j * np.pi * alpha)),
-                      0.5 * (1 - np.exp(1.0j * np.pi * alpha)), 0],
-                     [0, 0.5 * (1 - np.exp(1.0j * np.pi * alpha)),
-                      0.5 * (1 + np.exp(1.0j * np.pi * alpha)), 0],
-                     [0, 0, 0, 1]],
-                    dims=[[2, 2], [2, 2]])
+    return Qobj([[1, 0, 0, 0],
+                 [0, 0.5 * (1 + np.exp(1.0j * np.pi * alpha)),
+                  0.5 * (1 - np.exp(1.0j * np.pi * alpha)), 0],
+                 [0, 0.5 * (1 - np.exp(1.0j * np.pi * alpha)),
+                  0.5 * (1 + np.exp(1.0j * np.pi * alpha)), 0],
+                 [0, 0, 0, 1]],
+                dims=[[2, 2], [2, 2]])
 
 
 def swap(N=None, targets=[0, 1]):
@@ -503,13 +571,11 @@ def swap(N=None, targets=[0, 1]):
 
     if N is not None:
         return gate_expand_2toN(swap(), N, targets=targets)
-
-    else:
-        return Qobj([[1, 0, 0, 0],
-                     [0, 0, 1, 0],
-                     [0, 1, 0, 0],
-                     [0, 0, 0, 1]],
-                    dims=[[2, 2], [2, 2]])
+    return Qobj([[1, 0, 0, 0],
+                 [0, 0, 1, 0],
+                 [0, 1, 0, 0],
+                 [0, 0, 0, 1]],
+                dims=[[2, 2], [2, 2]])
 
 
 def iswap(N=None, targets=[0, 1]):
@@ -536,13 +602,11 @@ def iswap(N=None, targets=[0, 1]):
 
     if N is not None:
         return gate_expand_2toN(iswap(), N, targets=targets)
-
-    else:
-        return Qobj([[1, 0, 0, 0],
-                     [0, 0, 1j, 0],
-                     [0, 1j, 0, 0],
-                     [0, 0, 0, 1]],
-                    dims=[[2, 2], [2, 2]])
+    return Qobj([[1, 0, 0, 0],
+                 [0, 0, 1j, 0],
+                 [0, 1j, 0, 0],
+                 [0, 0, 0, 1]],
+                dims=[[2, 2], [2, 2]])
 
 
 def sqrtswap(N=None, targets=[0, 1]):
@@ -559,12 +623,11 @@ def sqrtswap(N=None, targets=[0, 1]):
 
     if N is not None:
         return gate_expand_2toN(sqrtswap(), N, targets=targets)
-    else:
-        return Qobj(np.array([[1, 0, 0, 0],
-                              [0, 0.5 + 0.5j, 0.5 - 0.5j, 0],
-                              [0, 0.5 - 0.5j, 0.5 + 0.5j, 0],
-                              [0, 0, 0, 1]]),
-                    dims=[[2, 2], [2, 2]])
+    return Qobj(np.array([[1, 0, 0, 0],
+                          [0, 0.5 + 0.5j, 0.5 - 0.5j, 0],
+                          [0, 0.5 - 0.5j, 0.5 + 0.5j, 0],
+                          [0, 0, 0, 1]]),
+                dims=[[2, 2], [2, 2]])
 
 
 def sqrtiswap(N=None, targets=[0, 1]):
@@ -596,11 +659,10 @@ def sqrtiswap(N=None, targets=[0, 1]):
 
     if N is not None:
         return gate_expand_2toN(sqrtiswap(), N, targets=targets)
-    else:
-        return Qobj(np.array([[1, 0, 0, 0],
-                              [0, 1 / np.sqrt(2), 1j / np.sqrt(2), 0],
-                              [0, 1j / np.sqrt(2), 1 / np.sqrt(2), 0],
-                              [0, 0, 0, 1]]), dims=[[2, 2], [2, 2]])
+    return Qobj(np.array([[1, 0, 0, 0],
+                          [0, 1 / np.sqrt(2), 1j / np.sqrt(2), 0],
+                          [0, 1j / np.sqrt(2), 1 / np.sqrt(2), 0],
+                          [0, 0, 0, 1]]), dims=[[2, 2], [2, 2]])
 
 
 def molmer_sorensen(theta, N=None, targets=[0, 1]):
@@ -626,15 +688,14 @@ def molmer_sorensen(theta, N=None, targets=[0, 1]):
 
     if N is not None:
         return expand_operator(molmer_sorensen(theta), N, targets=targets)
-    else:
-        return Qobj(
-            [
-                [np.cos(theta/2.), 0, 0, -1.j*np.sin(theta/2.)],
-                [0, np.cos(theta/2.), -1.j*np.sin(theta/2.), 0],
-                [0, -1.j*np.sin(theta/2.), np.cos(theta/2.), 0],
-                [-1.j*np.sin(theta/2.), 0, 0, np.cos(theta/2.)]
-            ],
-            dims=[[2, 2], [2, 2]])
+    return Qobj(
+        [
+            [np.cos(theta/2.), 0, 0, -1.j*np.sin(theta/2.)],
+            [0, np.cos(theta/2.), -1.j*np.sin(theta/2.), 0],
+            [0, -1.j*np.sin(theta/2.), np.cos(theta/2.), 0],
+            [-1.j*np.sin(theta/2.), 0, 0, np.cos(theta/2.)]
+        ],
+        dims=[[2, 2], [2, 2]])
 
 
 #
@@ -671,17 +732,15 @@ def fredkin(N=None, control=0, targets=[1, 2]):
     if N is not None:
         return gate_expand_3toN(fredkin(), N,
                                 [control, targets[0]], targets[1])
-
-    else:
-        return Qobj([[1, 0, 0, 0, 0, 0, 0, 0],
-                     [0, 1, 0, 0, 0, 0, 0, 0],
-                     [0, 0, 1, 0, 0, 0, 0, 0],
-                     [0, 0, 0, 1, 0, 0, 0, 0],
-                     [0, 0, 0, 0, 1, 0, 0, 0],
-                     [0, 0, 0, 0, 0, 0, 1, 0],
-                     [0, 0, 0, 0, 0, 1, 0, 0],
-                     [0, 0, 0, 0, 0, 0, 0, 1]],
-                    dims=[[2, 2, 2], [2, 2, 2]])
+    return Qobj([[1, 0, 0, 0, 0, 0, 0, 0],
+                 [0, 1, 0, 0, 0, 0, 0, 0],
+                 [0, 0, 1, 0, 0, 0, 0, 0],
+                 [0, 0, 0, 1, 0, 0, 0, 0],
+                 [0, 0, 0, 0, 1, 0, 0, 0],
+                 [0, 0, 0, 0, 0, 0, 1, 0],
+                 [0, 0, 0, 0, 0, 1, 0, 0],
+                 [0, 0, 0, 0, 0, 0, 0, 1]],
+                dims=[[2, 2, 2], [2, 2, 2]])
 
 
 def toffoli(N=None, controls=[0, 1], target=2):
@@ -696,7 +755,7 @@ def toffoli(N=None, controls=[0, 1], target=2):
     --------
     >>> toffoli()
     Quantum object: dims = [[2, 2, 2], [2, 2, 2]], \
-shape = [8, 8], type = oper, isHerm = True
+                    shape = [8, 8], type = oper, isHerm = True
     Qobj data =
         [[ 1.+0.j  0.+0.j  0.+0.j  0.+0.j  0.+0.j  0.+0.j  0.+0.j  0.+0.j]
          [ 0.+0.j  1.+0.j  0.+0.j  0.+0.j  0.+0.j  0.+0.j  0.+0.j  0.+0.j]
@@ -714,17 +773,15 @@ def toffoli(N=None, controls=[0, 1], target=2):
 
     if N is not None:
         return gate_expand_3toN(toffoli(), N, controls, target)
-
-    else:
-        return Qobj([[1, 0, 0, 0, 0, 0, 0, 0],
-                     [0, 1, 0, 0, 0, 0, 0, 0],
-                     [0, 0, 1, 0, 0, 0, 0, 0],
-                     [0, 0, 0, 1, 0, 0, 0, 0],
-                     [0, 0, 0, 0, 1, 0, 0, 0],
-                     [0, 0, 0, 0, 0, 1, 0, 0],
-                     [0, 0, 0, 0, 0, 0, 0, 1],
-                     [0, 0, 0, 0, 0, 0, 1, 0]],
-                    dims=[[2, 2, 2], [2, 2, 2]])
+    return Qobj([[1, 0, 0, 0, 0, 0, 0, 0],
+                 [0, 1, 0, 0, 0, 0, 0, 0],
+                 [0, 0, 1, 0, 0, 0, 0, 0],
+                 [0, 0, 0, 1, 0, 0, 0, 0],
+                 [0, 0, 0, 0, 1, 0, 0, 0],
+                 [0, 0, 0, 0, 0, 1, 0, 0],
+                 [0, 0, 0, 0, 0, 0, 0, 1],
+                 [0, 0, 0, 0, 0, 0, 1, 0]],
+                dims=[[2, 2, 2], [2, 2, 2]])
 
 
 #
@@ -742,8 +799,7 @@ def rotation(op, phi, N=None, target=0):
     """
     if N is not None:
         return gate_expand_1toN(rotation(op, phi), N, target)
-    else:
-        return (-1j * op * phi / 2).expm()
+    return (-1j * op * phi / 2).expm()
 
 
 def controlled_gate(U, N=2, control=0, target=1, control_value=1):
@@ -778,9 +834,8 @@ def controlled_gate(U, N=2, control=0, target=1, control_value=1):
     if [N, control, target] == [2, 0, 1]:
         return (tensor(fock_dm(2, control_value), U) +
                 tensor(fock_dm(2, 1 - control_value), identity(2)))
-    else:
-        U2 = controlled_gate(U, control_value=control_value)
-        return gate_expand_2toN(U2, N=N, control=control, target=target)
+    U2 = controlled_gate(U, control_value=control_value)
+    return gate_expand_2toN(U2, N=N, control=control, target=target)
 
 
 def globalphase(theta, N=1):
@@ -924,7 +979,8 @@ def qubit_clifford_group(N=None, target=0):
     E = H * (S ** 3) * w ** 3
 
     for op in map(partial(reduce, mul), product(_powers(E, 3),
-                  _powers(X, 2), _powers(S, 4))):
+                                                _powers(X, 2),
+                                                _powers(S, 4))):
 
         # partial(reduce, mul) returns a function that takes products
         # of its argument, by analogy to sum. Note that by analogy,
@@ -1072,8 +1128,8 @@ def gate_expand_3toN(U, N, controls=[0, 1], target=2):
                          " Must be integer < integer N")
 
     if (controls[0] == target or
-        controls[1] == target or
-        controls[0] == controls[1]):
+            controls[1] == target or
+            controls[0] == controls[1]):
 
         raise ValueError("controls[0], controls[1], and target"
                          " cannot be equal")


Test patch:
diff --git a/qutip/tests/test_gates.py b/qutip/tests/test_gates.py
--- a/qutip/tests/test_gates.py
+++ b/qutip/tests/test_gates.py
@@ -33,14 +33,15 @@
 
 import itertools
 import numpy as np
-from numpy.testing import (assert_, assert_allclose, assert_array_equal, 
+from numpy.testing import (assert_, assert_allclose, assert_array_equal,
                            run_module_suite)
 from qutip.states import basis, ket2dm
 from qutip.operators import identity, qeye, sigmax, sigmay, sigmaz
-from qutip.qip.operations.gates import (rx, ry, rz, phasegate, qrot, cnot, swap, iswap,
-                       sqrtswap, molmer_sorensen,
-                       toffoli, fredkin, gate_expand_3toN, 
-                       qubit_clifford_group, expand_operator)
+from qutip.qip.operations.gates import (
+    rx, ry, rz, x_gate, y_gate, z_gate, s_gate, t_gate, cy_gate, cz_gate,
+    cs_gate, ct_gate, phasegate, qrot, cnot, swap, iswap, sqrtswap,
+    molmer_sorensen, toffoli, fredkin, gate_expand_3toN, qubit_clifford_group,
+    expand_operator)
 from qutip.random_objects import rand_ket, rand_herm, rand_unitary, rand_dm
 from qutip.tensor import tensor
 from qutip.qobj import Qobj
@@ -70,6 +71,71 @@ def testSwapGate(self):
         psi_res = swap() * swap() * psi_in
         assert_((psi_in - psi_res).norm() < 1e-12)
 
+    def test_one_qubit_gates(self):
+         """
+         gates: X,Y,Z,S,T gates
+         """
+         N = 7
+         for g in [x_gate, y_gate, z_gate, s_gate, t_gate]:
+
+             a, b = np.random.rand(), np.random.rand()
+             psi1 = (a * basis(2, 0) + b * basis(2, 1)).unit()
+             psi2 = g() * psi1
+
+             psi_rand_list = [rand_ket(2) for k in range(N)]
+
+             for m in range(N):
+
+                 psi_in = tensor([psi1 if k == m else psi_rand_list[k]
+                                  for k in range(N)])
+                 psi_out = tensor([psi2 if k == m else psi_rand_list[k]
+                                   for k in range(N)])
+
+                 G = g(N, m)
+                 psi_res = G * psi_in
+
+                 assert_((psi_out - psi_res).norm() < 1e-12)
+
+    def test_controlled_one_qubit_gates(self):
+        """
+        gates: CY,CZ,CS, CT gates
+        """
+        a, b = np.random.rand(), np.random.rand()
+        k1 = (a * basis(2, 0) + b * basis(2, 1)).unit()
+
+        c, d = np.random.rand(), np.random.rand()
+        k2 = (c * basis(2, 0) + d * basis(2, 1)).unit()
+
+        psi_ref_in = tensor(k1, k2)
+
+        N = 6
+        psi_rand_list = [rand_ket(2) for k in range(N)]
+
+        for g in [cy_gate, cz_gate, cs_gate, ct_gate]:
+
+            psi_ref_out = g() * psi_ref_in
+            rho_ref_out = ket2dm(psi_ref_out)
+
+            for m in range(N):
+                for n in set(range(N)) - {m}:
+                    psi_list = [psi_rand_list[k] for k in range(N)]
+                    psi_list[m] = k1
+                    psi_list[n] = k2
+                    psi_in = tensor(psi_list)
+
+                    G = g(N, m, n)
+
+                    psi_out = G * psi_in
+
+                    o1 = psi_out.overlap(psi_in)
+                    o2 = psi_ref_out.overlap(psi_ref_in)
+                    assert_(abs(o1 - o2) < 1e-12)
+
+                    p = [0, 1] if m < n else [1, 0]
+                    rho_out = psi_out.ptrace([m, n]).permute(p)
+
+                    assert_((rho_ref_out - rho_out).norm() < 1e-12)
+
     def test_clifford_group_len(self):
         assert_(len(list(qubit_clifford_group())) == 24)
 
@@ -218,19 +284,19 @@ def testExpandGate3toN_permutation(self):
 
             U = toffoli(N=3, controls=controls, target=target)
 
-            ops = [basis(2, 0).dag(),  basis(2, 0).dag(), identity(2)]
+            ops = [basis(2, 0).dag(), basis(2, 0).dag(), identity(2)]
             P = tensor(ops[p[0]], ops[p[1]], ops[p[2]])
             assert_(P * U * P.dag() == identity(2))
 
-            ops = [basis(2, 1).dag(),  basis(2, 0).dag(), identity(2)]
+            ops = [basis(2, 1).dag(), basis(2, 0).dag(), identity(2)]
             P = tensor(ops[p[0]], ops[p[1]], ops[p[2]])
             assert_(P * U * P.dag() == identity(2))
 
-            ops = [basis(2, 0).dag(),  basis(2, 1).dag(), identity(2)]
+            ops = [basis(2, 0).dag(), basis(2, 1).dag(), identity(2)]
             P = tensor(ops[p[0]], ops[p[1]], ops[p[2]])
             assert_(P * U * P.dag() == identity(2))
 
-            ops = [basis(2, 1).dag(),  basis(2, 1).dag(), identity(2)]
+            ops = [basis(2, 1).dag(), basis(2, 1).dag(), identity(2)]
             P = tensor(ops[p[0]], ops[p[1]], ops[p[2]])
             assert_(P * U * P.dag() == sigmax())
 
@@ -256,8 +322,7 @@ def testExpandGate3toN(self):
         def _rand_3qubit_gate(N=None, controls=None, k=None):
             if N is None:
                 return _rand_gate_U
-            else:
-                return gate_expand_3toN(_rand_gate_U, N, controls, k)
+            return gate_expand_3toN(_rand_gate_U, N, controls, k)
 
         for g in [fredkin, toffoli, _rand_3qubit_gate]:
 
@@ -294,8 +359,8 @@ def test_expand_operator(self):
         # oper size is N, no expansion
         oper = tensor(sigmax(), sigmay())
         assert_allclose(expand_operator(oper=oper, targets=[0, 1], N=2), oper)
-        assert_allclose(expand_operator(oper=oper, targets=[1, 0], N=2), 
-                            tensor(sigmay(), sigmax()))
+        assert_allclose(expand_operator(oper=oper, targets=[1, 0], N=2),
+                        tensor(sigmay(), sigmax()))
 
         # random single qubit gate test, integer as target
         r = rand_unitary(2)
@@ -314,16 +379,17 @@ def test_expand_operator(self):
             [r2, identity(2)]).permute([0, 2, 1]))
 
         # cnot expantion, qubit 2 control qubit 0
-        assert_allclose(expand_operator(cnot(), 3, [2, 0]), Qobj([
-            [1., 0., 0., 0., 0., 0., 0., 0.],
-            [0., 0., 0., 0., 0., 1., 0., 0.],
-            [0., 0., 1., 0., 0., 0., 0., 0.],
-            [0., 0., 0., 0., 0., 0., 0., 1.],
-            [0., 0., 0., 0., 1., 0., 0., 0.],
-            [0., 1., 0., 0., 0., 0., 0., 0.],
-            [0., 0., 0., 0., 0., 0., 1., 0.],
-            [0., 0., 0., 1., 0., 0., 0., 0.]],
-            dims=[[2, 2, 2], [2, 2, 2]]))
+        assert_allclose(expand_operator(cnot(), 3, [2, 0]),
+                         Qobj([
+                             [1., 0., 0., 0., 0., 0., 0., 0.],
+                             [0., 0., 0., 0., 0., 1., 0., 0.],
+                             [0., 0., 1., 0., 0., 0., 0., 0.],
+                             [0., 0., 0., 0., 0., 0., 0., 1.],
+                             [0., 0., 0., 0., 1., 0., 0., 0.],
+                             [0., 1., 0., 0., 0., 0., 0., 0.],
+                             [0., 0., 0., 0., 0., 0., 1., 0.],
+                             [0., 0., 0., 1., 0., 0., 0., 0.]],
+                              dims=[[2, 2, 2], [2, 2, 2]]))
 
         # test expansion with cyclic permutation
         result = expand_operator(
@@ -357,18 +423,18 @@ def test_molmer_sorensen(self):
         assert_allclose(
             molmer_sorensen(np.pi, targets=[0, 1]),
             Qobj(-1j*np.array(
-                 [[0, 0, 0, 1],
-                  [0, 0, 1, 0],
-                  [0, 1, 0, 0],
-                  [1, 0, 0, 0]]), dims=[[2, 2], [2, 2]]),
+                [[0, 0, 0, 1],
+                 [0, 0, 1, 0],
+                 [0, 1, 0, 0],
+                 [1, 0, 0, 0]]), dims=[[2, 2], [2, 2]]),
             atol=1e-15)
         assert_allclose(
             molmer_sorensen(2*np.pi, targets=[0, 1]),
             Qobj(-np.array(
-                 [[1, 0, 0, 0],
-                  [0, 1, 0, 0],
-                  [0, 0, 1, 0],
-                  [0, 0, 0, 1]]), dims=[[2, 2], [2, 2]]),
+                [[1, 0, 0, 0],
+                 [0, 1, 0, 0],
+                 [0, 0, 1, 0],
+                 [0, 0, 0, 1]]), dims=[[2, 2], [2, 2]]),
             atol=1e-15)
         assert_allclose(
             molmer_sorensen(np.pi/2, N=4, targets=[1, 2]),
diff --git a/qutip/tests/test_qubitcircuit.py b/qutip/tests/test_qubitcircuit.py
--- a/qutip/tests/test_qubitcircuit.py
+++ b/qutip/tests/test_qubitcircuit.py
@@ -32,9 +32,9 @@
 ###############################################################################
 
 import numpy as np
-from numpy.testing import assert_, assert_allclose, run_module_suite
+from numpy.testing import assert_raises, assert_, assert_allclose, run_module_suite
 from qutip.qip.operations.gates import (
-    gate_sequence_product, rx, expand_operator)
+    gate_sequence_product, rx)
 from qutip.operators import identity
 from qutip.qip.circuit import QubitCircuit, Gate
 from qutip.tensor import tensor
@@ -163,13 +163,13 @@ def test_add_gate(self):
         """
         qc = QubitCircuit(6)
         qc.add_gate("CNOT", targets=[1], controls=[0])
-        test_gate = Gate("RZ", targets=[1], arg_value = 1.570796,
+        test_gate = Gate("RZ", targets=[1], arg_value=1.570796,
                          arg_label="P")
         qc.add_gate(test_gate)
         qc.add_gate("TOFFOLI", controls=[0, 1], targets=[2])
         qc.add_gate("SNOT", targets=[3])
-        qc.add_gate(test_gate, index = [3])
-        qc.add_1q_gate("RY", start = 4, end = 5, arg_value = 1.570796)
+        qc.add_gate(test_gate, index=[3])
+        qc.add_1q_gate("RY", start=4, end=5, arg_value=1.570796)
 
         # Test explicit gate addition
         assert_(qc.gates[0].name == "CNOT")
@@ -203,17 +203,17 @@ def test_add_state(self):
         qc.add_state("-", targets=[1])
 
         assert_(qc.input_states[0] == "0")
-        assert_(qc.input_states[2] == None)
+        assert_(qc.input_states[2] is None)
         assert_(qc.output_states[1] == "+")
 
         qc1 = QubitCircuit(10)
 
         qc1.add_state("0", targets=[2, 3, 5, 6])
-        qc1.add_state("+", targets=[1,4,9])
-        qc1.add_state("A", targets=[1,4,9], state_type="output")
-        qc1.add_state("A", targets=[1,4,9], state_type="output")
+        qc1.add_state("+", targets=[1, 4, 9])
+        qc1.add_state("A", targets=[1, 4, 9], state_type="output")
+        qc1.add_state("A", targets=[1, 4, 9], state_type="output")
         qc1.add_state("beta", targets=[0], state_type="output")
-        assert_(qc1.input_states[0] == None)
+        assert_(qc1.input_states[0] is None)
 
         assert_(qc1.input_states[2] == "0")
         assert_(qc1.input_states[3] == "0")
@@ -221,13 +221,70 @@ def test_add_state(self):
         assert_(qc1.input_states[1] == "+")
         assert_(qc1.input_states[4] == "+")
 
-        assert_(qc1.output_states[2] == None)
+        assert_(qc1.output_states[2] is None)
         assert_(qc1.output_states[1] == "A")
         assert_(qc1.output_states[4] == "A")
         assert_(qc1.output_states[9] == "A")
 
         assert_(qc1.output_states[0] == "beta")
 
+    def test_exceptions(self):
+        """
+        Text exceptions are thrown correctly for inadequate inputs
+        """
+        qc = QubitCircuit(2)
+        for gate in ["X", "Y", "Z", "S", "T"]:
+            assert_raises(ValueError, qc.add_gate, gate,
+                          targets=[1], controls=[0])
+
+        for gate in ["CY", "CZ", "CS", "CT"]:
+            assert_raises(ValueError, qc.add_gate, gate,
+                          targets=[1])
+            assert_raises(ValueError, qc.add_gate, gate)
+
+
+    def test_single_qubit_gates(self):
+        """
+        Text single qubit gates are added correctly
+        """
+        qc = QubitCircuit(3)
+
+        qc.add_gate("X", targets=[0])
+        qc.add_gate("CY", targets=[1], controls=[0])
+        qc.add_gate("Y", targets=[2])
+        qc.add_gate("CS", targets=[0], controls=[1])
+        qc.add_gate("Z", targets=[1])
+        qc.add_gate("CT", targets=[2], controls=[2])
+        qc.add_gate("CZ", targets=[0], controls=[0])
+        qc.add_gate("S", targets=[1])
+        qc.add_gate("T", targets=[2])
+
+        assert_(qc.gates[8].name == "T")
+        assert_(qc.gates[7].name == "S")
+        assert_(qc.gates[6].name == "CZ")
+        assert_(qc.gates[5].name == "CT")
+        assert_(qc.gates[4].name == "Z")
+        assert_(qc.gates[3].name == "CS")
+        assert_(qc.gates[2].name == "Y")
+        assert_(qc.gates[1].name == "CY")
+        assert_(qc.gates[0].name == "X")
+
+        assert_(qc.gates[8].targets == [2])
+        assert_(qc.gates[7].targets == [1])
+        assert_(qc.gates[6].targets == [0])
+        assert_(qc.gates[5].targets == [2])
+        assert_(qc.gates[4].targets == [1])
+        assert_(qc.gates[3].targets == [0])
+        assert_(qc.gates[2].targets == [2])
+        assert_(qc.gates[1].targets == [1])
+        assert_(qc.gates[0].targets == [0])
+
+        assert_(qc.gates[6].controls == [0])
+        assert_(qc.gates[5].controls == [2])
+        assert_(qc.gates[3].controls == [1])
+        assert_(qc.gates[1].controls == [0])
+
+
     def test_reverse(self):
         """
         Reverse a quantum circuit
@@ -251,7 +308,7 @@ def test_reverse(self):
         assert_(qc.gates[0].name == "RX")
 
         assert_(qc.input_states[0] == "0")
-        assert_(qc.input_states[2] == None)
+        assert_(qc.input_states[2] is None)
         assert_(qc.output_states[1] == "+")
 
 
@@ -265,20 +322,20 @@ def customer_gate1(arg_values):
             mat[2:4, 2:4] = rx(arg_values)
             return Qobj(mat, dims=[[2, 2], [2, 2]])
 
-        def customer_gate2(arg_values):
-            mat = np.array([[1.,   0],
+        def customer_gate2():
+            mat = np.array([[1., 0],
                             [0., 1.j]])
             return Qobj(mat, dims=[[2], [2]])
 
         qc = QubitCircuit(3)
         qc.user_gates = {"CTRLRX": customer_gate1,
-                         "T": customer_gate2}
+                         "T1": customer_gate2}
         qc.add_gate("CTRLRX", targets=[1, 2], arg_value=np.pi/2)
-        qc.add_gate("T", targets=[1])
+        qc.add_gate("T1", targets=[1])
         props = qc.propagators()
         result1 = tensor(identity(2), customer_gate1(np.pi/2))
         assert_allclose(props[0], result1)
-        result2 = tensor(identity(2), customer_gate2(None), identity(2))
+        result2 = tensor(identity(2), customer_gate2(), identity(2))
         assert_allclose(props[1], result2)
 
     def test_N_level_system(self):