classiq 0.90.0__py3-none-any.whl → 0.91.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of classiq might be problematic. Click here for more details.

Files changed (41) hide show
  1. classiq/evaluators/expression_evaluator.py +24 -124
  2. classiq/evaluators/qmod_expression_visitors/qmod_expression_simplifier.py +10 -3
  3. classiq/evaluators/qmod_node_evaluators/utils.py +0 -8
  4. classiq/interface/_version.py +1 -1
  5. classiq/interface/executor/result.py +22 -3
  6. classiq/interface/generator/expressions/expression_types.py +2 -0
  7. classiq/interface/generator/expressions/proxies/classical/classical_array_proxy.py +3 -8
  8. classiq/interface/generator/functions/classical_type.py +2 -5
  9. classiq/interface/generator/functions/type_name.py +0 -12
  10. classiq/interface/model/quantum_type.py +0 -39
  11. classiq/model_expansions/capturing/captured_vars.py +3 -0
  12. classiq/model_expansions/function_builder.py +18 -2
  13. classiq/model_expansions/interpreters/frontend_generative_interpreter.py +0 -10
  14. classiq/model_expansions/interpreters/generative_interpreter.py +63 -18
  15. classiq/model_expansions/quantum_operations/emitter.py +13 -3
  16. classiq/model_expansions/quantum_operations/expression_evaluator.py +49 -5
  17. classiq/model_expansions/scope.py +5 -14
  18. classiq/model_expansions/utils/handles_collector.py +7 -0
  19. classiq/qmod/builtins/operations.py +7 -3
  20. classiq/qmod/qmod_variable.py +3 -4
  21. classiq/qmod/semantics/error_manager.py +34 -15
  22. classiq/qmod/symbolic.py +15 -4
  23. classiq/qmod/utilities.py +4 -1
  24. classiq/synthesis.py +1 -2
  25. {classiq-0.90.0.dist-info → classiq-0.91.0.dist-info}/METADATA +1 -1
  26. {classiq-0.90.0.dist-info → classiq-0.91.0.dist-info}/RECORD +27 -41
  27. classiq/interface/generator/expressions/handle_identifier.py +0 -6
  28. classiq/interface/generator/expressions/proxies/classical/any_classical_value.py +0 -41
  29. classiq/interface/generator/expressions/proxies/quantum/__init__.py +0 -0
  30. classiq/interface/generator/expressions/proxies/quantum/qmod_qarray_proxy.py +0 -80
  31. classiq/interface/generator/expressions/proxies/quantum/qmod_qscalar_proxy.py +0 -77
  32. classiq/interface/generator/expressions/proxies/quantum/qmod_qstruct_proxy.py +0 -38
  33. classiq/interface/generator/expressions/proxies/quantum/qmod_sized_proxy.py +0 -39
  34. classiq/interface/generator/expressions/type_proxy.py +0 -10
  35. classiq/model_expansions/atomic_expression_functions_defs.py +0 -395
  36. classiq/model_expansions/model_tables.py +0 -18
  37. classiq/model_expansions/sympy_conversion/__init__.py +0 -0
  38. classiq/model_expansions/sympy_conversion/expression_to_sympy.py +0 -181
  39. classiq/model_expansions/sympy_conversion/sympy_to_python.py +0 -136
  40. classiq/model_expansions/utils/sympy_utils.py +0 -24
  41. {classiq-0.90.0.dist-info → classiq-0.91.0.dist-info}/WHEEL +0 -0
@@ -1,395 +0,0 @@
1
- from collections.abc import Mapping
2
- from enum import Enum
3
- from typing import Any, Callable, Union, get_args
4
-
5
- import sympy
6
- from sympy import Eq, Expr, Piecewise, Symbol
7
-
8
- from classiq.interface.exceptions import (
9
- ClassiqExpansionError,
10
- ClassiqInternalExpansionError,
11
- )
12
- from classiq.interface.generator.expressions.atomic_expression_functions import (
13
- MEASUREMENT_FUNCTIONS,
14
- )
15
- from classiq.interface.generator.expressions.expression_types import (
16
- ExpressionValue,
17
- QmodStructInstance,
18
- RuntimeConstant,
19
- )
20
- from classiq.interface.generator.expressions.proxies.classical.any_classical_value import (
21
- AnyClassicalValue,
22
- )
23
- from classiq.interface.generator.expressions.proxies.classical.classical_array_proxy import (
24
- ClassicalArrayProxy,
25
- ClassicalSequenceProxy,
26
- )
27
- from classiq.interface.generator.expressions.proxies.classical.classical_proxy import (
28
- ClassicalProxy,
29
- )
30
- from classiq.interface.generator.expressions.proxies.quantum.qmod_qscalar_proxy import (
31
- QmodQNumProxy,
32
- )
33
- from classiq.interface.generator.expressions.proxies.quantum.qmod_qstruct_proxy import (
34
- QmodQStructProxy,
35
- )
36
- from classiq.interface.generator.expressions.proxies.quantum.qmod_sized_proxy import (
37
- QmodSizedProxy,
38
- )
39
- from classiq.interface.generator.expressions.type_proxy import TypeProxy
40
- from classiq.interface.generator.functions.classical_function_declaration import (
41
- ClassicalFunctionDeclaration,
42
- )
43
- from classiq.interface.generator.functions.classical_type import (
44
- Bool,
45
- ClassicalArray,
46
- ClassicalTuple,
47
- ClassicalType,
48
- Real,
49
- )
50
- from classiq.interface.generator.functions.type_name import TypeName
51
- from classiq.interface.helpers.backward_compatibility import zip_strict
52
-
53
- from classiq.evaluators.qmod_annotated_expression import QmodAnnotatedExpression
54
- from classiq.evaluators.qmod_expression_visitors.sympy_wrappers import (
55
- BitwiseAnd,
56
- BitwiseNot,
57
- BitwiseOr,
58
- BitwiseXor,
59
- LogicalXor,
60
- LShift,
61
- RShift,
62
- )
63
- from classiq.model_expansions.sympy_conversion.expression_to_sympy import (
64
- MISSING_SLICE_VALUE_PLACEHOLDER,
65
- )
66
- from classiq.model_expansions.sympy_conversion.sympy_to_python import (
67
- sympy_to_python,
68
- )
69
- from classiq.model_expansions.utils.sympy_utils import is_constant_subscript
70
- from classiq.qmod.builtins.classical_functions import (
71
- __all__ as qmod_classical_functions,
72
- )
73
- from classiq.qmod.model_state_container import QMODULE
74
- from classiq.qmod.utilities import qmod_val_to_expr_str
75
-
76
-
77
- def qmod_val_to_python(val: ExpressionValue, qmod_type: ClassicalType) -> Any:
78
- if isinstance(qmod_type, TypeName):
79
- if (
80
- isinstance(val, QmodStructInstance)
81
- and val.struct_declaration == QMODULE.type_decls[qmod_type.name]
82
- ):
83
- return {
84
- field_name: qmod_val_to_python(val.fields[field_name], field_type)
85
- for field_name, field_type in val.struct_declaration.variables.items()
86
- }
87
-
88
- if isinstance(val, (Enum, int)):
89
- return val
90
-
91
- elif isinstance(qmod_type, ClassicalArray):
92
- if isinstance(val, list):
93
- return [qmod_val_to_python(elem, qmod_type.element_type) for elem in val]
94
-
95
- elif isinstance(qmod_type, ClassicalTuple):
96
- if isinstance(val, list):
97
- return [
98
- qmod_val_to_python(elem, elem_type)
99
- for elem_type, elem in zip_strict(
100
- qmod_type.element_types, val, strict=True
101
- )
102
- ]
103
-
104
- elif isinstance(val, Expr):
105
- return sympy_to_python(val)
106
-
107
- elif isinstance(qmod_type, Real):
108
- if isinstance(val, (float, int)):
109
- return val
110
-
111
- elif isinstance(qmod_type, Bool):
112
- if isinstance(val, bool):
113
- return val
114
-
115
- elif isinstance(val, int): # other scalars are represented as int
116
- return val
117
-
118
- raise ClassiqInternalExpansionError(
119
- f"Bad value {val!r} of type {type(val)!r} for {qmod_type!r}"
120
- )
121
-
122
-
123
- def python_val_to_qmod(val: Any, qmod_type: ClassicalType) -> ExpressionValue:
124
- if isinstance(qmod_type, TypeName):
125
- if qmod_type.name in QMODULE.enum_decls:
126
- return val
127
-
128
- struct_decl = QMODULE.type_decls[qmod_type.name]
129
- if not isinstance(val, Mapping):
130
- raise ClassiqInternalExpansionError(
131
- f"Bad value for struct {struct_decl.name}"
132
- )
133
- qmod_dict = {
134
- field_name: python_val_to_qmod(val[field_name], field_type)
135
- for field_name, field_type in struct_decl.variables.items()
136
- }
137
- return QmodStructInstance(struct_decl.model_copy(deep=True), qmod_dict)
138
-
139
- if isinstance(qmod_type, ClassicalArray):
140
- if not isinstance(val, list):
141
- raise ClassiqInternalExpansionError("Bad value for list")
142
- return [python_val_to_qmod(elem, qmod_type.element_type) for elem in val]
143
-
144
- if isinstance(qmod_type, ClassicalTuple):
145
- if not isinstance(val, list):
146
- raise ClassiqInternalExpansionError("Bad value for list")
147
- return [
148
- python_val_to_qmod(elem, elem_type)
149
- for elem, elem_type in zip_strict(val, qmod_type.element_types, strict=True)
150
- ]
151
-
152
- return val
153
-
154
-
155
- def python_call_wrapper(func: Callable, *args: ExpressionValue) -> Any:
156
- func_decl = ClassicalFunctionDeclaration.FOREIGN_FUNCTION_DECLARATIONS[
157
- func.__name__
158
- ]
159
- python_args = [
160
- qmod_val_to_python(args[idx], param_type.classical_type)
161
- for idx, param_type in enumerate(func_decl.param_decls)
162
- ]
163
- assert func_decl.return_type is not None
164
- return python_val_to_qmod(func(*python_args), func_decl.return_type)
165
-
166
-
167
- def struct_literal(struct_type_symbol: Symbol, **kwargs: Any) -> QmodStructInstance:
168
- return QmodStructInstance(
169
- QMODULE.type_decls[struct_type_symbol.name].model_copy(deep=True),
170
- {field: sympy_to_python(field_value) for field, field_value in kwargs.items()},
171
- )
172
-
173
-
174
- def get_field(
175
- proxy: Union[
176
- QmodSizedProxy, QmodStructInstance, list, ClassicalProxy, AnyClassicalValue
177
- ],
178
- field: str,
179
- ) -> Any:
180
- if isinstance(proxy, AnyClassicalValue) or (
181
- isinstance(proxy, Symbol)
182
- and not isinstance(proxy, QmodSizedProxy)
183
- and not isinstance(proxy, ClassicalProxy)
184
- ):
185
- return AnyClassicalValue(f"get_field({qmod_val_to_expr_str(proxy)}, '{field}')")
186
- if isinstance(proxy, type) and issubclass(proxy, Enum):
187
- return getattr(proxy, field)
188
- if isinstance(proxy, list):
189
- if field != "len":
190
- raise ClassiqExpansionError(
191
- f"List {str(proxy)!r} has no attribute {field!r}. "
192
- f"Available attributes: len"
193
- )
194
- return len(proxy)
195
- if not isinstance(
196
- proxy, (QmodSizedProxy, QmodStructInstance, ClassicalProxy, AnyClassicalValue)
197
- ):
198
- raise ClassiqExpansionError(
199
- f"Object {str(proxy)!r} has not attribute {field!r}"
200
- )
201
- if field not in proxy.fields:
202
- if isinstance(proxy, (QmodStructInstance, QmodQStructProxy)):
203
- property_name = "field"
204
- else:
205
- property_name = "attribute"
206
- suffix = (
207
- f". Available {property_name}s: {', '.join(proxy.fields.keys())}"
208
- if len(proxy.fields) > 0
209
- else ""
210
- )
211
- proxy_str = proxy.__name__ if isinstance(proxy, type) else f"{str(proxy)!r}"
212
- raise ClassiqExpansionError(
213
- f"{proxy.type_name} {proxy_str} has no {property_name} {field!r}{suffix}"
214
- )
215
- return proxy.fields[field]
216
-
217
-
218
- def get_type(struct_type: Symbol) -> TypeProxy:
219
- return TypeProxy(QMODULE.type_decls[struct_type.name])
220
-
221
-
222
- def do_div(lhs: Any, rhs: Any) -> Any:
223
- res = lhs / rhs
224
- if isinstance(res, sympy.Expr):
225
- res = res.evalf()
226
- return res
227
-
228
-
229
- _EXPRESSION_TYPES = (*get_args(RuntimeConstant), QmodAnnotatedExpression)
230
-
231
-
232
- def _is_qmod_value(val: Any) -> bool:
233
- if not isinstance(val, slice):
234
- return isinstance(val, _EXPRESSION_TYPES)
235
- if val.start is not None and not isinstance(val.start, _EXPRESSION_TYPES):
236
- return False
237
- if val.stop is not None and not isinstance(val.stop, _EXPRESSION_TYPES):
238
- return False
239
- return val.step is None or isinstance(val.step, _EXPRESSION_TYPES)
240
-
241
-
242
- def do_subscript(value: Any, index: Any) -> Any:
243
- if not isinstance(value, (list, ClassicalSequenceProxy)) or not isinstance(
244
- index, QmodQNumProxy
245
- ):
246
- if isinstance(index, (QmodSizedProxy, QmodStructInstance)):
247
- raise ClassiqExpansionError(
248
- f"Subscript {value}[{index}] is not supported. Supported subscripts "
249
- f"include:\n"
250
- f"\t1. `qbv[idx]`, where `qbv` is a quantum array and `idx` is a "
251
- f"classical integer.\n"
252
- f"\t2. `l[n]`, where `l` is a list of classical real numbers and `n` "
253
- f"is a classical or quantum integer."
254
- )
255
- if (
256
- isinstance(value, list)
257
- and not is_constant_subscript(index)
258
- and _is_qmod_value(index)
259
- ):
260
- return AnyClassicalValue(qmod_val_to_expr_str(value))[index]
261
- return value[index]
262
- if index.is_signed or index.fraction_digits > 0:
263
- raise ClassiqExpansionError(
264
- "Quantum numeric subscript must be an unsigned integer (is_signed=False, "
265
- "fraction_digits=0)"
266
- )
267
- if isinstance(value, ClassicalSequenceProxy):
268
- length = value.length
269
- else:
270
- length = len(value)
271
- if not isinstance(length, sympy.Basic) and length != 2**index.size:
272
- raise ClassiqExpansionError(
273
- f"Quantum numeric subscript size mismatch: The quantum numeric has "
274
- f"{index.size} qubits but the list size is {length} != 2**{index.size}"
275
- )
276
- if isinstance(value, ClassicalSequenceProxy):
277
- return AnyClassicalValue(
278
- f"do_subscript({qmod_val_to_expr_str(value)}, {qmod_val_to_expr_str(index)})"
279
- )
280
- else:
281
- return Piecewise(
282
- *[(item, Eq(index, idx)) for idx, item in enumerate(value[:-1])],
283
- (value[-1], True),
284
- )
285
-
286
-
287
- def do_slice(value: Any, lower: Any, upper: Any) -> Any:
288
- if isinstance(lower, Symbol) and str(lower) == MISSING_SLICE_VALUE_PLACEHOLDER:
289
- lower = None
290
- if isinstance(upper, Symbol) and str(upper) == MISSING_SLICE_VALUE_PLACEHOLDER:
291
- upper = None
292
- return do_subscript(value, slice(lower, upper))
293
-
294
-
295
- def do_sum(val: Any) -> Any:
296
- if (isinstance(val, sympy.Basic) and len(val.free_symbols) > 0) or (
297
- isinstance(val, ClassicalArrayProxy) and not isinstance(val.length, int)
298
- ):
299
- return AnyClassicalValue(f"sum({val})")
300
- return sum(val)
301
-
302
-
303
- do_sum.__name__ = "sum"
304
-
305
-
306
- def mod_inverse(a: Any, b: Any) -> Any:
307
- if (
308
- isinstance(a, AnyClassicalValue)
309
- or (isinstance(a, sympy.Basic) and len(a.free_symbols) > 0)
310
- or isinstance(b, AnyClassicalValue)
311
- or (isinstance(b, sympy.Basic) and len(b.free_symbols) > 0)
312
- ):
313
- return AnyClassicalValue(f"mod_inverse({a}, {b})")
314
- return sympy.mod_inverse(a, b)
315
-
316
-
317
- def min_wrapper(*vals: Any) -> Any:
318
- try:
319
- return sympy.Min(*vals)
320
- except ValueError:
321
- return AnyClassicalValue(f"Min({', '.join(map(str, vals))})")
322
-
323
-
324
- min_wrapper.__name__ = "min"
325
-
326
-
327
- def Min_wrapper(*vals: Any) -> Any: # noqa: N802
328
- return min_wrapper(*vals)
329
-
330
-
331
- Min_wrapper.__name__ = "Min"
332
-
333
-
334
- def max_wrapper(*vals: Any) -> Any:
335
- try:
336
- return sympy.Max(*vals)
337
- except ValueError:
338
- return AnyClassicalValue(f"Max({', '.join(map(str, vals))})")
339
-
340
-
341
- max_wrapper.__name__ = "max"
342
-
343
-
344
- def Max_wrapper(*vals: Any) -> Any: # noqa: N802
345
- return max_wrapper(*vals)
346
-
347
-
348
- Max_wrapper.__name__ = "Max"
349
-
350
-
351
- CORE_LIB_FUNCTIONS_LIST: list[Callable] = [
352
- print,
353
- do_sum,
354
- struct_literal,
355
- get_field,
356
- get_type,
357
- do_div,
358
- do_slice,
359
- do_subscript,
360
- BitwiseAnd,
361
- BitwiseXor,
362
- BitwiseNot,
363
- BitwiseOr,
364
- LogicalXor,
365
- RShift,
366
- LShift,
367
- mod_inverse,
368
- min_wrapper,
369
- Min_wrapper,
370
- max_wrapper,
371
- Max_wrapper,
372
- ]
373
-
374
-
375
- def _symbolic_function(func: str) -> Callable:
376
- def wrapper(*args: Any) -> AnyClassicalValue:
377
- return AnyClassicalValue(
378
- f"{func}({', '.join(map(qmod_val_to_expr_str, args))})"
379
- )
380
-
381
- wrapper.__name__ = func
382
- return wrapper
383
-
384
-
385
- QMOD_CLASSICAL_FUNCTIONS = [
386
- _symbolic_function(func)
387
- for func in qmod_classical_functions + list(MEASUREMENT_FUNCTIONS)
388
- ]
389
-
390
- ATOMIC_EXPRESSION_FUNCTIONS = {
391
- **{
392
- core_func.__name__: core_func
393
- for core_func in CORE_LIB_FUNCTIONS_LIST + QMOD_CLASSICAL_FUNCTIONS
394
- },
395
- }
@@ -1,18 +0,0 @@
1
- from typing import Optional
2
-
3
- from classiq.interface.generator.expressions.handle_identifier import HandleIdentifier
4
- from classiq.interface.generator.functions.classical_type import QmodPyObject
5
-
6
-
7
- class HandleTable:
8
- _handle_map: dict[HandleIdentifier, QmodPyObject] = {}
9
-
10
- @classmethod
11
- def get_handle_object(cls, hid: HandleIdentifier) -> Optional[QmodPyObject]:
12
- return cls._handle_map.get(hid)
13
-
14
- @classmethod
15
- def set_handle_object(cls, qmod_object: QmodPyObject) -> HandleIdentifier:
16
- hid = HandleIdentifier(id(qmod_object))
17
- cls._handle_map[hid] = qmod_object
18
- return hid
File without changes
@@ -1,181 +0,0 @@
1
- import ast
2
- from typing import TYPE_CHECKING, cast
3
-
4
- from classiq.interface.exceptions import ClassiqExpansionError
5
-
6
- MISSING_SLICE_VALUE_PLACEHOLDER = "MISSING_SLICE_VALUE"
7
-
8
-
9
- def translate_to_sympy(expr: str) -> str:
10
- node = ast.parse(expr)
11
- node = ExpressionSympyTranslator().visit(node)
12
- # node is a Module, we want an Expression
13
- if TYPE_CHECKING:
14
- assert isinstance(node.body[0], ast.Expr)
15
- expression = ast.Expression(node.body[0].value)
16
-
17
- return ast.unparse(ast.fix_missing_locations(expression))
18
-
19
-
20
- class ExpressionSympyTranslator(ast.NodeTransformer):
21
- BINARY_OPERATORS: dict[type[ast.AST], str] = {
22
- ast.BitOr: "BitwiseOr",
23
- ast.BitAnd: "BitwiseAnd",
24
- ast.BitXor: "BitwiseXor",
25
- ast.Div: "do_div",
26
- ast.RShift: "RShift",
27
- ast.LShift: "LShift",
28
- }
29
-
30
- UNARY_OPERATORS: dict[type[ast.AST], str] = {
31
- ast.Invert: "BitwiseNot",
32
- ast.Not: "Not",
33
- }
34
-
35
- BOOLEAN_OPERATORS: dict[type[ast.AST], str] = {
36
- ast.Or: "Or",
37
- ast.And: "And",
38
- }
39
-
40
- COMPARE_OPERATORS: dict[type[ast.AST], str] = {
41
- ast.Eq: "Eq",
42
- ast.NotEq: "Ne",
43
- }
44
-
45
- SPECIAL_FUNCTIONS: dict[str, str] = {
46
- "max": "Max",
47
- "min": "Min",
48
- }
49
-
50
- def visit_BinOp(self, node: ast.BinOp) -> ast.AST:
51
- sympy_class = self.BINARY_OPERATORS.get(node.op.__class__)
52
- if sympy_class is not None:
53
- left = self.visit(node.left)
54
- right = self.visit(node.right)
55
-
56
- new_node = ast.Call(
57
- func=ast.Name(id=sympy_class, ctx=ast.Load()),
58
- args=[left, right],
59
- starargs=None,
60
- keywords=[],
61
- kwargs=None,
62
- )
63
-
64
- return new_node
65
- return self.generic_visit(node)
66
-
67
- def visit_Compare(self, node: ast.Compare) -> ast.AST:
68
- if len(node.ops) > 1:
69
- raise ClassiqExpansionError(
70
- f"Qmod expressions do not support chained comparison, as done in {ast.unparse(node)}"
71
- )
72
- sympy_class = self.COMPARE_OPERATORS.get(node.ops[0].__class__)
73
- if sympy_class is not None:
74
- left = self.visit(node.left)
75
- right = self.visit(node.comparators[0])
76
-
77
- new_node = ast.Call(
78
- func=ast.Name(id=sympy_class, ctx=ast.Load()),
79
- args=[left, right],
80
- starargs=None,
81
- keywords=[],
82
- kwargs=None,
83
- )
84
-
85
- return new_node
86
- return self.generic_visit(node)
87
-
88
- def visit_BoolOp(self, node: ast.BoolOp) -> ast.AST:
89
- sympy_class = self.BOOLEAN_OPERATORS.get(node.op.__class__)
90
- if sympy_class is not None:
91
- values = [self.visit(value) for value in node.values]
92
-
93
- new_node = ast.Call(
94
- func=ast.Name(id=sympy_class, ctx=ast.Load()),
95
- args=values,
96
- starargs=None,
97
- keywords=[],
98
- kwargs=None,
99
- )
100
-
101
- return new_node
102
- return self.generic_visit(node)
103
-
104
- def visit_UnaryOp(self, node: ast.UnaryOp) -> ast.AST:
105
- sympy_class = self.UNARY_OPERATORS.get(node.op.__class__)
106
- if sympy_class is not None:
107
- operand = self.visit(node.operand)
108
-
109
- new_node = ast.Call(
110
- func=ast.Name(id=sympy_class, ctx=ast.Load()),
111
- args=[operand],
112
- starargs=None,
113
- keywords=[],
114
- kwargs=None,
115
- )
116
-
117
- return new_node
118
- return self.generic_visit(node)
119
-
120
- def visit_Call(self, node: ast.Call) -> ast.AST:
121
- if isinstance(node.func, ast.Name) and node.func.id == "Piecewise":
122
- return self._visit_piecewise(node)
123
-
124
- if (
125
- not isinstance(node.func, ast.Name)
126
- or node.func.id not in self.SPECIAL_FUNCTIONS
127
- ):
128
- return self.generic_visit(node)
129
-
130
- return ast.Call(
131
- func=ast.Name(self.SPECIAL_FUNCTIONS[node.func.id]),
132
- args=[self.visit(arg) for arg in (node.args)],
133
- keywords=[self.visit(arg) for arg in node.keywords],
134
- )
135
-
136
- def _visit_piecewise(self, node: ast.Call) -> ast.AST:
137
- # sympy Piecewise expression may include bitwise operations:
138
- # Piecewise((0, Eq(x, 0)), (0.5, Eq(x, 1) | Eq(x, 2)), (1, True))
139
- # ^
140
- # We should avoid converting these to 'BitwiseOr' and such.
141
- return ast.Call(
142
- func=node.func,
143
- args=[
144
- ast.Tuple(
145
- elts=(
146
- self.generic_visit(cast(ast.Tuple, arg).elts[0]),
147
- cast(ast.Tuple, arg).elts[1],
148
- )
149
- )
150
- for arg in node.args
151
- ],
152
- keywords=node.keywords,
153
- )
154
-
155
- def visit_Subscript(self, node: ast.Subscript) -> ast.AST:
156
- if isinstance(node.slice, ast.Slice):
157
- if node.slice.lower is not None:
158
- lower = self.visit(node.slice.lower)
159
- else:
160
- lower = ast.Name(MISSING_SLICE_VALUE_PLACEHOLDER)
161
- if node.slice.upper is not None:
162
- upper = self.visit(node.slice.upper)
163
- else:
164
- upper = ast.Name(MISSING_SLICE_VALUE_PLACEHOLDER)
165
- return ast.Call(
166
- func=ast.Name("do_slice"),
167
- args=[self.visit(node.value), lower, upper],
168
- keywords=[],
169
- )
170
- return ast.Call(
171
- func=ast.Name("do_subscript"),
172
- args=[self.visit(node.value), self.visit(node.slice)],
173
- keywords=[],
174
- )
175
-
176
- def visit_Attribute(self, node: ast.Attribute) -> ast.Call:
177
- return ast.Call(
178
- func=ast.Name("get_field"),
179
- args=[self.visit(node.value), ast.Constant(value=node.attr)],
180
- keywords=[],
181
- )