classiq 0.40.0__py3-none-any.whl → 0.41.1__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.
Files changed (81) hide show
  1. classiq/__init__.py +4 -2
  2. classiq/_internals/api_wrapper.py +3 -21
  3. classiq/applications/chemistry/chemistry_model_constructor.py +86 -100
  4. classiq/applications/combinatorial_helpers/combinatorial_problem_utils.py +6 -24
  5. classiq/applications/combinatorial_helpers/pauli_helpers/pauli_utils.py +33 -45
  6. classiq/applications/combinatorial_optimization/__init__.py +2 -0
  7. classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py +29 -26
  8. classiq/applications/finance/finance_model_constructor.py +23 -26
  9. classiq/applications/grover/grover_model_constructor.py +37 -38
  10. classiq/applications/qsvm/qsvm.py +1 -2
  11. classiq/applications/qsvm/qsvm_model_constructor.py +15 -16
  12. classiq/execution/__init__.py +4 -0
  13. classiq/execution/execution_session.py +151 -0
  14. classiq/execution/qnn.py +80 -0
  15. classiq/executor.py +2 -109
  16. classiq/interface/_version.py +1 -1
  17. classiq/interface/analyzer/analysis_params.py +11 -0
  18. classiq/interface/applications/qsvm.py +0 -8
  19. classiq/interface/ast_node.py +12 -2
  20. classiq/interface/backend/backend_preferences.py +25 -1
  21. classiq/interface/backend/quantum_backend_providers.py +4 -4
  22. classiq/interface/executor/execution_preferences.py +4 -59
  23. classiq/interface/executor/execution_result.py +22 -1
  24. classiq/interface/generator/arith/arithmetic_expression_validator.py +0 -2
  25. classiq/interface/generator/arith/binary_ops.py +88 -25
  26. classiq/interface/generator/arith/unary_ops.py +28 -19
  27. classiq/interface/generator/expressions/atomic_expression_functions.py +6 -2
  28. classiq/interface/generator/expressions/enums/__init__.py +10 -0
  29. classiq/interface/generator/expressions/enums/classical_enum.py +5 -1
  30. classiq/interface/generator/expressions/expression.py +9 -2
  31. classiq/interface/generator/expressions/qmod_qarray_proxy.py +7 -0
  32. classiq/interface/generator/expressions/qmod_qscalar_proxy.py +0 -1
  33. classiq/interface/generator/expressions/sympy_supported_expressions.py +10 -1
  34. classiq/interface/generator/functions/builtins/internal_operators.py +7 -62
  35. classiq/interface/generator/functions/builtins/open_lib_functions.py +810 -2
  36. classiq/interface/generator/functions/classical_type.py +1 -3
  37. classiq/interface/generator/synthesis_metadata/synthesis_duration.py +0 -4
  38. classiq/interface/model/bind_operation.py +3 -1
  39. classiq/interface/model/call_synthesis_data.py +2 -13
  40. classiq/interface/model/classical_if.py +3 -1
  41. classiq/interface/model/classical_parameter_declaration.py +13 -0
  42. classiq/interface/model/control.py +3 -101
  43. classiq/interface/model/inplace_binary_operation.py +3 -1
  44. classiq/interface/model/invert.py +3 -1
  45. classiq/interface/model/port_declaration.py +8 -1
  46. classiq/interface/model/power.py +3 -1
  47. classiq/interface/model/quantum_expressions/amplitude_loading_operation.py +4 -2
  48. classiq/interface/model/quantum_expressions/arithmetic_operation.py +3 -1
  49. classiq/interface/model/quantum_expressions/quantum_expression.py +11 -1
  50. classiq/interface/model/quantum_function_call.py +4 -10
  51. classiq/interface/model/quantum_function_declaration.py +26 -4
  52. classiq/interface/model/quantum_lambda_function.py +1 -20
  53. classiq/interface/model/quantum_statement.py +9 -2
  54. classiq/interface/model/repeat.py +3 -1
  55. classiq/interface/model/statement_block.py +19 -13
  56. classiq/interface/model/validations/handles_validator.py +8 -2
  57. classiq/interface/model/variable_declaration_statement.py +3 -1
  58. classiq/interface/model/within_apply_operation.py +3 -1
  59. classiq/interface/server/routes.py +0 -5
  60. classiq/qmod/__init__.py +1 -2
  61. classiq/qmod/builtins/classical_execution_primitives.py +22 -2
  62. classiq/qmod/builtins/functions.py +51 -1
  63. classiq/qmod/builtins/operations.py +6 -36
  64. classiq/qmod/declaration_inferrer.py +8 -15
  65. classiq/qmod/native/__init__.py +9 -0
  66. classiq/qmod/native/expression_to_qmod.py +12 -9
  67. classiq/qmod/native/pretty_printer.py +4 -4
  68. classiq/qmod/pretty_print/__init__.py +9 -0
  69. classiq/qmod/pretty_print/expression_to_python.py +221 -0
  70. classiq/qmod/pretty_print/pretty_printer.py +421 -0
  71. classiq/qmod/qmod_parameter.py +7 -4
  72. classiq/qmod/quantum_callable.py +2 -1
  73. classiq/qmod/quantum_expandable.py +4 -3
  74. classiq/qmod/quantum_function.py +4 -16
  75. classiq/qmod/symbolic.py +1 -6
  76. classiq/synthesis.py +15 -16
  77. {classiq-0.40.0.dist-info → classiq-0.41.1.dist-info}/METADATA +5 -4
  78. {classiq-0.40.0.dist-info → classiq-0.41.1.dist-info}/RECORD +79 -76
  79. classiq/interface/model/common_model_types.py +0 -23
  80. classiq/interface/model/quantum_expressions/control_state.py +0 -38
  81. {classiq-0.40.0.dist-info → classiq-0.41.1.dist-info}/WHEEL +0 -0
@@ -14,9 +14,7 @@ from classiq.interface.generator.expressions.enums.pauli import Pauli as PauliEn
14
14
  from classiq.interface.generator.expressions.expression_types import RuntimeExpression
15
15
  from classiq.interface.helpers.pydantic_model_helpers import values_with_discriminator
16
16
 
17
- CLASSICAL_ATTRIBUTES = {
18
- "len": len,
19
- }
17
+ CLASSICAL_ATTRIBUTES = {"len", "size", "is_signed", "fraction_digits"}
20
18
 
21
19
  NamedSymbol = Union[IndexedBase, Symbol]
22
20
 
@@ -1,10 +1,7 @@
1
- from typing import Optional
2
-
3
1
  import pydantic
4
2
 
5
3
 
6
4
  class SynthesisStepDurations(pydantic.BaseModel):
7
- model_preprocessing: Optional[float] = None
8
5
  preprocessing: float
9
6
  solving: float
10
7
  conversion_to_circuit: float
@@ -14,7 +11,6 @@ class SynthesisStepDurations(pydantic.BaseModel):
14
11
  return sum(
15
12
  time if time is not None else 0
16
13
  for time in (
17
- self.model_preprocessing,
18
14
  self.preprocessing,
19
15
  self.solving,
20
16
  self.conversion_to_circuit,
@@ -1,4 +1,4 @@
1
- from typing import List, Mapping
1
+ from typing import List, Literal, Mapping
2
2
 
3
3
  import pydantic
4
4
 
@@ -12,6 +12,8 @@ BIND_OUTPUT_NAME = "bind_output"
12
12
 
13
13
 
14
14
  class BindOperation(QuantumOperation):
15
+ kind: Literal["BindOperation"]
16
+
15
17
  in_handles: List[HandleBinding]
16
18
  out_handles: List[HandleBinding]
17
19
 
@@ -36,24 +36,13 @@ class CallSynthesisData(Mapping):
36
36
  should_control=self.should_control and other.should_control,
37
37
  )
38
38
 
39
- def set_control(self, ctrl_name: str, ctrl_size: int) -> None:
39
+ def set_control(self, ctrl_name: str, ctrl_size: int, ctrl_state: str) -> None:
40
40
  self.control_states = [
41
41
  ControlState(
42
- name=ctrl_name,
43
- num_ctrl_qubits=ctrl_size,
42
+ name=ctrl_name, num_ctrl_qubits=ctrl_size, ctrl_state=ctrl_state
44
43
  )
45
44
  ]
46
45
 
47
- def update_control_state(self, ctrl_size: int, ctrl_state: str) -> None:
48
- prev_ctrl_state = self.control_states.pop()
49
- self.control_states.append(
50
- ControlState(
51
- name=prev_ctrl_state.name,
52
- num_ctrl_qubits=ctrl_size,
53
- ctrl_state=ctrl_state,
54
- )
55
- )
56
-
57
46
  @property
58
47
  def has_control(self) -> bool:
59
48
  return bool(self.control_states)
@@ -1,4 +1,4 @@
1
- from typing import TYPE_CHECKING
1
+ from typing import TYPE_CHECKING, Literal
2
2
 
3
3
  from classiq.interface.generator.expressions.expression import Expression
4
4
  from classiq.interface.model.quantum_statement import QuantumOperation
@@ -8,6 +8,8 @@ if TYPE_CHECKING:
8
8
 
9
9
 
10
10
  class ClassicalIf(QuantumOperation):
11
+ kind: Literal["ClassicalIf"]
12
+
11
13
  condition: Expression
12
14
  then: "StatementBlock"
13
15
  else_: "StatementBlock"
@@ -1,7 +1,20 @@
1
+ from typing import Any, Dict, Literal
2
+
3
+ import pydantic
4
+
1
5
  from classiq.interface.ast_node import ASTNode
2
6
  from classiq.interface.generator.functions.classical_type import ConcreteClassicalType
7
+ from classiq.interface.helpers.pydantic_model_helpers import values_with_discriminator
3
8
 
4
9
 
5
10
  class ClassicalParameterDeclaration(ASTNode):
11
+ kind: Literal["ClassicalParameterDeclaration"]
12
+
6
13
  name: str
7
14
  classical_type: ConcreteClassicalType
15
+
16
+ @pydantic.root_validator(pre=True)
17
+ def _set_kind(cls, values: Dict[str, Any]) -> Dict[str, Any]:
18
+ return values_with_discriminator(
19
+ values, "kind", "ClassicalParameterDeclaration"
20
+ )
@@ -1,112 +1,14 @@
1
- from typing import TYPE_CHECKING, Optional
1
+ from typing import TYPE_CHECKING, Literal
2
2
 
3
- import pydantic
4
- from sympy import Equality
5
- from sympy.core.numbers import Integer
6
-
7
- from classiq.interface.generator.expressions.expression import Expression
8
- from classiq.interface.generator.expressions.qmod_qscalar_proxy import (
9
- QmodQNumProxy,
10
- QmodSizedProxy,
11
- )
12
- from classiq.interface.model.quantum_expressions.control_state import (
13
- min_bit_length,
14
- to_twos_complement,
15
- )
16
3
  from classiq.interface.model.quantum_expressions.quantum_expression import (
17
4
  QuantumExpressionOperation,
18
5
  )
19
6
 
20
- from classiq.exceptions import ClassiqValueError
21
-
22
7
  if TYPE_CHECKING:
23
8
  from classiq.interface.model.statement_block import StatementBlock
24
9
 
25
- CONTROL_INOUT_NAME = "ctrl"
26
- CONTROL_CTRL_ARG_ERROR_MESSAGE_FORMAT = (
27
- "control condition must be of the form '<quantum-variable> == "
28
- "<classical-integer-expression>', but condition's {}-hand side was {!r}"
29
- )
30
-
31
10
 
32
11
  class Control(QuantumExpressionOperation):
33
- body: "StatementBlock"
34
- _ctrl: Optional[QmodSizedProxy] = pydantic.PrivateAttr(
35
- default=None,
36
- )
37
- _ctrl_val: Optional[int] = pydantic.PrivateAttr(
38
- default=None,
39
- )
40
-
41
- @property
42
- def condition(self) -> Expression:
43
- return self.expression
12
+ kind: Literal["Control"]
44
13
 
45
- @property
46
- def ctrl(self) -> QmodSizedProxy:
47
- assert self._ctrl is not None
48
- return self._ctrl
49
-
50
- @property
51
- def ctrl_val(self) -> int:
52
- assert self._ctrl_val is not None
53
- return self._ctrl_val
54
-
55
- def resolve_condition(self) -> None:
56
- condition = self.condition.value.value
57
- if isinstance(condition, QmodSizedProxy):
58
- self._resolve_port_condition(condition)
59
- elif isinstance(condition, Equality):
60
- self._resolve_num_condition(condition)
61
- else:
62
- raise ClassiqValueError(
63
- f"control condition must be a qubit, an array of qubits, or a quantum "
64
- f"numeric equality, was {str(condition)!r}"
65
- )
66
-
67
- def _resolve_port_condition(self, condition: QmodSizedProxy) -> None:
68
- self._ctrl = condition
69
-
70
- def _resolve_num_condition(self, condition: Equality) -> None:
71
- ctrl, ctrl_val = condition.args
72
- if isinstance(ctrl, Integer) and isinstance(ctrl_val, QmodQNumProxy):
73
- ctrl, ctrl_val = ctrl_val, ctrl
74
- if not isinstance(ctrl, QmodQNumProxy):
75
- raise ClassiqValueError(
76
- CONTROL_CTRL_ARG_ERROR_MESSAGE_FORMAT.format("left", str(ctrl))
77
- )
78
- if not isinstance(ctrl_val, Integer):
79
- raise ClassiqValueError(
80
- CONTROL_CTRL_ARG_ERROR_MESSAGE_FORMAT.format("right", str(ctrl_val))
81
- )
82
- self._ctrl, self._ctrl_val = ctrl, int(ctrl_val)
83
-
84
- @property
85
- def has_ctrl_state(self) -> bool:
86
- assert self._ctrl is not None
87
- return self._ctrl_val is not None
88
-
89
- @property
90
- def ctrl_state(self) -> str:
91
- ctrl = self.ctrl
92
- assert isinstance(ctrl, QmodQNumProxy)
93
- is_signed = ctrl.is_signed
94
- fraction_places = ctrl.fraction_digits
95
- ctrl_size = len(ctrl)
96
- if not is_signed and self.ctrl_val < 0:
97
- raise ClassiqValueError(
98
- f"Variable {str(ctrl)!r} is not signed but control value "
99
- f"{self.ctrl_val} is negative"
100
- )
101
- required_qubits = min_bit_length(self.ctrl_val, is_signed)
102
- if ctrl_size < required_qubits:
103
- raise ClassiqValueError(
104
- f"Variable {str(ctrl)!r} has {ctrl_size} qubits but control value "
105
- f"{str(self.ctrl_val)!r} requires at least {required_qubits} qubits"
106
- )
107
- if fraction_places != 0:
108
- raise ClassiqValueError(
109
- f"Comparison (`==`) on a non-integer quantum variable {str(ctrl)!r} is "
110
- f"not supported at the moment"
111
- )
112
- return to_twos_complement(self.ctrl_val, ctrl_size, is_signed)
14
+ body: "StatementBlock"
@@ -1,4 +1,4 @@
1
- from typing import Mapping
1
+ from typing import Literal, Mapping
2
2
 
3
3
  import pydantic
4
4
 
@@ -23,6 +23,8 @@ class BinaryOperation(StrEnum):
23
23
 
24
24
 
25
25
  class InplaceBinaryOperation(QuantumOperation):
26
+ kind: Literal["InplaceBinaryOperation"]
27
+
26
28
  target: HandleBinding
27
29
  value: HandleBinding
28
30
  operation: BinaryOperation
@@ -1,4 +1,4 @@
1
- from typing import TYPE_CHECKING
1
+ from typing import TYPE_CHECKING, Literal
2
2
 
3
3
  from classiq.interface.model.quantum_statement import QuantumOperation
4
4
 
@@ -7,4 +7,6 @@ if TYPE_CHECKING:
7
7
 
8
8
 
9
9
  class Invert(QuantumOperation):
10
+ kind: Literal["Invert"]
11
+
10
12
  body: "StatementBlock"
@@ -1,10 +1,11 @@
1
- from typing import Any, Mapping
1
+ from typing import Any, Dict, Literal, Mapping
2
2
 
3
3
  import pydantic
4
4
 
5
5
  from classiq.interface.generator.functions.port_declaration import (
6
6
  PortDeclarationDirection,
7
7
  )
8
+ from classiq.interface.helpers.pydantic_model_helpers import values_with_discriminator
8
9
  from classiq.interface.model.quantum_variable_declaration import (
9
10
  QuantumVariableDeclaration,
10
11
  )
@@ -13,8 +14,14 @@ from classiq.exceptions import ClassiqValueError
13
14
 
14
15
 
15
16
  class PortDeclaration(QuantumVariableDeclaration):
17
+ kind: Literal["PortDeclaration"]
18
+
16
19
  direction: PortDeclarationDirection
17
20
 
21
+ @pydantic.root_validator(pre=True)
22
+ def _set_kind(cls, values: Dict[str, Any]) -> Dict[str, Any]:
23
+ return values_with_discriminator(values, "kind", "PortDeclaration")
24
+
18
25
  @pydantic.validator("direction")
19
26
  def _direction_validator(
20
27
  cls, direction: PortDeclarationDirection, values: Mapping[str, Any]
@@ -1,4 +1,4 @@
1
- from typing import TYPE_CHECKING
1
+ from typing import TYPE_CHECKING, Literal
2
2
 
3
3
  from classiq.interface.generator.expressions.expression import Expression
4
4
  from classiq.interface.model.quantum_statement import QuantumOperation
@@ -8,5 +8,7 @@ if TYPE_CHECKING:
8
8
 
9
9
 
10
10
  class Power(QuantumOperation):
11
+ kind: Literal["Power"]
12
+
11
13
  power: Expression
12
14
  body: "StatementBlock"
@@ -1,4 +1,4 @@
1
- from typing import Dict, Mapping, Union
1
+ from typing import Dict, Literal, Mapping, Union
2
2
 
3
3
  import pydantic
4
4
 
@@ -28,6 +28,8 @@ VAR_DOMAIN_ILLEGAL = (
28
28
 
29
29
 
30
30
  class AmplitudeLoadingOperation(QuantumAssignmentOperation):
31
+ kind: Literal["AmplitudeLoadingOperation"]
32
+
31
33
  _result_type: QuantumType = pydantic.PrivateAttr(default_factory=QuantumBit)
32
34
 
33
35
  @property
@@ -52,7 +54,7 @@ class AmplitudeLoadingOperation(QuantumAssignmentOperation):
52
54
  ) -> None:
53
55
  if len(var_types) != 1:
54
56
  raise ClassiqValueError(MULTI_VARS_UNSUPPORTED_ERROR)
55
- var_type = var_types[self.var_handles[0].name]
57
+ var_type = list(var_types.values())[0]
56
58
  if not (
57
59
  isinstance(var_type, QuantumNumeric)
58
60
  and var_type.fraction_digits_value == var_type.size_in_bits
@@ -1,4 +1,4 @@
1
- from typing import Dict, Mapping, Union
1
+ from typing import Dict, Literal, Mapping, Union
2
2
 
3
3
  import pydantic
4
4
 
@@ -18,6 +18,8 @@ from classiq.interface.model.quantum_type import QuantumType
18
18
 
19
19
 
20
20
  class ArithmeticOperation(QuantumAssignmentOperation):
21
+ kind: Literal["ArithmeticOperation"]
22
+
21
23
  inplace_result: bool = pydantic.Field(
22
24
  description="Determines whether the result variable is initialized",
23
25
  )
@@ -33,6 +33,16 @@ class VarRefCollector(ast.NodeVisitor):
33
33
  super().generic_visit(node)
34
34
 
35
35
 
36
+ class VarRefTransformer(ast.NodeTransformer):
37
+ def __init__(self, var_mapping: Dict[str, str]) -> None:
38
+ self.var_mapping = var_mapping
39
+
40
+ def visit_Name(self, node: ast.Name) -> ast.Name:
41
+ if node.id in self.var_mapping:
42
+ node.id = self.var_mapping[node.id]
43
+ return node
44
+
45
+
36
46
  class QuantumExpressionOperation(QuantumOperation):
37
47
  expression: Expression = pydantic.Field()
38
48
  _var_handles: List[HandleBinding] = pydantic.PrivateAttr(
@@ -58,7 +68,7 @@ class QuantumExpressionOperation(QuantumOperation):
58
68
  var_types: Dict[str, QuantumType],
59
69
  machine_precision: int,
60
70
  ) -> None:
61
- assert len(var_types) == len(self.var_handles)
71
+ assert len(var_types) == len(self.var_handles) or len(self.var_handles) == 0
62
72
  self._var_types = var_types
63
73
 
64
74
  @property
@@ -1,6 +1,6 @@
1
1
  import itertools
2
2
  import re
3
- from typing import Any, Dict, List, Mapping, Optional, Set, Type, Union
3
+ from typing import Any, Dict, List, Literal, Mapping, Optional, Set, Type, Union
4
4
 
5
5
  import pydantic
6
6
 
@@ -23,7 +23,6 @@ from classiq.interface.model.quantum_function_declaration import (
23
23
  QuantumOperandDeclaration,
24
24
  )
25
25
  from classiq.interface.model.quantum_lambda_function import (
26
- LambdaListComprehension,
27
26
  QuantumCallable,
28
27
  QuantumLambdaFunction,
29
28
  QuantumOperand,
@@ -114,6 +113,8 @@ class OperandIdentifier(ASTNode):
114
113
 
115
114
 
116
115
  class QuantumFunctionCall(QuantumOperation):
116
+ kind: Literal["QuantumFunctionCall"]
117
+
117
118
  function: Union[str, OperandIdentifier] = pydantic.Field(
118
119
  description="The function that is called"
119
120
  )
@@ -304,10 +305,7 @@ class QuantumFunctionCall(QuantumOperation):
304
305
  def get_lambda_defs(operand: QuantumOperand) -> List[QuantumCallable]:
305
306
  if isinstance(operand, list):
306
307
  return operand
307
- elif isinstance(operand, LambdaListComprehension):
308
- return [operand.func]
309
- else:
310
- return [operand]
308
+ return [operand]
311
309
 
312
310
 
313
311
  def _check_ports_against_declaration(
@@ -368,10 +366,6 @@ def _check_operand_against_declaration(
368
366
  if operand_argument.func_decl is None:
369
367
  return
370
368
  operand_arg_decl = operand_argument.func_decl
371
- elif isinstance(operand_argument, LambdaListComprehension):
372
- if operand_argument.func.func_decl is None:
373
- return
374
- operand_arg_decl = operand_argument.func.func_decl
375
369
  else:
376
370
  raise ClassiqValueError(
377
371
  f"{str(operand_argument)!r} argument to {call.func_decl.name!r} is not a "
@@ -1,6 +1,18 @@
1
- from typing import Any, ClassVar, Dict, List, Mapping, Sequence, Set, Type, Union
1
+ from typing import (
2
+ Any,
3
+ ClassVar,
4
+ Dict,
5
+ List,
6
+ Literal,
7
+ Mapping,
8
+ Sequence,
9
+ Set,
10
+ Type,
11
+ Union,
12
+ )
2
13
 
3
14
  import pydantic
15
+ from typing_extensions import Annotated
4
16
 
5
17
  from classiq.interface.generator.function_params import ArithmeticIODict, PortDirection
6
18
  from classiq.interface.generator.functions.function_declaration import (
@@ -9,7 +21,10 @@ from classiq.interface.generator.functions.function_declaration import (
9
21
  from classiq.interface.generator.functions.port_declaration import (
10
22
  PortDeclarationDirection,
11
23
  )
12
- from classiq.interface.helpers.pydantic_model_helpers import Nameable
24
+ from classiq.interface.helpers.pydantic_model_helpers import (
25
+ Nameable,
26
+ values_with_discriminator,
27
+ )
13
28
  from classiq.interface.helpers.validation_helpers import (
14
29
  validate_nameables_mapping,
15
30
  validate_nameables_no_overlap,
@@ -49,8 +64,9 @@ def _populate_declaration_dicts_with_positional_lists(
49
64
  )
50
65
 
51
66
 
52
- PositionalArg = Union[
53
- ClassicalParameterDeclaration, "QuantumOperandDeclaration", PortDeclaration
67
+ PositionalArg = Annotated[
68
+ Union[ClassicalParameterDeclaration, "QuantumOperandDeclaration", PortDeclaration],
69
+ pydantic.Field(..., discriminator="kind"),
54
70
  ]
55
71
 
56
72
 
@@ -218,10 +234,16 @@ class QuantumFunctionDeclaration(FunctionDeclaration):
218
234
 
219
235
 
220
236
  class QuantumOperandDeclaration(QuantumFunctionDeclaration):
237
+ kind: Literal["QuantumOperandDeclaration"]
238
+
221
239
  is_list: bool = pydantic.Field(
222
240
  description="Indicate whether the operand expects an unnamed list of lambdas",
223
241
  default=False,
224
242
  )
225
243
 
244
+ @pydantic.root_validator(pre=True)
245
+ def _set_kind(cls, values: Dict[str, Any]) -> Dict[str, Any]:
246
+ return values_with_discriminator(values, "kind", "QuantumOperandDeclaration")
247
+
226
248
 
227
249
  QuantumFunctionDeclaration.update_forward_refs()
@@ -3,7 +3,6 @@ from typing import TYPE_CHECKING, Dict, List, Optional, Union
3
3
  import pydantic
4
4
 
5
5
  from classiq.interface.ast_node import ASTNode
6
- from classiq.interface.generator.expressions.expression import Expression
7
6
  from classiq.interface.model.quantum_function_declaration import (
8
7
  QuantumOperandDeclaration,
9
8
  )
@@ -36,23 +35,5 @@ class QuantumLambdaFunction(ASTNode):
36
35
  self._func_decl = fd
37
36
 
38
37
 
39
- class LambdaListComprehension(ASTNode):
40
- """
41
- Specification of a list of lambda functions iteratively
42
- """
43
-
44
- count: Expression = pydantic.Field(
45
- description="The number of lambda functions in the list"
46
- )
47
-
48
- index_var: str = pydantic.Field(
49
- description="The name of the integer variable holding the iteration index"
50
- )
51
-
52
- func: QuantumLambdaFunction = pydantic.Field(
53
- description="A lambda function definition replicated for index values 0 to count-1"
54
- )
55
-
56
-
57
38
  QuantumCallable = Union[str, QuantumLambdaFunction]
58
- QuantumOperand = Union[QuantumCallable, List[QuantumCallable], LambdaListComprehension]
39
+ QuantumOperand = Union[QuantumCallable, List[QuantumCallable]]
@@ -1,8 +1,9 @@
1
- from typing import Mapping, Union
1
+ from typing import Any, Dict, Mapping, Union
2
2
 
3
- from pydantic import Extra
3
+ from pydantic import Extra, root_validator
4
4
 
5
5
  from classiq.interface.ast_node import ASTNode
6
+ from classiq.interface.helpers.pydantic_model_helpers import values_with_discriminator
6
7
  from classiq.interface.model.handle_binding import (
7
8
  HandleBinding,
8
9
  SlicedHandleBinding,
@@ -11,9 +12,15 @@ from classiq.interface.model.handle_binding import (
11
12
 
12
13
 
13
14
  class QuantumStatement(ASTNode):
15
+ kind: str
16
+
14
17
  class Config:
15
18
  extra = Extra.forbid
16
19
 
20
+ @root_validator(pre=True)
21
+ def _set_kind(cls, values: Dict[str, Any]) -> Dict[str, Any]:
22
+ return values_with_discriminator(values, "kind", cls.__name__) # type: ignore[attr-defined]
23
+
17
24
 
18
25
  class QuantumOperation(QuantumStatement):
19
26
  @property
@@ -1,4 +1,4 @@
1
- from typing import TYPE_CHECKING
1
+ from typing import TYPE_CHECKING, Literal
2
2
 
3
3
  from classiq.interface.generator.expressions.expression import Expression
4
4
  from classiq.interface.model.quantum_statement import QuantumOperation
@@ -8,6 +8,8 @@ if TYPE_CHECKING:
8
8
 
9
9
 
10
10
  class Repeat(QuantumOperation):
11
+ kind: Literal["Repeat"]
12
+
11
13
  iter_var: str
12
14
  count: Expression
13
15
  body: "StatementBlock"
@@ -1,5 +1,8 @@
1
1
  from typing import List, Union
2
2
 
3
+ from pydantic import Field
4
+ from typing_extensions import Annotated
5
+
3
6
  from classiq.interface.model.bind_operation import BindOperation
4
7
  from classiq.interface.model.classical_if import ClassicalIf
5
8
  from classiq.interface.model.control import Control
@@ -20,19 +23,22 @@ from classiq.interface.model.variable_declaration_statement import (
20
23
  )
21
24
  from classiq.interface.model.within_apply_operation import WithinApply
22
25
 
23
- ConcreteQuantumStatement = Union[
24
- QuantumFunctionCall,
25
- ArithmeticOperation,
26
- AmplitudeLoadingOperation,
27
- VariableDeclarationStatement,
28
- BindOperation,
29
- InplaceBinaryOperation,
30
- Repeat,
31
- Power,
32
- Invert,
33
- ClassicalIf,
34
- Control,
35
- WithinApply,
26
+ ConcreteQuantumStatement = Annotated[
27
+ Union[
28
+ QuantumFunctionCall,
29
+ ArithmeticOperation,
30
+ AmplitudeLoadingOperation,
31
+ VariableDeclarationStatement,
32
+ BindOperation,
33
+ InplaceBinaryOperation,
34
+ Repeat,
35
+ Power,
36
+ Invert,
37
+ ClassicalIf,
38
+ Control,
39
+ WithinApply,
40
+ ],
41
+ Field(..., discriminator="kind"),
36
42
  ]
37
43
 
38
44
  StatementBlock = List[ConcreteQuantumStatement]
@@ -61,8 +61,14 @@ class HandleValidator(HandleValidationBase):
61
61
  self._handle_apply([QuantumFunctionCall(function=call_name)])
62
62
  elif isinstance(op, WithinApply):
63
63
  self._handle_apply(op.action)
64
- self._handle_inputs(op.wiring_inputs)
65
- self._handle_outputs(op.wiring_outputs)
64
+
65
+ if isinstance(op, QuantumFunctionCall) and op.synthesis_data.is_inverse:
66
+ self._handle_inputs(op.wiring_outputs)
67
+ self._handle_outputs(op.wiring_inputs)
68
+ else:
69
+ self._handle_inputs(op.wiring_inputs)
70
+ self._handle_outputs(op.wiring_outputs)
71
+
66
72
  self._handle_inouts(op.wiring_inouts)
67
73
 
68
74
  def handle_variable_declaration(
@@ -1,3 +1,5 @@
1
+ from typing import Literal
2
+
1
3
  from classiq.interface.model.quantum_statement import QuantumStatement
2
4
  from classiq.interface.model.quantum_variable_declaration import (
3
5
  QuantumVariableDeclaration,
@@ -5,4 +7,4 @@ from classiq.interface.model.quantum_variable_declaration import (
5
7
 
6
8
 
7
9
  class VariableDeclarationStatement(QuantumStatement, QuantumVariableDeclaration):
8
- pass
10
+ kind: Literal["VariableDeclarationStatement"]
@@ -1,4 +1,4 @@
1
- from typing import TYPE_CHECKING
1
+ from typing import TYPE_CHECKING, Literal
2
2
 
3
3
  from classiq.interface.model.quantum_statement import QuantumOperation
4
4
 
@@ -7,5 +7,7 @@ if TYPE_CHECKING:
7
7
 
8
8
 
9
9
  class WithinApply(QuantumOperation):
10
+ kind: Literal["WithinApply"]
11
+
10
12
  compute: "StatementBlock"
11
13
  action: "StatementBlock"
@@ -1,6 +1,5 @@
1
1
  ANALYZER_PREFIX = "/analyzer"
2
2
  CHEMISTRY_PREFIX = "/chemistry"
3
- LEGACY_EXECUTE_PREFIX = "/execute"
4
3
  EXECUTION_PREFIX = "/execution"
5
4
  CONVERSION_PREFIX = "/conversion"
6
5
 
@@ -22,8 +21,6 @@ ANALYZER_OPTIONAL_DEVICES = "/graphs/available_devices"
22
21
  ANALYZER_OPTIONAL_DEVICES_FULL_PATH = ANALYZER_PREFIX + ANALYZER_OPTIONAL_DEVICES
23
22
 
24
23
  TASKS_SUFFIX = "/tasks"
25
- QUANTUM_PROGRAM_SUFFIX = "/quantum_program"
26
- ESTIMATE_SUFFIX = "/estimate"
27
24
  RB = "/rb"
28
25
  ANALYZER_DATA_TASK = f"{TASKS_SUFFIX}/data"
29
26
  ANALYZER_QASM_TASK = f"{TASKS_SUFFIX}/qasm"
@@ -60,8 +57,6 @@ EXECUTION_JOBS_FULL_PATH = EXECUTION_PREFIX + EXECUTION_JOBS_SUFFIX
60
57
  EXECUTION_JOBS_NON_VERSIONED_FULL_PATH = (
61
58
  EXECUTION_NON_VERSIONED_PREFIX + EXECUTION_JOBS_SUFFIX
62
59
  )
63
- EXECUTE_QUANTUM_PROGRAM_FULL_PATH = LEGACY_EXECUTE_PREFIX + QUANTUM_PROGRAM_SUFFIX
64
- EXECUTE_ESTIMATE_FULL_PATH = LEGACY_EXECUTE_PREFIX + ESTIMATE_SUFFIX
65
60
 
66
61
  ANALYZER_FULL_PATH = ANALYZER_PREFIX + TASKS_SUFFIX
67
62
  ANALYZER_RB_FULL_PATH = ANALYZER_PREFIX + TASK_RB_SUFFIX