We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
sqrtISWAP serializer doesn't like rz, ry, rx
The `cirq.rz` helper function ([cirq.ops.common_gates:1045](https://github.com/quantumlib/Cirq/blob/d998b3afe20dd6783e00dcc2590ba0f162b95af7/cirq/ops/common_gates.py#L1045)) converts inputs to half turns (radians?) by dividing by sympy.pi for parametrized inputs, but this division is actually expressed as `sympy.Mul(sympy.Pow(sympy.pi, sympy.Integer(-1))`

The `sympy.Pow` part of that expression then causes problems with serializers that expect only `Mul` and `Add` in Sympy expressions (i.e. [cirq.google.arg_func_langs:143](https://github.com/quantumlib/Cirq/blob/d998b3afe20dd6783e00dcc2590ba0f162b95af7/cirq/google/arg_func_langs.py#L143)) 

Would it make more sense to convert all forms of `rz` inputs (symbolic or not) with division by `np.pi`?

reproducing code:
```
# This introduces `Pow`:
contains_pow = sympy.Symbol('x') / sympy.pi
for arg in contains_pow.args:
  print(arg, type(arg))
>>> x <class 'sympy.core.symbol.Symbol'>
>>> 1/pi <class 'sympy.core.power.Pow'>

# This casts to float:
no_pow = sympy.Symbol('x') / np.pi
for arg in no_pow.args:
  print(arg, type(arg))

>>> 0.318309886183791 <class 'sympy.core.numbers.Float'>
>>> x <class 'sympy.core.symbol.Symbol'>

# Serializer chokes up on Pow due to sympy.pi division
q0 = cirq.GridQubit(0, 0)
c0 = cirq.Circuit(cirq.rz(sympy.Symbol('x')).on(q0))
c1 = cirq.Circuit(cirq.ZPowGate(exponent=sympy.Symbol('x')/np.pi, global_shift=-0.5).on(q0) )

cirq.google.SQRT_ISWAP_GATESET.serialize(c0) # Throws ValueError: Unrecognized arg type: <class 'sympy.core.power.Pow'>
cirq.google.SQRT_ISWAP_GATESET.serialize(c1) # Works fine
```

@dstrain115 

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `cirq/google/arg_func_langs.py`
Content:
```
1 # Copyright 2019 The Cirq Developers
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 #     https://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 import math
15 from typing import (
16     List,
17     Union,
18     Optional,
19     Iterator,
20     Iterable,
21     cast,
22     Set,
23     Dict,
24     FrozenSet,
25 )
26 
27 import numpy as np
28 import sympy
29 from cirq.google.api import v2
30 
31 SUPPORTED_FUNCTIONS_FOR_LANGUAGE: Dict[Optional[str], FrozenSet[str]] = {
32     '': frozenset(),
33     'linear': frozenset({'add', 'mul'}),
34     # None means any. Is used when inferring the language during serialization.
35     None: frozenset({'add', 'mul'}),
36 }
37 
38 SUPPORTED_SYMPY_OPS = (sympy.Symbol, sympy.Add, sympy.Mul)
39 
40 # Argument types for gates.
41 ARG_LIKE = Union[int, float, List[bool], str, sympy.Symbol, sympy.Add, sympy.
42                  Mul]
43 
44 # Supported function languages in order from least to most flexible.
45 # Clients should use the least flexible language they can, to make it easier
46 # to gradually roll out new capabilities to clients and servers.
47 LANGUAGE_ORDER = [
48     '',
49     'linear',
50 ]
51 
52 
53 def _max_lang(langs: Iterable[str]) -> str:
54     i = max((LANGUAGE_ORDER.index(e) for e in langs), default=0)
55     return LANGUAGE_ORDER[i]
56 
57 
58 def _infer_function_language_from_circuit(value: v2.program_pb2.Circuit) -> str:
59     return _max_lang({
60         e for moment in value.moments for op in moment.operations
61         for e in _function_languages_from_operation(op)
62     })
63 
64 
65 def _infer_function_language_from_schedule(value: v2.program_pb2.Schedule
66                                           ) -> str:
67     return _max_lang({
68         e for op in value.scheduled_operations
69         for e in _function_languages_from_operation(op.operation)
70     })
71 
72 
73 def _function_languages_from_operation(value: v2.program_pb2.Operation
74                                       ) -> Iterator[str]:
75     for arg in value.args.values():
76         yield from _function_languages_from_arg(arg)
77 
78 
79 def _function_languages_from_arg(arg_proto: v2.program_pb2.Arg
80                                 ) -> Iterator[str]:
81 
82     which = arg_proto.WhichOneof('arg')
83     if which == 'func':
84         if arg_proto.func.type in ['add', 'mul']:
85             yield 'linear'
86             for a in arg_proto.func.args:
87                 yield from _function_languages_from_arg(a)
88 
89 
90 def _arg_to_proto(value: ARG_LIKE,
91                   *,
92                   arg_function_language: Optional[str],
93                   out: Optional[v2.program_pb2.Arg] = None
94                  ) -> v2.program_pb2.Arg:
95     """Writes an argument value into an Arg proto.
96 
97     Args:
98         value: The value to encode.
99         arg_function_language: The language to use when encoding functions. If
100             this is set to None, it will be set to the minimal language
101             necessary to support the features that were actually used.
102         out: The proto to write the result into. Defaults to a new instance.
103 
104     Returns:
105         The proto that was written into as well as the `arg_function_language`
106         that was used.
107     """
108 
109     if arg_function_language not in SUPPORTED_FUNCTIONS_FOR_LANGUAGE:
110         raise ValueError(f'Unrecognized arg_function_language: '
111                          f'{arg_function_language!r}')
112     supported = SUPPORTED_FUNCTIONS_FOR_LANGUAGE[arg_function_language]
113 
114     msg = v2.program_pb2.Arg() if out is None else out
115 
116     def check_support(func_type: str) -> str:
117         if func_type not in supported:
118             lang = (repr(arg_function_language)
119                     if arg_function_language is not None else '[any]')
120             raise ValueError(f'Function type {func_type!r} not supported by '
121                              f'arg_function_language {lang}')
122         return func_type
123 
124     if isinstance(value, (float, int, sympy.Integer, sympy.Float,
125                           sympy.Rational, sympy.NumberSymbol)):
126         msg.arg_value.float_value = float(value)
127     elif isinstance(value, str):
128         msg.arg_value.string_value = value
129     elif (isinstance(value, (list, tuple, np.ndarray)) and
130           all(isinstance(x, (bool, np.bool_)) for x in value)):
131         # Some protobuf / numpy combinations do not support np.bool_, so cast.
132         msg.arg_value.bool_values.values.extend([bool(x) for x in value])
133     elif isinstance(value, sympy.Symbol):
134         msg.symbol = str(value.free_symbols.pop())
135     elif isinstance(value, sympy.Add):
136         msg.func.type = check_support('add')
137         for arg in value.args:
138             _arg_to_proto(arg,
139                           arg_function_language=arg_function_language,
140                           out=msg.func.args.add())
141     elif isinstance(value, sympy.Mul):
142         msg.func.type = check_support('mul')
143         for arg in value.args:
144             _arg_to_proto(arg,
145                           arg_function_language=arg_function_language,
146                           out=msg.func.args.add())
147     else:
148         raise ValueError(f'Unrecognized arg type: {type(value)}')
149 
150     return msg
151 
152 
153 def _arg_from_proto(
154         arg_proto: v2.program_pb2.Arg,
155         *,
156         arg_function_language: str,
157         required_arg_name: Optional[str] = None,
158 ) -> Optional[ARG_LIKE]:
159     """Extracts a python value from an argument value proto.
160 
161     Args:
162         arg_proto: The proto containing a serialized value.
163         arg_function_language: The `arg_function_language` field from
164             `Program.Language`.
165         required_arg_name: If set to `None`, the method will return `None` when
166             given an unset proto value. If set to a string, the method will
167             instead raise an error complaining that the value is missing in that
168             situation.
169 
170     Returns:
171         The deserialized value, or else None if there was no set value and
172         `required_arg_name` was set to `None`.
173     """
174     supported = SUPPORTED_FUNCTIONS_FOR_LANGUAGE.get(arg_function_language)
175     if supported is None:
176         raise ValueError(f'Unrecognized arg_function_language: '
177                          f'{arg_function_language!r}')
178 
179     which = arg_proto.WhichOneof('arg')
180     if which == 'arg_value':
181         arg_value = arg_proto.arg_value
182         which_val = arg_value.WhichOneof('arg_value')
183         if which_val == 'float_value' or which_val == 'double_value':
184             if which_val == 'double_value':
185                 result = float(arg_value.double_value)
186             else:
187                 result = float(arg_value.float_value)
188             if math.ceil(result) == math.floor(result):
189                 result = int(result)
190             return result
191         if which_val == 'bool_values':
192             return list(arg_value.bool_values.values)
193         if which_val == 'string_value':
194             return str(arg_value.string_value)
195         raise ValueError(f'Unrecognized value type: {which_val!r}')
196 
197     if which == 'symbol':
198         return sympy.Symbol(arg_proto.symbol)
199 
200     if which == 'func':
201         func = arg_proto.func
202 
203         if func.type not in cast(Set[str], supported):
204             raise ValueError(
205                 f'Unrecognized function type {func.type!r} '
206                 f'for arg_function_language={arg_function_language!r}')
207 
208         if func.type == 'add':
209             return sympy.Add(*[
210                 _arg_from_proto(a,
211                                 arg_function_language=arg_function_language,
212                                 required_arg_name='An addition argument')
213                 for a in func.args
214             ])
215 
216         if func.type == 'mul':
217             return sympy.Mul(*[
218                 _arg_from_proto(a,
219                                 arg_function_language=arg_function_language,
220                                 required_arg_name='A multiplication argument')
221                 for a in func.args
222             ])
223 
224     if required_arg_name is not None:
225         raise ValueError(
226             f'{required_arg_name} is missing or has an unrecognized '
227             f'argument type (WhichOneof("arg")={which!r}).')
228 
229     return None
230
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/cirq/google/arg_func_langs.py b/cirq/google/arg_func_langs.py
--- a/cirq/google/arg_func_langs.py
+++ b/cirq/google/arg_func_langs.py
@@ -31,11 +31,12 @@
 SUPPORTED_FUNCTIONS_FOR_LANGUAGE: Dict[Optional[str], FrozenSet[str]] = {
     '': frozenset(),
     'linear': frozenset({'add', 'mul'}),
+    'exp': frozenset({'add', 'mul', 'pow'}),
     # None means any. Is used when inferring the language during serialization.
-    None: frozenset({'add', 'mul'}),
+    None: frozenset({'add', 'mul', 'pow'}),
 }
 
-SUPPORTED_SYMPY_OPS = (sympy.Symbol, sympy.Add, sympy.Mul)
+SUPPORTED_SYMPY_OPS = (sympy.Symbol, sympy.Add, sympy.Mul, sympy.Pow)
 
 # Argument types for gates.
 ARG_LIKE = Union[int, float, List[bool], str, sympy.Symbol, sympy.Add, sympy.
@@ -47,6 +48,7 @@
 LANGUAGE_ORDER = [
     '',
     'linear',
+    'exp',
 ]
 
 
@@ -85,6 +87,10 @@
             yield 'linear'
             for a in arg_proto.func.args:
                 yield from _function_languages_from_arg(a)
+        if arg_proto.func.type in ['pow']:
+            yield 'exp'
+            for a in arg_proto.func.args:
+                yield from _function_languages_from_arg(a)
 
 
 def _arg_to_proto(value: ARG_LIKE,
@@ -144,6 +150,12 @@
             _arg_to_proto(arg,
                           arg_function_language=arg_function_language,
                           out=msg.func.args.add())
+    elif isinstance(value, sympy.Pow):
+        msg.func.type = check_support('pow')
+        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)}')
 
@@ -221,6 +233,14 @@
                 for a in func.args
             ])
 
+        if func.type == 'pow':
+            return sympy.Pow(*[
+                _arg_from_proto(a,
+                                arg_function_language=arg_function_language,
+                                required_arg_name='A power argument')
+                for a in func.args
+            ])
+
     if required_arg_name is not None:
         raise ValueError(
             f'{required_arg_name} is missing or has an unrecognized '

{"golden_diff": "diff --git a/cirq/google/arg_func_langs.py b/cirq/google/arg_func_langs.py\n--- a/cirq/google/arg_func_langs.py\n+++ b/cirq/google/arg_func_langs.py\n@@ -31,11 +31,12 @@\n SUPPORTED_FUNCTIONS_FOR_LANGUAGE: Dict[Optional[str], FrozenSet[str]] = {\n     '': frozenset(),\n     'linear': frozenset({'add', 'mul'}),\n+    'exp': frozenset({'add', 'mul', 'pow'}),\n     # None means any. Is used when inferring the language during serialization.\n-    None: frozenset({'add', 'mul'}),\n+    None: frozenset({'add', 'mul', 'pow'}),\n }\n \n-SUPPORTED_SYMPY_OPS = (sympy.Symbol, sympy.Add, sympy.Mul)\n+SUPPORTED_SYMPY_OPS = (sympy.Symbol, sympy.Add, sympy.Mul, sympy.Pow)\n \n # Argument types for gates.\n ARG_LIKE = Union[int, float, List[bool], str, sympy.Symbol, sympy.Add, sympy.\n@@ -47,6 +48,7 @@\n LANGUAGE_ORDER = [\n     '',\n     'linear',\n+    'exp',\n ]\n \n \n@@ -85,6 +87,10 @@\n             yield 'linear'\n             for a in arg_proto.func.args:\n                 yield from _function_languages_from_arg(a)\n+        if arg_proto.func.type in ['pow']:\n+            yield 'exp'\n+            for a in arg_proto.func.args:\n+                yield from _function_languages_from_arg(a)\n \n \n def _arg_to_proto(value: ARG_LIKE,\n@@ -144,6 +150,12 @@\n             _arg_to_proto(arg,\n                           arg_function_language=arg_function_language,\n                           out=msg.func.args.add())\n+    elif isinstance(value, sympy.Pow):\n+        msg.func.type = check_support('pow')\n+        for arg in value.args:\n+            _arg_to_proto(arg,\n+                          arg_function_language=arg_function_language,\n+                          out=msg.func.args.add())\n     else:\n         raise ValueError(f'Unrecognized arg type: {type(value)}')\n \n@@ -221,6 +233,14 @@\n                 for a in func.args\n             ])\n \n+        if func.type == 'pow':\n+            return sympy.Pow(*[\n+                _arg_from_proto(a,\n+                                arg_function_language=arg_function_language,\n+                                required_arg_name='A power argument')\n+                for a in func.args\n+            ])\n+\n     if required_arg_name is not None:\n         raise ValueError(\n             f'{required_arg_name} is missing or has an unrecognized '\n", "issue": "sqrtISWAP serializer doesn't like rz, ry, rx\nThe `cirq.rz` helper function ([cirq.ops.common_gates:1045](https://github.com/quantumlib/Cirq/blob/d998b3afe20dd6783e00dcc2590ba0f162b95af7/cirq/ops/common_gates.py#L1045)) converts inputs to half turns (radians?) by dividing by sympy.pi for parametrized inputs, but this division is actually expressed as `sympy.Mul(sympy.Pow(sympy.pi, sympy.Integer(-1))`\r\n\r\nThe `sympy.Pow` part of that expression then causes problems with serializers that expect only `Mul` and `Add` in Sympy expressions (i.e. [cirq.google.arg_func_langs:143](https://github.com/quantumlib/Cirq/blob/d998b3afe20dd6783e00dcc2590ba0f162b95af7/cirq/google/arg_func_langs.py#L143)) \r\n\r\nWould it make more sense to convert all forms of `rz` inputs (symbolic or not) with division by `np.pi`?\r\n\r\nreproducing code:\r\n```\r\n# This introduces `Pow`:\r\ncontains_pow = sympy.Symbol('x') / sympy.pi\r\nfor arg in contains_pow.args:\r\n  print(arg, type(arg))\r\n>>> x <class 'sympy.core.symbol.Symbol'>\r\n>>> 1/pi <class 'sympy.core.power.Pow'>\r\n\r\n# This casts to float:\r\nno_pow = sympy.Symbol('x') / np.pi\r\nfor arg in no_pow.args:\r\n  print(arg, type(arg))\r\n\r\n>>> 0.318309886183791 <class 'sympy.core.numbers.Float'>\r\n>>> x <class 'sympy.core.symbol.Symbol'>\r\n\r\n# Serializer chokes up on Pow due to sympy.pi division\r\nq0 = cirq.GridQubit(0, 0)\r\nc0 = cirq.Circuit(cirq.rz(sympy.Symbol('x')).on(q0))\r\nc1 = cirq.Circuit(cirq.ZPowGate(exponent=sympy.Symbol('x')/np.pi, global_shift=-0.5).on(q0) )\r\n\r\ncirq.google.SQRT_ISWAP_GATESET.serialize(c0) # Throws ValueError: Unrecognized arg type: <class 'sympy.core.power.Pow'>\r\ncirq.google.SQRT_ISWAP_GATESET.serialize(c1) # Works fine\r\n```\r\n\r\n@dstrain115 \n", "before_files": [{"content": "# Copyright 2019 The Cirq Developers\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\nimport math\nfrom typing import (\n    List,\n    Union,\n    Optional,\n    Iterator,\n    Iterable,\n    cast,\n    Set,\n    Dict,\n    FrozenSet,\n)\n\nimport numpy as np\nimport sympy\nfrom cirq.google.api import v2\n\nSUPPORTED_FUNCTIONS_FOR_LANGUAGE: Dict[Optional[str], FrozenSet[str]] = {\n    '': frozenset(),\n    'linear': frozenset({'add', 'mul'}),\n    # None means any. Is used when inferring the language during serialization.\n    None: frozenset({'add', 'mul'}),\n}\n\nSUPPORTED_SYMPY_OPS = (sympy.Symbol, sympy.Add, sympy.Mul)\n\n# Argument types for gates.\nARG_LIKE = Union[int, float, List[bool], str, sympy.Symbol, sympy.Add, sympy.\n                 Mul]\n\n# Supported function languages in order from least to most flexible.\n# Clients should use the least flexible language they can, to make it easier\n# to gradually roll out new capabilities to clients and servers.\nLANGUAGE_ORDER = [\n    '',\n    'linear',\n]\n\n\ndef _max_lang(langs: Iterable[str]) -> str:\n    i = max((LANGUAGE_ORDER.index(e) for e in langs), default=0)\n    return LANGUAGE_ORDER[i]\n\n\ndef _infer_function_language_from_circuit(value: v2.program_pb2.Circuit) -> str:\n    return _max_lang({\n        e for moment in value.moments for op in moment.operations\n        for e in _function_languages_from_operation(op)\n    })\n\n\ndef _infer_function_language_from_schedule(value: v2.program_pb2.Schedule\n                                          ) -> str:\n    return _max_lang({\n        e for op in value.scheduled_operations\n        for e in _function_languages_from_operation(op.operation)\n    })\n\n\ndef _function_languages_from_operation(value: v2.program_pb2.Operation\n                                      ) -> Iterator[str]:\n    for arg in value.args.values():\n        yield from _function_languages_from_arg(arg)\n\n\ndef _function_languages_from_arg(arg_proto: v2.program_pb2.Arg\n                                ) -> Iterator[str]:\n\n    which = arg_proto.WhichOneof('arg')\n    if which == 'func':\n        if arg_proto.func.type in ['add', 'mul']:\n            yield 'linear'\n            for a in arg_proto.func.args:\n                yield from _function_languages_from_arg(a)\n\n\ndef _arg_to_proto(value: ARG_LIKE,\n                  *,\n                  arg_function_language: Optional[str],\n                  out: Optional[v2.program_pb2.Arg] = None\n                 ) -> v2.program_pb2.Arg:\n    \"\"\"Writes an argument value into an Arg proto.\n\n    Args:\n        value: The value to encode.\n        arg_function_language: The language to use when encoding functions. If\n            this is set to None, it will be set to the minimal language\n            necessary to support the features that were actually used.\n        out: The proto to write the result into. Defaults to a new instance.\n\n    Returns:\n        The proto that was written into as well as the `arg_function_language`\n        that was used.\n    \"\"\"\n\n    if arg_function_language not in SUPPORTED_FUNCTIONS_FOR_LANGUAGE:\n        raise ValueError(f'Unrecognized arg_function_language: '\n                         f'{arg_function_language!r}')\n    supported = SUPPORTED_FUNCTIONS_FOR_LANGUAGE[arg_function_language]\n\n    msg = v2.program_pb2.Arg() if out is None else out\n\n    def check_support(func_type: str) -> str:\n        if func_type not in supported:\n            lang = (repr(arg_function_language)\n                    if arg_function_language is not None else '[any]')\n            raise ValueError(f'Function type {func_type!r} not supported by '\n                             f'arg_function_language {lang}')\n        return func_type\n\n    if isinstance(value, (float, int, sympy.Integer, sympy.Float,\n                          sympy.Rational, sympy.NumberSymbol)):\n        msg.arg_value.float_value = float(value)\n    elif isinstance(value, str):\n        msg.arg_value.string_value = value\n    elif (isinstance(value, (list, tuple, np.ndarray)) and\n          all(isinstance(x, (bool, np.bool_)) for x in value)):\n        # Some protobuf / numpy combinations do not support np.bool_, so cast.\n        msg.arg_value.bool_values.values.extend([bool(x) for x in value])\n    elif isinstance(value, sympy.Symbol):\n        msg.symbol = str(value.free_symbols.pop())\n    elif isinstance(value, sympy.Add):\n        msg.func.type = check_support('add')\n        for arg in value.args:\n            _arg_to_proto(arg,\n                          arg_function_language=arg_function_language,\n                          out=msg.func.args.add())\n    elif isinstance(value, sympy.Mul):\n        msg.func.type = check_support('mul')\n        for arg in value.args:\n            _arg_to_proto(arg,\n                          arg_function_language=arg_function_language,\n                          out=msg.func.args.add())\n    else:\n        raise ValueError(f'Unrecognized arg type: {type(value)}')\n\n    return msg\n\n\ndef _arg_from_proto(\n        arg_proto: v2.program_pb2.Arg,\n        *,\n        arg_function_language: str,\n        required_arg_name: Optional[str] = None,\n) -> Optional[ARG_LIKE]:\n    \"\"\"Extracts a python value from an argument value proto.\n\n    Args:\n        arg_proto: The proto containing a serialized value.\n        arg_function_language: The `arg_function_language` field from\n            `Program.Language`.\n        required_arg_name: If set to `None`, the method will return `None` when\n            given an unset proto value. If set to a string, the method will\n            instead raise an error complaining that the value is missing in that\n            situation.\n\n    Returns:\n        The deserialized value, or else None if there was no set value and\n        `required_arg_name` was set to `None`.\n    \"\"\"\n    supported = SUPPORTED_FUNCTIONS_FOR_LANGUAGE.get(arg_function_language)\n    if supported is None:\n        raise ValueError(f'Unrecognized arg_function_language: '\n                         f'{arg_function_language!r}')\n\n    which = arg_proto.WhichOneof('arg')\n    if which == 'arg_value':\n        arg_value = arg_proto.arg_value\n        which_val = arg_value.WhichOneof('arg_value')\n        if which_val == 'float_value' or which_val == 'double_value':\n            if which_val == 'double_value':\n                result = float(arg_value.double_value)\n            else:\n                result = float(arg_value.float_value)\n            if math.ceil(result) == math.floor(result):\n                result = int(result)\n            return result\n        if which_val == 'bool_values':\n            return list(arg_value.bool_values.values)\n        if which_val == 'string_value':\n            return str(arg_value.string_value)\n        raise ValueError(f'Unrecognized value type: {which_val!r}')\n\n    if which == 'symbol':\n        return sympy.Symbol(arg_proto.symbol)\n\n    if which == 'func':\n        func = arg_proto.func\n\n        if func.type not in cast(Set[str], supported):\n            raise ValueError(\n                f'Unrecognized function type {func.type!r} '\n                f'for arg_function_language={arg_function_language!r}')\n\n        if func.type == 'add':\n            return sympy.Add(*[\n                _arg_from_proto(a,\n                                arg_function_language=arg_function_language,\n                                required_arg_name='An addition argument')\n                for a in func.args\n            ])\n\n        if func.type == 'mul':\n            return sympy.Mul(*[\n                _arg_from_proto(a,\n                                arg_function_language=arg_function_language,\n                                required_arg_name='A multiplication argument')\n                for a in func.args\n            ])\n\n    if required_arg_name is not None:\n        raise ValueError(\n            f'{required_arg_name} is missing or has an unrecognized '\n            f'argument type (WhichOneof(\"arg\")={which!r}).')\n\n    return None\n", "path": "cirq/google/arg_func_langs.py"}], "after_files": [{"content": "# Copyright 2019 The Cirq Developers\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\nimport math\nfrom typing import (\n    List,\n    Union,\n    Optional,\n    Iterator,\n    Iterable,\n    cast,\n    Set,\n    Dict,\n    FrozenSet,\n)\n\nimport numpy as np\nimport sympy\nfrom cirq.google.api import v2\n\nSUPPORTED_FUNCTIONS_FOR_LANGUAGE: Dict[Optional[str], FrozenSet[str]] = {\n    '': frozenset(),\n    'linear': frozenset({'add', 'mul'}),\n    'exp': frozenset({'add', 'mul', 'pow'}),\n    # None means any. Is used when inferring the language during serialization.\n    None: frozenset({'add', 'mul', 'pow'}),\n}\n\nSUPPORTED_SYMPY_OPS = (sympy.Symbol, sympy.Add, sympy.Mul, sympy.Pow)\n\n# Argument types for gates.\nARG_LIKE = Union[int, float, List[bool], str, sympy.Symbol, sympy.Add, sympy.\n                 Mul]\n\n# Supported function languages in order from least to most flexible.\n# Clients should use the least flexible language they can, to make it easier\n# to gradually roll out new capabilities to clients and servers.\nLANGUAGE_ORDER = [\n    '',\n    'linear',\n    'exp',\n]\n\n\ndef _max_lang(langs: Iterable[str]) -> str:\n    i = max((LANGUAGE_ORDER.index(e) for e in langs), default=0)\n    return LANGUAGE_ORDER[i]\n\n\ndef _infer_function_language_from_circuit(value: v2.program_pb2.Circuit) -> str:\n    return _max_lang({\n        e for moment in value.moments for op in moment.operations\n        for e in _function_languages_from_operation(op)\n    })\n\n\ndef _infer_function_language_from_schedule(value: v2.program_pb2.Schedule\n                                          ) -> str:\n    return _max_lang({\n        e for op in value.scheduled_operations\n        for e in _function_languages_from_operation(op.operation)\n    })\n\n\ndef _function_languages_from_operation(value: v2.program_pb2.Operation\n                                      ) -> Iterator[str]:\n    for arg in value.args.values():\n        yield from _function_languages_from_arg(arg)\n\n\ndef _function_languages_from_arg(arg_proto: v2.program_pb2.Arg\n                                ) -> Iterator[str]:\n\n    which = arg_proto.WhichOneof('arg')\n    if which == 'func':\n        if arg_proto.func.type in ['add', 'mul']:\n            yield 'linear'\n            for a in arg_proto.func.args:\n                yield from _function_languages_from_arg(a)\n        if arg_proto.func.type in ['pow']:\n            yield 'exp'\n            for a in arg_proto.func.args:\n                yield from _function_languages_from_arg(a)\n\n\ndef _arg_to_proto(value: ARG_LIKE,\n                  *,\n                  arg_function_language: Optional[str],\n                  out: Optional[v2.program_pb2.Arg] = None\n                 ) -> v2.program_pb2.Arg:\n    \"\"\"Writes an argument value into an Arg proto.\n\n    Args:\n        value: The value to encode.\n        arg_function_language: The language to use when encoding functions. If\n            this is set to None, it will be set to the minimal language\n            necessary to support the features that were actually used.\n        out: The proto to write the result into. Defaults to a new instance.\n\n    Returns:\n        The proto that was written into as well as the `arg_function_language`\n        that was used.\n    \"\"\"\n\n    if arg_function_language not in SUPPORTED_FUNCTIONS_FOR_LANGUAGE:\n        raise ValueError(f'Unrecognized arg_function_language: '\n                         f'{arg_function_language!r}')\n    supported = SUPPORTED_FUNCTIONS_FOR_LANGUAGE[arg_function_language]\n\n    msg = v2.program_pb2.Arg() if out is None else out\n\n    def check_support(func_type: str) -> str:\n        if func_type not in supported:\n            lang = (repr(arg_function_language)\n                    if arg_function_language is not None else '[any]')\n            raise ValueError(f'Function type {func_type!r} not supported by '\n                             f'arg_function_language {lang}')\n        return func_type\n\n    if isinstance(value, (float, int, sympy.Integer, sympy.Float,\n                          sympy.Rational, sympy.NumberSymbol)):\n        msg.arg_value.float_value = float(value)\n    elif isinstance(value, str):\n        msg.arg_value.string_value = value\n    elif (isinstance(value, (list, tuple, np.ndarray)) and\n          all(isinstance(x, (bool, np.bool_)) for x in value)):\n        # Some protobuf / numpy combinations do not support np.bool_, so cast.\n        msg.arg_value.bool_values.values.extend([bool(x) for x in value])\n    elif isinstance(value, sympy.Symbol):\n        msg.symbol = str(value.free_symbols.pop())\n    elif isinstance(value, sympy.Add):\n        msg.func.type = check_support('add')\n        for arg in value.args:\n            _arg_to_proto(arg,\n                          arg_function_language=arg_function_language,\n                          out=msg.func.args.add())\n    elif isinstance(value, sympy.Mul):\n        msg.func.type = check_support('mul')\n        for arg in value.args:\n            _arg_to_proto(arg,\n                          arg_function_language=arg_function_language,\n                          out=msg.func.args.add())\n    elif isinstance(value, sympy.Pow):\n        msg.func.type = check_support('pow')\n        for arg in value.args:\n            _arg_to_proto(arg,\n                          arg_function_language=arg_function_language,\n                          out=msg.func.args.add())\n    else:\n        raise ValueError(f'Unrecognized arg type: {type(value)}')\n\n    return msg\n\n\ndef _arg_from_proto(\n        arg_proto: v2.program_pb2.Arg,\n        *,\n        arg_function_language: str,\n        required_arg_name: Optional[str] = None,\n) -> Optional[ARG_LIKE]:\n    \"\"\"Extracts a python value from an argument value proto.\n\n    Args:\n        arg_proto: The proto containing a serialized value.\n        arg_function_language: The `arg_function_language` field from\n            `Program.Language`.\n        required_arg_name: If set to `None`, the method will return `None` when\n            given an unset proto value. If set to a string, the method will\n            instead raise an error complaining that the value is missing in that\n            situation.\n\n    Returns:\n        The deserialized value, or else None if there was no set value and\n        `required_arg_name` was set to `None`.\n    \"\"\"\n    supported = SUPPORTED_FUNCTIONS_FOR_LANGUAGE.get(arg_function_language)\n    if supported is None:\n        raise ValueError(f'Unrecognized arg_function_language: '\n                         f'{arg_function_language!r}')\n\n    which = arg_proto.WhichOneof('arg')\n    if which == 'arg_value':\n        arg_value = arg_proto.arg_value\n        which_val = arg_value.WhichOneof('arg_value')\n        if which_val == 'float_value' or which_val == 'double_value':\n            if which_val == 'double_value':\n                result = float(arg_value.double_value)\n            else:\n                result = float(arg_value.float_value)\n            if math.ceil(result) == math.floor(result):\n                result = int(result)\n            return result\n        if which_val == 'bool_values':\n            return list(arg_value.bool_values.values)\n        if which_val == 'string_value':\n            return str(arg_value.string_value)\n        raise ValueError(f'Unrecognized value type: {which_val!r}')\n\n    if which == 'symbol':\n        return sympy.Symbol(arg_proto.symbol)\n\n    if which == 'func':\n        func = arg_proto.func\n\n        if func.type not in cast(Set[str], supported):\n            raise ValueError(\n                f'Unrecognized function type {func.type!r} '\n                f'for arg_function_language={arg_function_language!r}')\n\n        if func.type == 'add':\n            return sympy.Add(*[\n                _arg_from_proto(a,\n                                arg_function_language=arg_function_language,\n                                required_arg_name='An addition argument')\n                for a in func.args\n            ])\n\n        if func.type == 'mul':\n            return sympy.Mul(*[\n                _arg_from_proto(a,\n                                arg_function_language=arg_function_language,\n                                required_arg_name='A multiplication argument')\n                for a in func.args\n            ])\n\n        if func.type == 'pow':\n            return sympy.Pow(*[\n                _arg_from_proto(a,\n                                arg_function_language=arg_function_language,\n                                required_arg_name='A power argument')\n                for a in func.args\n            ])\n\n    if required_arg_name is not None:\n        raise ValueError(\n            f'{required_arg_name} is missing or has an unrecognized '\n            f'argument type (WhichOneof(\"arg\")={which!r}).')\n\n    return None\n", "path": "cirq/google/arg_func_langs.py"}]}