Skip to content

'SingleQubitCliffordGate' object has no attribute '__name__' #6292

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
epelaaez opened this issue Sep 18, 2023 · 7 comments · Fixed by #6295
Closed

'SingleQubitCliffordGate' object has no attribute '__name__' #6292

epelaaez opened this issue Sep 18, 2023 · 7 comments · Fixed by #6295
Assignees
Labels
kind/bug-report Something doesn't seem to work.

Comments

@epelaaez
Copy link
Contributor

epelaaez commented Sep 18, 2023

Description of the issue
I'm trying to define a noise model with Clifford gates, and then serialize it. However, I get an error when trying to serialize it using cirq.to_json.

How to reproduce the issue

A simplified version of my noise model is the following.

p_x, p_y, p_z = 0.1, 0.1, 0.1
pauli_error_rates = {"X": p_x, "Y": p_y, "Z": p_z, "I": 1 - (p_x + p_y + p_z)}
qubits = cirq.LineQubit.range(1)
cliff = cirq.SingleQubitCliffordGate.from_xz_map((cirq.X, False), (cirq.Z, False))
ops_added = {
    cirq.OpIdentifier(cliff, qubits[0]): cirq.asymmetric_depolarize(error_probabilities=pauli_error_rates)(qubits[0])
}

Then, I do the following to serialize it.

model = cirq.devices.InsertionNoiseModel(ops_added, prepend=True, require_physical_tag=False)
cirq.to_json(model)

And I get the following.

AttributeError: 'SingleQubitCliffordGate' object has no attribute '__name__'

(full log below)

I also noticed the same happens when I use a cirq.CZ gate.

AttributeError                            Traceback (most recent call last)
Cell In[30], line 1
----> 1 cirq.to_json(model)

File /Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/cirq/protocols/json_serialization.py:613, in to_json(obj, file_or_fn, indent, separators, cls)
    583 def to_json(
    584     obj: Any,
    585     file_or_fn: Union[None, IO, pathlib.Path, str] = None,
   (...)
    589     cls: Type[json.JSONEncoder] = CirqEncoder,
    590 ) -> Optional[str]:
    591     """Write a JSON file containing a representation of obj.
    592 
    593     The object may be a cirq object or have data members that are cirq
   (...)
    611             to your classes rather than overriding this default.
    612     """
--> 613     if has_serializable_by_keys(obj):
    614         obj = _ContextualSerialization(obj)
    616         class ContextualEncoder(cls):  # type: ignore

File /Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/cirq/protocols/json_serialization.py:430, in has_serializable_by_keys(obj)
    428 json_dict = getattr(obj, '_json_dict_', lambda: None)()
    429 if isinstance(json_dict, Dict):
--> 430     return any(has_serializable_by_keys(v) for v in json_dict.values())
    432 # Handle primitive container types.
    433 if isinstance(obj, Dict):

File /Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/cirq/protocols/json_serialization.py:430, in <genexpr>(.0)
    428 json_dict = getattr(obj, '_json_dict_', lambda: None)()
    429 if isinstance(json_dict, Dict):
--> 430     return any(has_serializable_by_keys(v) for v in json_dict.values())
    432 # Handle primitive container types.
    433 if isinstance(obj, Dict):

File /Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/cirq/protocols/json_serialization.py:441, in has_serializable_by_keys(obj)
    436 if hasattr(obj, '__iter__') and not isinstance(obj, str):
    437     # Return False on TypeError because some numpy values
    438     # (like np.array(1)) have iterable methods
    439     # yet return a TypeError when there is an attempt to iterate over them
    440     try:
--> 441         return any(has_serializable_by_keys(elem) for elem in obj)
    442     except TypeError:
    443         return False

File /Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/cirq/protocols/json_serialization.py:441, in <genexpr>(.0)
    436 if hasattr(obj, '__iter__') and not isinstance(obj, str):
    437     # Return False on TypeError because some numpy values
    438     # (like np.array(1)) have iterable methods
    439     # yet return a TypeError when there is an attempt to iterate over them
    440     try:
--> 441         return any(has_serializable_by_keys(elem) for elem in obj)
    442     except TypeError:
    443         return False

File /Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/cirq/protocols/json_serialization.py:441, in has_serializable_by_keys(obj)
    436 if hasattr(obj, '__iter__') and not isinstance(obj, str):
    437     # Return False on TypeError because some numpy values
    438     # (like np.array(1)) have iterable methods
    439     # yet return a TypeError when there is an attempt to iterate over them
    440     try:
--> 441         return any(has_serializable_by_keys(elem) for elem in obj)
    442     except TypeError:
    443         return False

File /Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/cirq/protocols/json_serialization.py:441, in <genexpr>(.0)
    436 if hasattr(obj, '__iter__') and not isinstance(obj, str):
    437     # Return False on TypeError because some numpy values
    438     # (like np.array(1)) have iterable methods
    439     # yet return a TypeError when there is an attempt to iterate over them
    440     try:
--> 441         return any(has_serializable_by_keys(elem) for elem in obj)
    442     except TypeError:
    443         return False

File /Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/cirq/protocols/json_serialization.py:428, in has_serializable_by_keys(obj)
    426 if isinstance(obj, SerializableByKey):
    427     return True
--> 428 json_dict = getattr(obj, '_json_dict_', lambda: None)()
    429 if isinstance(json_dict, Dict):
    430     return any(has_serializable_by_keys(v) for v in json_dict.values())

File /Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/cirq/devices/noise_utils.py:89, in OpIdentifier._json_dict_(self)
     88 def _json_dict_(self) -> Dict[str, Any]:
---> 89     gate_json = protocols.json_cirq_type(self._gate_type)
     90     return {'gate_type': gate_json, 'qubits': self._qubits}

File /Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/cirq/protocols/json_serialization.py:506, in json_cirq_type(type_obj)
    504 if namespace:
    505     return f'{namespace}.{type_obj.__name__}'
--> 506 return type_obj.__name__

AttributeError: 'SingleQubitCliffordGate' object has no attribute '__name__'

Cirq version
1.3.0.dev20230915001934

@epelaaez epelaaez added the kind/bug-report Something doesn't seem to work. label Sep 18, 2023
@vtomole
Copy link
Collaborator

vtomole commented Sep 18, 2023

@epelaaez Do you want to work on this?

@epelaaez
Copy link
Contributor Author

epelaaez commented Sep 18, 2023

Yes, I can look into it

It seems like the problem here is that when defining a gate as follows:

gate = cirq.SingleQubitCliffordGate.from_xz_map((cirq.X, False), (cirq.Z, False))

Doing gate.__name__ returns the error I'm experiencing, but doing gate.__class__.__name__ returns 'SingleQubitCliffordGate', which I think is the output we want (can you confirm this?)

@vtomole
Copy link
Collaborator

vtomole commented Sep 18, 2023

which I think is the output we want

Yep

@epelaaez
Copy link
Contributor Author

I found that doing

ops_added = { 
    cliff(qubits[0]): cirq.asymmetric_depolarize(error_probabilities=pauli_error_rates)(qubits[0]) 
}

solves the problem.

The issue is that OpIdentifier._json_dict_ calls protocols.json_cirq_type(self._gate_type) and this is where the '__name__' is not found. This could be fixed by doing something like

try:
    return type_obj.__name__
except AttributeError:
    return type_obj.__class__.__name__

but then I get

{
  "cirq_type": "InsertionNoiseModel",
  "ops_added": [
    [
      {
        "cirq_type": "OpIdentifier",
        "gate_type": "SingleQubitCliffordGate",
        "qubits": [
          {
            "cirq_type": "LineQubit",
            "x": 0
          }
        ]
      },
      {
        "cirq_type": "GateOperation",
        "gate": {
          "cirq_type": "AsymmetricDepolarizingChannel",
          "error_probabilities": {
            "X": 0.1,
            "Y": 0.1,
            "Z": 0.1,
            "I": 0.7
          }
        },
        "qubits": [
          {
            "cirq_type": "LineQubit",
            "x": 0
          }
        ]
      }
    ]
  ],
  "prepend": true,
  "require_physical_tag": false
} 

which loses information about the specific Clifford gate I'm using in my model. I think this is the intended behavior of OpIdentifier though, as it takes as an argument gate_type: Type['cirq.Gate'] and not a specific gate. Since it seems like I can get away with not using OpIdentifier when using particular gates, and this looks like intended behavior, I think this could be closed (wdyt @vtomole)?

@vtomole
Copy link
Collaborator

vtomole commented Sep 20, 2023

So, it looks like OpIdentifier can't be json serializable for some inputs?

@epelaaez
Copy link
Contributor Author

Yes, I think that's the issue. At least that the specificity of certain inputs is lost when serializing it.

@vtomole
Copy link
Collaborator

vtomole commented Sep 20, 2023

Okay, sounds like a bug that we can fix as part of this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind/bug-report Something doesn't seem to work.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants