Repository: quantumlib/Cirq

Issue:
Naming rotations
This issue seeks to settle the naming convention for factory functions that produce gate instances given rotation angles. I found the following factories:

```
Rx, Ry, Rz, GivensRotation, ISwapRotation, MS
```

These are clearly inconsistent. Proposals:

1. `Rx, Ry, Rz, Rgivens, Riswap, Rms`
2. `rx, ry, rz, rgivens, riswap, rms`
3. `XRotation, YRotation, ZRotation, GivensRotation, ISwapRotation, MSRotation`
4. `x_rotation, y_rotation, z_rotation, givens_rotation, iswap_rotation, ms_rotation`

I'm uneasy about conventions that lead to names like `cirq.rms` since this may be interpreted as "root mean square".

To broaden the set of examples, here are some names we may reasonably anticipate in future: 

```
Rzz, pauli_string_rotation
```

Context: [comment](https://github.com/quantumlib/Cirq/commit/5c13dea6ead7dc3721c1a84c523dd1e5d805bef0#commitcomment-35820146)

Thoughts?


Discussion:
related #1681 
I think method names should follow style conventions, so `snake_case`.  When I see `cirq.Rx` I think it is a class and start looking around for the class definition.  Maybe,
5. `rx, ry, rz, givens, iswap, ms`.
I think the factory methods main benefit is being short-cuts.   
I agree about `snake_case` (hence conventions 2 and 4).

Convention 5 is inconsistent with its use of the `r` prefix.
I think calling a unitary gate a rotation is kind of redundant.  "Rotation about givens" or "Rotation about Molmer-Sorenson" seems odd to me.
Good point. I'm starting to like 5. One more concern with it though: `cirq.iswap` and `cirq.ISWAP` meaning slightly different things is potentially confusing and error-prone.
Thought about it and I think I'm willing to accept `cirq.iswap` and `cirq.ISWAP` given that they would actually enter python expressions quite differently: one as a function call like `cirq.iswap(np.pi/5)` and the other standalone or exponentiated, e.g. `cirq.ISWAP**0.5`. This use is also consistent with the naming convention which implies the former is a function and the latter is a constant.

Thoughts?
> Rx, Ry, Rz, Rgivens, Riswap, Rms

`Rms` reads like root mean square.
`Rgivens` and `Riswap` are sorta logical given the first three, but very weird on their own.
Violates python naming convention.

> rx, ry, rz, rgivens, riswap, rms

`rms` reads like root mean square.
`rgivens` and `riswap` are sorta logical given the first three, but very weird on their own.
Semi-violates python naming convention in that there would normally be an underscore after the `r`.

> XRotation, YRotation, ZRotation, GivensRotation, ISwapRotation, MSRotation

The names for X/Y/Z are too long IMO. The most common gates should have short names.
`MSRotation` seems wrong; like saying `HadamardRotation`. I get what it means but it's odd.
Violates python naming convention.

> x_rotation, y_rotation, z_rotation, givens_rotation, iswap_rotation, ms_rotation

Too long x/y/z.
`ms_rotation` seems strange.

> rx, ry, rz, givens, iswap, ms.

Lacks consistency across them, but honestly I like this one the best by far. Avoiding the rotation word for two qubit operations seems to be a good idea.

The only major problem, I think, is that it will be confusing to have `iswap` *and* `ISWAP`.
Agreed, commented on the `iswap` vs `ISWAP` concern [above](https://github.com/quantumlib/Cirq/issues/2508#issuecomment-550596699).

Resolving patch:
diff --git a/cirq/__init__.py b/cirq/__init__.py
--- a/cirq/__init__.py
+++ b/cirq/__init__.py
@@ -239,6 +239,7 @@
     QubitOrderOrList,
     reset,
     ResetChannel,
+    riswap,
     Rx,
     Ry,
     Rz,
diff --git a/cirq/ops/__init__.py b/cirq/ops/__init__.py
--- a/cirq/ops/__init__.py
+++ b/cirq/ops/__init__.py
@@ -201,6 +201,7 @@
     ISWAP,
     ISwapPowGate,
     ISwapRotation,
+    riswap,
     SWAP,
     SwapPowGate,
 )
diff --git a/cirq/ops/swap_gates.py b/cirq/ops/swap_gates.py
--- a/cirq/ops/swap_gates.py
+++ b/cirq/ops/swap_gates.py
@@ -26,7 +26,7 @@
 import sympy
 
 from cirq import protocols, value
-from cirq._compat import proper_repr
+from cirq._compat import deprecated, proper_repr
 from cirq._doc import document
 from cirq.ops import common_gates, gate_features, eigen_gate, raw_types
 
@@ -248,10 +248,15 @@ def __repr__(self):
                                              self._global_shift)
 
 
-def ISwapRotation(angle_rads: value.TParamVal) -> ISwapPowGate:
+def riswap(rads: value.TParamVal) -> ISwapPowGate:
     """Returns gate with matrix exp(+i angle_rads (X⊗X + Y⊗Y) / 2)."""
-    pi = sympy.pi if protocols.is_parameterized(angle_rads) else np.pi
-    return ISwapPowGate()**(2 * angle_rads / pi)
+    pi = sympy.pi if protocols.is_parameterized(rads) else np.pi
+    return ISwapPowGate()**(2 * rads / pi)
+
+
+@deprecated(deadline='v0.8.0', fix='Use cirq.riswap, instead.')
+def ISwapRotation(angle_rads: value.TParamVal) -> ISwapPowGate:
+    return riswap(angle_rads)
 
 
 SWAP = SwapPowGate()


Test patch:
diff --git a/cirq/ops/swap_gates_test.py b/cirq/ops/swap_gates_test.py
--- a/cirq/ops/swap_gates_test.py
+++ b/cirq/ops/swap_gates_test.py
@@ -145,8 +145,8 @@ def test_trace_distance_over_range_of_exponents():
 
 
 @pytest.mark.parametrize('angle_rads', (-np.pi, -np.pi / 3, -0.1, np.pi / 5))
-def test_iswap_rotation_unitary(angle_rads):
-    actual = cirq.unitary(cirq.ISwapRotation(angle_rads))
+def test_riswap_unitary(angle_rads):
+    actual = cirq.unitary(cirq.riswap(angle_rads))
     c = np.cos(angle_rads)
     s = 1j * np.sin(angle_rads)
     # yapf: disable
@@ -159,8 +159,8 @@ def test_iswap_rotation_unitary(angle_rads):
 
 
 @pytest.mark.parametrize('angle_rads', (-2 * np.pi / 3, -0.2, 0.4, np.pi / 4))
-def test_iswap_rotation_hamiltonian(angle_rads):
-    actual = cirq.unitary(cirq.ISwapRotation(angle_rads))
+def test_riswap_hamiltonian(angle_rads):
+    actual = cirq.unitary(cirq.riswap(angle_rads))
     x = np.array([[0, 1], [1, 0]])
     y = np.array([[0, -1j], [1j, 0]])
     xx = np.kron(x, x)
@@ -170,6 +170,13 @@ def test_iswap_rotation_hamiltonian(angle_rads):
 
 
 @pytest.mark.parametrize('angle_rads', (-np.pi / 5, 0.4, 2, np.pi))
-def test_iswap_rotation_has_consistent_protocols(angle_rads):
+def test_riswap_has_consistent_protocols(angle_rads):
     cirq.testing.assert_implements_consistent_protocols(
-        cirq.ISwapRotation(angle_rads), ignoring_global_phase=False)
+        cirq.riswap(angle_rads), ignoring_global_phase=False)
+
+
+@pytest.mark.parametrize('angle_rads', (-1, -0.3, 0.2, 1))
+def test_deprecated_riswap(angle_rads):
+    assert np.all(
+        cirq.unitary(cirq.ISwapRotation(angle_rads)) == cirq.unitary(
+            cirq.riswap(angle_rads)))