Repository: quantumlib/Cirq

Issue:
Deprecate gateset.accepts_global_phase
**Description of the issue**

Issue requested by @tanujkhattar 

xref: https://github.com/quantumlib/Cirq/pull/4697/files/d64eb23319c0eb7664526613b95db368659fb7aa#r766054614

Since global phase has a gate, it can be inspected like any other gate. Therefore gatesets no longer need special handling for global phase.
mypy check is failing on `CI` for sympy `v1.10`
**Description of the issue**
See: https://github.com/quantumlib/Cirq/pull/4936#issuecomment-1060953773

**Cirq version**
`master` version


Docs: Filter out TYPE_CHECKING from public docs
**Description of the issue**

The `TYPE_CHECKING` variable imported from `typing` shows up in API docs (example: https://github.com/quantumlib/Cirq/issues/5150). We should filter it out, since it's not part of the cirq API. Per @dabacon's [comment](https://github.com/quantumlib/Cirq/pull/5229#issuecomment-1093080151), we should be able to do this in `dev_tools/docs/build_api_docs.py`.

Deprecation of abstract/protocol methods
We need a better way to deprecate abstract methods.

Context (#3860): 

@balopat  This ends up being a breaking change though for any simulator that was overriding `_simulator_iterator`. This is why I had left the call to `_simulator_iterator` there in the original PR #3650. Otherwise I'd have just inlined and deleted `_simulator_iterator` outright: it's a private method and it's unused elsewhere.

It doesn't sound like anyone has been broken by this, so maybe it's okay. (We can just delete `_simulator_iterator` in that case; it's not called by anyone). I think there's still an unmet need for cleanly deprecate abstract methods, or methods that were intended to be overridden. The base class has to continue calling them until the deadline or it will break child classes. I like the error-by-default, but maybe there's a way to silence these errors when retaining the call to a deprecated method is required, like here.

_Originally posted by @daxfohl in https://github.com/quantumlib/Cirq/pull/3860#discussion_r587578684_


Discussion:

Looks like sympy v1.10 (released Mar 6) is triggering this failure. #5059 pins us to the old version, but we should look into updating the sympy type hints to allow us to advance.
Okay. To avoid us creating another issue related to this, we can leave this open until the sympy type hints have been updated.

This issue should spell out in what way the present deprecation mechanism is insufficient.
Discussed on Cirq Cynque: 

- First of all, we should clarify underscore usage  `_method` should be considered private. 
One suggestion: 
```
public
_private
_cirq_protocol_
__python_protocol__
_protected_protected
```

- Second, deprecation seems like a good idea to have for these.


I can't remember all the details but In retrospect I *think* I could have done this with some reflection in the calling methods. We could delete the method in the base class, and then the callers could do "if old method exists in the subclass then call it else call the new one" (or maybe vice-versa). Regardless, I think this isn't quite concrete enough of a problem to give a concrete answer for, and probably needs to be resolved on a case-by-case basis. I'd suggest closing the issue. @viathor @MichaelBroughton 

Resolving patch:
diff --git a/examples/qaoa.py b/examples/qaoa.py
--- a/examples/qaoa.py
+++ b/examples/qaoa.py
@@ -58,7 +58,7 @@
 import cirq
 
 
-def main(repetitions=1000, maxiter=50):
+def main(repetitions=10, maxiter=50, use_boolean_hamiltonian_gate=False):
     # Set problem parameters
     n = 6
     p = 2
@@ -72,7 +72,7 @@ def main(repetitions=1000, maxiter=50):
     # Print an example circuit
     betas = np.random.uniform(-np.pi, np.pi, size=p)
     gammas = np.random.uniform(-np.pi, np.pi, size=p)
-    circuit = qaoa_max_cut_circuit(qubits, betas, gammas, graph)
+    circuit = qaoa_max_cut_circuit(qubits, betas, gammas, graph, use_boolean_hamiltonian_gate)
     print('Example QAOA circuit:')
     print(circuit.to_text_diagram(transpose=True))
 
@@ -89,7 +89,7 @@ def f(x):
         # Create circuit
         betas = x[:p]
         gammas = x[p:]
-        circuit = qaoa_max_cut_circuit(qubits, betas, gammas, graph)
+        circuit = qaoa_max_cut_circuit(qubits, betas, gammas, graph, use_boolean_hamiltonian_gate)
         # Sample bitstrings from circuit
         result = simulator.run(circuit, repetitions=repetitions)
         bitstrings = result.measurements['m']
@@ -128,18 +128,29 @@ def rzz(rads):
     return cirq.ZZPowGate(exponent=2 * rads / np.pi, global_shift=-0.5)
 
 
-def qaoa_max_cut_unitary(qubits, betas, gammas, graph):  # Nodes should be integers
-    for beta, gamma in zip(betas, gammas):
-        yield (rzz(-0.5 * gamma).on(qubits[i], qubits[j]) for i, j in graph.edges)
-        yield cirq.rx(2 * beta).on_each(*qubits)
-
-
-def qaoa_max_cut_circuit(qubits, betas, gammas, graph):  # Nodes should be integers
+def qaoa_max_cut_unitary(
+    qubits, betas, gammas, graph, use_boolean_hamiltonian_gate
+):  # Nodes should be integers
+    if use_boolean_hamiltonian_gate:
+        booleans = [f"x{i} ^ x{j}" for i, j in sorted(graph.edges)]
+        param_names = [f"x{i}" for i in range(len(qubits))]
+        for beta, gamma in zip(betas, gammas):
+            yield cirq.BooleanHamiltonianGate(param_names, booleans, 2.0 * gamma).on(*qubits)
+            yield cirq.rx(2 * beta).on_each(*qubits)
+    else:
+        for beta, gamma in zip(betas, gammas):
+            yield (rzz(-0.5 * gamma).on(qubits[i], qubits[j]) for i, j in graph.edges)
+            yield cirq.rx(2 * beta).on_each(*qubits)
+
+
+def qaoa_max_cut_circuit(
+    qubits, betas, gammas, graph, use_boolean_hamiltonian_gate
+):  # Nodes should be integers
     return cirq.Circuit(
         # Prepare uniform superposition
         cirq.H.on_each(*qubits),
         # Apply QAOA unitary
-        qaoa_max_cut_unitary(qubits, betas, gammas, graph),
+        qaoa_max_cut_unitary(qubits, betas, gammas, graph, use_boolean_hamiltonian_gate),
         # Measure
         cirq.measure(*qubits, key='m'),
     )


Test patch:
diff --git a/examples/examples_test.py b/examples/examples_test.py
--- a/examples/examples_test.py
+++ b/examples/examples_test.py
@@ -1,6 +1,7 @@
 # pylint: disable=wrong-or-nonexistent-copyright-notice
 import itertools
 
+import networkx
 import numpy as np
 import pytest
 import matplotlib.pyplot as plt
@@ -93,7 +94,28 @@ def test_example_heatmaps():
 
 
 def test_example_runs_qaoa():
-    examples.qaoa.main(repetitions=10, maxiter=5)
+    examples.qaoa.main(repetitions=10, maxiter=5, use_boolean_hamiltonian_gate=False)
+    examples.qaoa.main(repetitions=10, maxiter=5, use_boolean_hamiltonian_gate=True)
+
+
+def test_example_qaoa_same_unitary():
+    n = 6
+    p = 2
+
+    qubits = cirq.LineQubit.range(n)
+
+    graph = networkx.random_regular_graph(3, n)
+
+    betas = np.random.uniform(-np.pi, np.pi, size=p)
+    gammas = np.random.uniform(-np.pi, np.pi, size=p)
+    circuits = [
+        examples.qaoa.qaoa_max_cut_circuit(
+            qubits, betas, gammas, graph, use_boolean_hamiltonian_gate
+        )
+        for use_boolean_hamiltonian_gate in [True, False]
+    ]
+
+    assert cirq.allclose_up_to_global_phase(cirq.unitary(circuits[0]), cirq.unitary(circuits[1]))
 
 
 def test_example_runs_quantum_teleportation():