Repository: quantumlib/Cirq

Issue:
merge_single_qubit_gates_to_phxz raises IndexError when encountering GlobalPhaseGate
**Description of the issue**

**How to reproduce the issue**

```
cirq.merge_single_qubit_gates_to_phxz(cirq.Circuit(cirq.GlobalPhaseGate(1j).on()))
...
/src/cirq/cirq-core/cirq/linalg/decompositions.py in deconstruct_single_qubit_matrix_into_angles(mat)
     88     """
     89     # Anti-cancel left-vs-right phase along top row.
---> 90     right_phase = cmath.phase(mat[0, 1] * np.conj(mat[0, 0])) + math.pi
     91     mat = np.dot(mat, _phase_matrix(-right_phase))
     92 

IndexError: index 1 is out of bounds for axis 1 with size 1
```

I also checked `merge_single_qubit_gates_to_phased_x_and_z` and it suffers from the same issue.

The problem appears to be that the rewriter passes a 1x1 matrix to `single_qubit_matrix_to_phxz` which expects a 2x2 matrix.

**Cirq version**
0.16.0.dev



Discussion:

Resolving patch:
diff --git a/cirq-core/cirq/transformers/merge_single_qubit_gates.py b/cirq-core/cirq/transformers/merge_single_qubit_gates.py
--- a/cirq-core/cirq/transformers/merge_single_qubit_gates.py
+++ b/cirq-core/cirq/transformers/merge_single_qubit_gates.py
@@ -16,7 +16,7 @@
 
 from typing import Optional, TYPE_CHECKING
 
-from cirq import protocols, circuits
+from cirq import circuits, ops, protocols
 from cirq.transformers.analytical_decompositions import single_qubit_decompositions
 from cirq.transformers import transformer_api, transformer_primitives, merge_k_qubit_gates
 
@@ -47,11 +47,12 @@ def merge_single_qubit_gates_to_phased_x_and_z(
     """
 
     def rewriter(op: 'cirq.CircuitOperation') -> 'cirq.OP_TREE':
+        u = protocols.unitary(op)
+        if protocols.num_qubits(op) == 0:
+            return ops.GlobalPhaseGate(u[0, 0]).on()
         return [
             g(op.qubits[0])
-            for g in single_qubit_decompositions.single_qubit_matrix_to_phased_x_z(
-                protocols.unitary(op), atol
-            )
+            for g in single_qubit_decompositions.single_qubit_matrix_to_phased_x_z(u, atol)
         ]
 
     return merge_k_qubit_gates.merge_k_qubit_unitaries(
@@ -82,7 +83,10 @@ def merge_single_qubit_gates_to_phxz(
     """
 
     def rewriter(op: 'cirq.CircuitOperation') -> 'cirq.OP_TREE':
-        gate = single_qubit_decompositions.single_qubit_matrix_to_phxz(protocols.unitary(op), atol)
+        u = protocols.unitary(op)
+        if protocols.num_qubits(op) == 0:
+            return ops.GlobalPhaseGate(u[0, 0]).on()
+        gate = single_qubit_decompositions.single_qubit_matrix_to_phxz(u, atol)
         return gate(op.qubits[0]) if gate else []
 
     return merge_k_qubit_gates.merge_k_qubit_unitaries(


Test patch:
diff --git a/cirq-core/cirq/transformers/merge_single_qubit_gates_test.py b/cirq-core/cirq/transformers/merge_single_qubit_gates_test.py
--- a/cirq-core/cirq/transformers/merge_single_qubit_gates_test.py
+++ b/cirq-core/cirq/transformers/merge_single_qubit_gates_test.py
@@ -219,3 +219,15 @@ def test_merge_single_qubit_moments_to_phxz_deep():
     cirq.testing.assert_allclose_up_to_global_phase(
         c_new.unitary(), c_expected.unitary(), atol=1e-7
     )
+
+
+def test_merge_single_qubit_moments_to_phxz_global_phase():
+    c = cirq.Circuit(cirq.GlobalPhaseGate(1j).on())
+    c2 = cirq.merge_single_qubit_gates_to_phxz(c)
+    assert c == c2
+
+
+def test_merge_single_qubit_moments_to_phased_x_and_z_global_phase():
+    c = cirq.Circuit(cirq.GlobalPhaseGate(1j).on())
+    c2 = cirq.merge_single_qubit_gates_to_phased_x_and_z(c)
+    assert c == c2