Repository: quantumlib/Cirq

Issue:
`MatrixGate` names don't survive serialization
**Description of the issue**

`_name` is excluded from `MatrixGate._json_dict_()` and so is reset to `None` by serialization+deserialization

**How to reproduce the issue**

```python
gate = cirq.MatrixGate(np.eye(2), name="name")
gate_after_serialization = cirq.read_json(json_text=cirq.to_json(gate))

print(gate._name)  # "name"
print(gate_after_serialization._name)  # None
```

**Cirq version**

```
1.2.0.dev20230105212249
```




Discussion:
Accepted, though we have to be careful that old jsons without names are still deserialized.
What are the deliverables precisely required here?
@mustapha-saad-codeStar We want to update `MatrixGate._json_dict_` method to also include the `name` attribute in json serialization, if the `name` is not None. This should be backwards compatible because deserializing a matrix gate without a name should work as expected as `name` has a default value of `None`. 

Resolving patch:
diff --git a/cirq-core/cirq/ops/matrix_gates.py b/cirq-core/cirq/ops/matrix_gates.py
--- a/cirq-core/cirq/ops/matrix_gates.py
+++ b/cirq-core/cirq/ops/matrix_gates.py
@@ -114,11 +114,15 @@ def with_name(self, name: str) -> 'MatrixGate':
         return MatrixGate(self._matrix, name=name, qid_shape=self._qid_shape, unitary_check=False)
 
     def _json_dict_(self) -> Dict[str, Any]:
-        return {'matrix': self._matrix.tolist(), 'qid_shape': self._qid_shape}
+        return {
+            'matrix': self._matrix.tolist(),
+            'qid_shape': self._qid_shape,
+            **({'name': self._name} if self._name is not None else {}),
+        }
 
     @classmethod
-    def _from_json_dict_(cls, matrix, qid_shape, **kwargs):
-        return cls(matrix=np.array(matrix), qid_shape=qid_shape)
+    def _from_json_dict_(cls, matrix, qid_shape, name=None, **kwargs):
+        return cls(matrix=np.array(matrix), qid_shape=qid_shape, name=name)
 
     def _qid_shape_(self) -> Tuple[int, ...]:
         return self._qid_shape


Test patch:
diff --git a/cirq-core/cirq/ops/matrix_gates_test.py b/cirq-core/cirq/ops/matrix_gates_test.py
--- a/cirq-core/cirq/ops/matrix_gates_test.py
+++ b/cirq-core/cirq/ops/matrix_gates_test.py
@@ -388,3 +388,25 @@ def test_matrixgate_unitary_tolerance():
     # very low atol -> the check never converges
     with pytest.raises(ValueError):
         _ = cirq.MatrixGate(np.array([[0.707, 0.707], [-0.707, 0.707]]), unitary_check_rtol=1e-10)
+
+
+def test_matrixgate_name_serialization():
+    # https://github.com/quantumlib/Cirq/issues/5999
+
+    # Test name serialization
+    gate1 = cirq.MatrixGate(np.eye(2), name='test_name')
+    gate_after_serialization1 = cirq.read_json(json_text=cirq.to_json(gate1))
+    assert gate1._name == 'test_name'
+    assert gate_after_serialization1._name == 'test_name'
+
+    # Test name backwards compatibility
+    gate2 = cirq.MatrixGate(np.eye(2))
+    gate_after_serialization2 = cirq.read_json(json_text=cirq.to_json(gate2))
+    assert gate2._name is None
+    assert gate_after_serialization2._name is None
+
+    # Test empty name
+    gate3 = cirq.MatrixGate(np.eye(2), name='')
+    gate_after_serialization3 = cirq.read_json(json_text=cirq.to_json(gate3))
+    assert gate3._name == ''
+    assert gate_after_serialization3._name == ''