Repository: quantumlib/Cirq

Issue:
Need documentation on what protobuf serializations are allowed
It is important for users to know if their sympy-parametrized circuits will be protobuf serializable, either through more verbose error messages or more thorough documentation on which sympy features are supported.

xref #2122 


Discussion:
Once https://github.com/quantumlib/Cirq/issues/5050 lands, a circuit can then be validated against a device before serialization by using the device's gateset: `engine.get_processor('processor').get_device().metadata.gateset.validate(circuit)`. 

Printing the gateset will also show the full supported gateset of the device.
@verult, note that the question was about what `sympy` features are supported by serialization. We only support a very limited set of sympy expressions such as addition, multiplication, and exponentiation, not arbitrary sympy expressions. This probably doesn't need to be part of gateset, though, but rather should be part of the other validate we do before sending to QCS.
Gotcha. I will update the documentation on this limitation (maybe [here](https://quantumai.google/cirq/google/devices#gates_supported)) and look into adding validation.
Documentation is added in #5472.

With the new `CircuitSerializer`, which is the default and eventually the only serializer, the `OpSerializer` path will no longer be executed IIUC. CircuitSerializer will error if an unsupported Sympy expression is used, but I'll send a PR to make the message more clear.

https://github.com/quantumlib/Cirq/blob/baf5b818ff901065ab7ade7f1a5080ef0e4d7699/cirq-google/cirq_google/serialization/arg_func_langs.py#L193

This validation happens right before serialization. To improve on this, the invalid expression could be detected via `cg.GridDevice.validate_circuit(circuit)` prior to running the circuit, but doing this is tricky. Although there are protocol functions to find symbols in any arbitrary operation (`cirq.parameter_symbols()`), there isn't one for finding sympy expressions. So we either add a new protocol method to every gate for extracting expressions (a lot of effort), or identify the fields for each gate that GridDevice supports, similar to how it's handled [inside CircuitSerializer](https://github.com/quantumlib/Cirq/blob/baf5b818ff901065ab7ade7f1a5080ef0e4d7699/cirq-google/cirq_google/serialization/circuit_serializer.py#L148) (extra logic to add for each new gate).

I'm leaning towards only having validation prior to serialization for simplicity.

Resolving patch:
diff --git a/cirq-google/cirq_google/serialization/arg_func_langs.py b/cirq-google/cirq_google/serialization/arg_func_langs.py
--- a/cirq-google/cirq_google/serialization/arg_func_langs.py
+++ b/cirq-google/cirq_google/serialization/arg_func_langs.py
@@ -190,7 +190,11 @@ def check_support(func_type: str) -> str:
         for arg in value.args:
             arg_to_proto(arg, arg_function_language=arg_function_language, out=msg.func.args.add())
     else:
-        raise ValueError(f'Unrecognized arg type: {type(value)}')
+        raise ValueError(
+            f"Unrecognized Sympy expression type: {type(value)}."
+            " Only the following types are recognized: 'sympy.Symbol', 'sympy.Add', 'sympy.Mul',"
+            " 'sympy.Pow'."
+        )
 
 
 def float_arg_from_proto(


Test patch: