Repository: quantumlib/Cirq

Issue:
cirq.I doesn't have an on_each() method
This is because `IdentityGate` doesn't subclass `SingleQubitGate`.  Instead `I = IdentityGate(num_qubits=1)`.

`cirq.H`, `X`, `T`, etc. all have `for_each()` so I expected `cirq.I` to also have this method.


Discussion:
Do they? There isn't a `for_each` method, but there is `on_each`, which seems to be supported by `IdentityGate` as well: see `cirq/cirquits/circuit_test.py`.
Yes, I meant `on_each`.

Another class called `IdentityGate` is defined for a test ([cirq/circuits/circuit_test.py#L1488](https://github.com/quantumlib/Cirq/blob/master/cirq/circuits/circuit_test.py#L1488)) but the class of `cirq.I` is [cirq/ops/common_gates.py#L587](https://github.com/quantumlib/Cirq/blob/master/cirq/ops/common_gates.py#L587).  The first one subclasses `SingleQubitGate` but the second one doesn't.

Resolving patch:
diff --git a/cirq/ops/common_gates.py b/cirq/ops/common_gates.py
--- a/cirq/ops/common_gates.py
+++ b/cirq/ops/common_gates.py
@@ -628,6 +628,38 @@ def __init__(self, num_qubits):
     def num_qubits(self) -> int:
         return self._num_qubits
 
+    def on_each(self, *targets: Union[raw_types.Qid, Iterable[Any]]
+               ) -> List[raw_types.Operation]:
+        """Returns a list of operations that applies the single qubit identity
+        to each of the targets.
+
+        Args:
+            *targets: The qubits to apply this gate to.
+
+        Returns:
+            Operations applying this gate to the target qubits.
+
+        Raises:
+            ValueError if targets are not instances of Qid or List[Qid] or
+            the gate from which this is applied is not a single qubit identity
+            gate.
+        """
+        if self._num_qubits != 1:
+            raise ValueError(
+                'IdentityGate only supports on_each when it is a one qubit '
+                'gate.')
+        operations: List[raw_types.Operation] = []
+        for target in targets:
+            if isinstance(target, Iterable) and not isinstance(target, str):
+                operations.extend(self.on_each(*target))
+            elif isinstance(target, raw_types.Qid):
+                operations.append(self.on(target))
+            else:
+                raise ValueError(
+                    'Gate was called with type different than Qid. Type: {}'.
+                    format(type(target)))
+        return operations
+
     def _unitary_(self):
         return np.identity(2 ** self.num_qubits())
 
diff --git a/cirq/ops/gate_features.py b/cirq/ops/gate_features.py
--- a/cirq/ops/gate_features.py
+++ b/cirq/ops/gate_features.py
@@ -39,7 +39,7 @@ def _num_qubits_(self) -> int:
 
     def on_each(self, *targets: Union[raw_types.Qid, Iterable[Any]]
                ) -> List[raw_types.Operation]:
-        """Returns a list of operations apply this gate to each of the targets.
+        """Returns a list of operations applying the gate to all targets.
 
         Args:
             *targets: The qubits to apply this gate to.


Test patch:
diff --git a/cirq/ops/common_gates_test.py b/cirq/ops/common_gates_test.py
--- a/cirq/ops/common_gates_test.py
+++ b/cirq/ops/common_gates_test.py
@@ -216,6 +216,27 @@ def test_identity_init(num_qubits):
     assert cirq.IdentityGate(num_qubits).num_qubits() == num_qubits
 
 
+def test_identity_on_each():
+    q0, q1, q2 = cirq.LineQubit.range(3)
+    assert cirq.I.on_each(q0, q1, q2) == [cirq.I(q0), cirq.I(q1), cirq.I(q2)]
+    assert cirq.I.on_each([q0, [q1],
+                           q2]) == [cirq.I(q0),
+                                    cirq.I(q1),
+                                    cirq.I(q2)]
+    assert cirq.I.on_each(iter([q0, [q1],
+                                q2])) == [cirq.I(q0),
+                                          cirq.I(q1),
+                                          cirq.I(q2)]
+    with pytest.raises(ValueError, match='str'):
+        cirq.I.on_each('abc')
+
+
+def test_identity_on_each_only_single_qubit():
+    q0, q1 = cirq.LineQubit.range(2)
+    with pytest.raises(ValueError, match='one qubit'):
+        cirq.IdentityGate(num_qubits=2).on_each(q0, q1)
+
+
 @pytest.mark.parametrize('num_qubits', [1, 2, 4])
 def test_identity_unitary(num_qubits):
     i = cirq.IdentityGate(num_qubits)