classiq 0.83.0__py3-none-any.whl → 0.84.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.
Files changed (82) hide show
  1. classiq/_internals/api_wrapper.py +27 -0
  2. classiq/applications/chemistry/chemistry_model_constructor.py +0 -2
  3. classiq/applications/chemistry/hartree_fock.py +68 -0
  4. classiq/applications/chemistry/mapping.py +85 -0
  5. classiq/applications/chemistry/op_utils.py +79 -0
  6. classiq/applications/chemistry/problems.py +195 -0
  7. classiq/applications/chemistry/ucc.py +109 -0
  8. classiq/applications/chemistry/z2_symmetries.py +368 -0
  9. classiq/applications/combinatorial_helpers/pauli_helpers/pauli_utils.py +30 -1
  10. classiq/{model_expansions/evaluators → evaluators}/arg_type_match.py +12 -4
  11. classiq/{model_expansions/evaluators → evaluators}/argument_types.py +1 -1
  12. classiq/{model_expansions/evaluators → evaluators}/classical_expression.py +1 -1
  13. classiq/{model_expansions/evaluators → evaluators}/classical_type_inference.py +3 -4
  14. classiq/{model_expansions/evaluators → evaluators}/parameter_types.py +17 -15
  15. classiq/execution/__init__.py +12 -1
  16. classiq/execution/execution_session.py +189 -43
  17. classiq/execution/jobs.py +26 -1
  18. classiq/execution/qnn.py +2 -2
  19. classiq/execution/user_budgets.py +39 -0
  20. classiq/interface/_version.py +1 -1
  21. classiq/interface/constants.py +1 -0
  22. classiq/interface/execution/primitives.py +29 -1
  23. classiq/interface/executor/estimate_cost.py +35 -0
  24. classiq/interface/executor/execution_result.py +13 -0
  25. classiq/interface/executor/result.py +116 -1
  26. classiq/interface/executor/user_budget.py +26 -33
  27. classiq/interface/generator/expressions/atomic_expression_functions.py +5 -1
  28. classiq/interface/generator/expressions/proxies/classical/any_classical_value.py +0 -6
  29. classiq/interface/generator/functions/classical_type.py +2 -35
  30. classiq/interface/generator/functions/concrete_types.py +0 -3
  31. classiq/interface/generator/functions/type_modifier.py +0 -19
  32. classiq/interface/generator/generated_circuit_data.py +0 -8
  33. classiq/interface/generator/types/compilation_metadata.py +0 -3
  34. classiq/interface/ide/visual_model.py +6 -2
  35. classiq/interface/model/model.py +12 -7
  36. classiq/interface/model/port_declaration.py +2 -24
  37. classiq/interface/pretty_print/__init__.py +0 -0
  38. classiq/{qmod/native → interface/pretty_print}/expression_to_qmod.py +18 -11
  39. classiq/interface/server/routes.py +4 -0
  40. classiq/model_expansions/atomic_expression_functions_defs.py +42 -5
  41. classiq/model_expansions/interpreters/base_interpreter.py +3 -3
  42. classiq/model_expansions/quantum_operations/allocate.py +1 -1
  43. classiq/model_expansions/quantum_operations/assignment_result_processor.py +1 -1
  44. classiq/model_expansions/quantum_operations/bind.py +2 -2
  45. classiq/model_expansions/quantum_operations/call_emitter.py +26 -20
  46. classiq/model_expansions/quantum_operations/variable_decleration.py +1 -1
  47. classiq/model_expansions/scope_initialization.py +3 -3
  48. classiq/model_expansions/transformers/model_renamer.py +6 -4
  49. classiq/model_expansions/transformers/type_modifier_inference.py +81 -43
  50. classiq/model_expansions/visitors/symbolic_param_inference.py +2 -3
  51. classiq/open_library/functions/__init__.py +3 -0
  52. classiq/open_library/functions/amplitude_amplification.py +10 -18
  53. classiq/open_library/functions/discrete_sine_cosine_transform.py +5 -5
  54. classiq/open_library/functions/grover.py +14 -6
  55. classiq/open_library/functions/modular_exponentiation.py +22 -20
  56. classiq/open_library/functions/state_preparation.py +17 -0
  57. classiq/qmod/builtins/enums.py +23 -0
  58. classiq/qmod/builtins/functions/__init__.py +2 -0
  59. classiq/qmod/builtins/functions/exponentiation.py +32 -4
  60. classiq/qmod/builtins/structs.py +55 -3
  61. classiq/qmod/declaration_inferrer.py +3 -2
  62. classiq/qmod/native/pretty_printer.py +2 -6
  63. classiq/qmod/pretty_print/expression_to_python.py +2 -1
  64. classiq/qmod/pretty_print/pretty_printer.py +1 -6
  65. classiq/qmod/python_classical_type.py +12 -5
  66. classiq/qmod/qmod_constant.py +2 -5
  67. classiq/qmod/qmod_parameter.py +2 -5
  68. classiq/qmod/qmod_variable.py +56 -15
  69. classiq/qmod/quantum_expandable.py +4 -2
  70. classiq/qmod/quantum_function.py +7 -2
  71. classiq/qmod/semantics/annotation/qstruct_annotator.py +1 -1
  72. classiq/qmod/semantics/validation/main_validation.py +1 -9
  73. classiq/qmod/utilities.py +0 -2
  74. classiq/qmod/write_qmod.py +1 -1
  75. {classiq-0.83.0.dist-info → classiq-0.84.0.dist-info}/METADATA +4 -1
  76. {classiq-0.83.0.dist-info → classiq-0.84.0.dist-info}/RECORD +82 -73
  77. /classiq/{model_expansions/evaluators → evaluators}/__init__.py +0 -0
  78. /classiq/{model_expansions/evaluators → evaluators}/control.py +0 -0
  79. /classiq/{model_expansions → evaluators}/expression_evaluator.py +0 -0
  80. /classiq/{model_expansions/evaluators → evaluators}/quantum_type_utils.py +0 -0
  81. /classiq/{model_expansions/evaluators → evaluators}/type_type_match.py +0 -0
  82. {classiq-0.83.0.dist-info → classiq-0.84.0.dist-info}/WHEEL +0 -0
@@ -1,9 +1,9 @@
1
1
  import datetime
2
- from collections import defaultdict
3
2
  from typing import Optional
4
3
 
5
4
  import pydantic
6
5
  from pydantic import ConfigDict, Field
6
+ from tabulate import tabulate
7
7
 
8
8
  from classiq.interface.helpers.versioned_model import VersionedModel
9
9
 
@@ -15,6 +15,7 @@ class UserBudget(VersionedModel):
15
15
  available_budget: float
16
16
  used_budget: float
17
17
  last_allocation_date: datetime.datetime
18
+ budget_limit: Optional[float] = Field(default=None)
18
19
 
19
20
  model_config = ConfigDict(extra="ignore")
20
21
 
@@ -22,35 +23,27 @@ class UserBudget(VersionedModel):
22
23
  class UserBudgets(VersionedModel):
23
24
  budgets: list[UserBudget] = pydantic.Field(default=[])
24
25
 
25
- def print_budgets(self) -> None:
26
- def format_header() -> str:
27
- return f"| {'Provider':<20} | {'Available Budget':<18} | {'Used Budget':<18} | {'Currency':<8} |"
28
-
29
- def format_row(
30
- provider: str, available: float, used: float, currency: str
31
- ) -> str:
32
- return f"| {provider:<20} | {available:<18.3f} | {used:<18.3f} | {currency:<8} |"
33
-
34
- table_data: dict = defaultdict(
35
- lambda: {"used": 0.0, "available": 0.0, "currency": "USD"}
36
- )
37
-
38
- for budget in self.budgets:
39
- provider = budget.provider
40
- table_data[provider]["available"] += budget.available_budget
41
- table_data[provider]["used"] += budget.used_budget
42
- table_data[provider]["currency"] = budget.currency_code
43
-
44
- line = "=" * 77
45
- print(line) # noqa: T201
46
- print(format_header()) # noqa: T201
47
- print(line) # noqa: T201
48
-
49
- for provider, values in table_data.items():
50
- print( # noqa: T201
51
- format_row(
52
- provider, values["available"], values["used"], values["currency"]
53
- )
54
- )
55
-
56
- print(line) # noqa: T201
26
+ def __str__(self) -> str:
27
+ rows = [
28
+ [
29
+ budget.provider,
30
+ f"{budget.used_budget:.3f}",
31
+ f"{budget.available_budget:.3f}",
32
+ (
33
+ f"{budget.budget_limit:.3f}"
34
+ if budget.budget_limit is not None
35
+ else "NOT SET"
36
+ ),
37
+ budget.currency_code,
38
+ ]
39
+ for budget in self.budgets
40
+ ]
41
+
42
+ headers = [
43
+ "Provider",
44
+ "Used Budget",
45
+ "Remaining Budget",
46
+ "Budget Limit",
47
+ "Currency",
48
+ ]
49
+ return tabulate(rows, headers=headers, tablefmt="grid")
@@ -23,7 +23,6 @@ CLASSIQ_EXPR_FUNCTIONS = {
23
23
  SUPPORTED_CLASSIQ_BUILTIN_FUNCTIONS = {
24
24
  *CLASSIQ_BUILTIN_CLASSICAL_FUNCTIONS,
25
25
  *CLASSIQ_EXPR_FUNCTIONS,
26
- "mod_inverse",
27
26
  }
28
27
 
29
28
  SUPPORTED_CLASSIQ_SYMPY_WRAPPERS = {
@@ -34,6 +33,11 @@ SUPPORTED_CLASSIQ_SYMPY_WRAPPERS = {
34
33
  "LogicalXor",
35
34
  "RShift",
36
35
  "LShift",
36
+ "mod_inverse",
37
+ "min",
38
+ "Min",
39
+ "max",
40
+ "Max",
37
41
  }
38
42
 
39
43
  SUPPORTED_ATOMIC_EXPRESSION_FUNCTIONS = {
@@ -21,12 +21,6 @@ def subscript_to_str(index: Any) -> str:
21
21
 
22
22
 
23
23
  class AnyClassicalValue(sympy.Symbol):
24
-
25
- is_commutative = None
26
- is_infinite = None
27
- is_finite = None
28
- is_extended_real = None
29
-
30
24
  def __getitem__(self, item: Any) -> "AnyClassicalValue":
31
25
  if isinstance(item, slice):
32
26
  return AnyClassicalValue(f"{self}[{subscript_to_str(item)}]")
@@ -98,39 +98,6 @@ class Bool(ClassicalType):
98
98
  return values_with_discriminator(values, "kind", "bool")
99
99
 
100
100
 
101
- class ClassicalList(ClassicalType):
102
- kind: Literal["list"]
103
- element_type: "ConcreteClassicalType"
104
-
105
- @pydantic.model_validator(mode="before")
106
- @classmethod
107
- def _set_kind(cls, values: Any) -> dict[str, Any]:
108
- return values_with_discriminator(values, "kind", "list")
109
-
110
- def get_classical_proxy(self, handle: HandleBinding) -> ClassicalProxy:
111
- return ClassicalArrayProxy(
112
- handle, self.element_type, AnyClassicalValue(f"get_field({handle}, 'len')")
113
- )
114
-
115
- @property
116
- def expressions(self) -> list[Expression]:
117
- return self.element_type.expressions
118
-
119
- @property
120
- def is_purely_declarative(self) -> bool:
121
- return super().is_purely_declarative and self.element_type.is_purely_declarative
122
-
123
- @property
124
- def is_purely_generative(self) -> bool:
125
- return super().is_purely_generative and self.element_type.is_purely_generative
126
-
127
- def get_raw_type(self) -> "ConcreteClassicalType":
128
- raw_type = ClassicalArray(element_type=self.element_type.get_raw_type())
129
- if self._is_generative:
130
- raw_type.set_generative()
131
- return raw_type
132
-
133
-
134
101
  class StructMetaType(ClassicalType):
135
102
  kind: Literal["type_proxy"]
136
103
 
@@ -146,8 +113,8 @@ class StructMetaType(ClassicalType):
146
113
  class ClassicalArray(ClassicalType):
147
114
  kind: Literal["array"]
148
115
  element_type: "ConcreteClassicalType"
149
- size: Optional[int] = None
150
- length: Optional[Expression] = pydantic.Field(exclude=True, default=None)
116
+ size: Optional[int] = pydantic.Field(exclude=True, default=None)
117
+ length: Optional[Expression] = None
151
118
 
152
119
  @pydantic.model_validator(mode="before")
153
120
  @classmethod
@@ -5,7 +5,6 @@ from pydantic import Field
5
5
  from classiq.interface.generator.functions.classical_type import (
6
6
  Bool,
7
7
  ClassicalArray,
8
- ClassicalList,
9
8
  ClassicalTuple,
10
9
  Estimation,
11
10
  Histogram,
@@ -29,7 +28,6 @@ ConcreteClassicalType = Annotated[
29
28
  Integer,
30
29
  Real,
31
30
  Bool,
32
- ClassicalList,
33
31
  StructMetaType,
34
32
  TypeName,
35
33
  ClassicalArray,
@@ -41,7 +39,6 @@ ConcreteClassicalType = Annotated[
41
39
  ],
42
40
  Field(discriminator="kind"),
43
41
  ]
44
- ClassicalList.model_rebuild()
45
42
  ClassicalArray.model_rebuild()
46
43
  ClassicalTuple.model_rebuild()
47
44
 
@@ -2,25 +2,6 @@ from classiq.interface.enum_utils import StrEnum
2
2
  from classiq.interface.exceptions import ClassiqInternalExpansionError
3
3
 
4
4
 
5
- class TypeQualifier(StrEnum):
6
- Const = "const"
7
- QFree = "qfree"
8
- Quantum = "quantum"
9
- Inferred = "inferred"
10
-
11
- def to_modifier(self) -> "TypeModifier":
12
- if self is TypeQualifier.Const:
13
- return TypeModifier.Const
14
- elif self is TypeQualifier.QFree:
15
- return TypeModifier.Permutable
16
- elif self is TypeQualifier.Quantum:
17
- return TypeModifier.Mutable
18
- elif self is TypeQualifier.Inferred:
19
- return TypeModifier.Inferred
20
- else:
21
- raise ClassiqInternalExpansionError(f"Unexpected type qualifier: {self}")
22
-
23
-
24
5
  class TypeModifier(StrEnum):
25
6
  Const = "const"
26
7
  Permutable = "permutable"
@@ -28,8 +28,6 @@ from classiq.interface.model.statement_block import (
28
28
  )
29
29
 
30
30
  from classiq.model_expansions.capturing.mangling_utils import (
31
- demangle_capture_name,
32
- demangle_name,
33
31
  is_captured_var_name,
34
32
  )
35
33
 
@@ -85,12 +83,6 @@ class GeneratedRegister(pydantic.BaseModel):
85
83
  def is_captured(self) -> bool:
86
84
  return is_captured_var_name(self.name)
87
85
 
88
- @staticmethod
89
- def demangle_name(name: str) -> str:
90
- if is_captured_var_name(name):
91
- name = demangle_capture_name(name)
92
- return demangle_name(name)
93
-
94
86
 
95
87
  class GeneratedFunction(pydantic.BaseModel):
96
88
  name: str
@@ -6,9 +6,6 @@ class CompilationMetadata(BaseModel):
6
6
  occurrences_number: NonNegativeInt = Field(default=1)
7
7
  _occupation_number: NonNegativeInt = PrivateAttr(default=0)
8
8
  unchecked: list[str] = Field(default_factory=list)
9
- atomic_qualifiers: list[str] = Field(
10
- default_factory=list, exclude=True
11
- ) # TODO remove after deprecation https://classiq.atlassian.net/browse/CLS-2671
12
9
 
13
10
  @property
14
11
  def occupation_number(self) -> NonNegativeInt:
@@ -110,7 +110,9 @@ class Operation(pydantic.BaseModel):
110
110
  name: str
111
111
  qasm_name: str = pydantic.Field(default="")
112
112
  details: str = pydantic.Field(default="")
113
- children: list["Operation"]
113
+ children: list["Operation"] = pydantic.Field(default_factory=list)
114
+ # children_ids is optional in order to support backwards compatibility.
115
+ children_ids: list[int] = pydantic.Field(default_factory=list)
114
116
  operation_data: Optional[OperationData] = None
115
117
  operation_links: OperationLinks
116
118
  control_qubits: tuple[int, ...] = pydantic.Field(default_factory=tuple)
@@ -129,5 +131,7 @@ class Operation(pydantic.BaseModel):
129
131
 
130
132
 
131
133
  class ProgramVisualModel(VersionedModel):
132
- main_operation: Operation
134
+ main_operation: Operation = pydantic.Field(default=None)
135
+ id_to_operations: dict[int, Operation] = pydantic.Field(default_factory=dict)
136
+ main_operation_id: int = pydantic.Field(default=None)
133
137
  program_data: ProgramData
@@ -185,11 +185,16 @@ class Model(VersionedModel, ASTNode):
185
185
  return constants
186
186
 
187
187
  def dump_no_metadata(self) -> dict[str, Any]:
188
- return self.model_dump(
189
- exclude={
190
- "constraints",
191
- "execution_preferences",
192
- "preferences",
193
- "functions_compilation_metadata",
194
- },
188
+ compilation_metadata_with_unchecked = {
189
+ name: CompilationMetadata(unchecked=comp_metadata.unchecked)
190
+ for name, comp_metadata in self.functions_compilation_metadata.items()
191
+ if len(comp_metadata.unchecked) > 0
192
+ }
193
+ model = self.model_copy(
194
+ update={
195
+ "functions_compilation_metadata": compilation_metadata_with_unchecked,
196
+ }
197
+ )
198
+ return model.model_dump(
199
+ exclude={"constraints", "execution_preferences", "preferences"},
195
200
  )
@@ -1,4 +1,4 @@
1
- from typing import Any, Literal, Optional
1
+ from typing import Any, Literal
2
2
 
3
3
  import pydantic
4
4
  from pydantic_core.core_schema import ValidationInfo
@@ -10,7 +10,6 @@ from classiq.interface.generator.functions.port_declaration import (
10
10
  )
11
11
  from classiq.interface.generator.functions.type_modifier import (
12
12
  TypeModifier,
13
- TypeQualifier,
14
13
  )
15
14
  from classiq.interface.helpers.pydantic_model_helpers import values_with_discriminator
16
15
  from classiq.interface.model.parameter import Parameter
@@ -19,35 +18,14 @@ from classiq.interface.model.parameter import Parameter
19
18
  class AnonPortDeclaration(Parameter):
20
19
  quantum_type: ConcreteQuantumType
21
20
  direction: PortDeclarationDirection
22
- type_qualifier: Optional[TypeQualifier] = pydantic.Field(
23
- default=None, exclude=True
24
- ) # TODO remove after BWC breaking release https://classiq.atlassian.net/browse/CLS-2777
25
21
  kind: Literal["PortDeclaration"]
26
- type_modifier: TypeModifier = pydantic.Field(default=None)
22
+ type_modifier: TypeModifier
27
23
 
28
24
  @pydantic.model_validator(mode="before")
29
25
  @classmethod
30
26
  def _set_kind(cls, values: Any) -> dict[str, Any]:
31
27
  return values_with_discriminator(values, "kind", "PortDeclaration")
32
28
 
33
- @pydantic.model_validator(mode="before")
34
- @classmethod
35
- def _set_type_modifier(cls, values: Any) -> dict[str, Any]:
36
- if values.get("type_modifier") is None:
37
- type_qualifier = values.get("type_qualifier")
38
- if type_qualifier is not None:
39
- if isinstance(type_qualifier, TypeQualifier):
40
- values["type_modifier"] = type_qualifier.to_modifier()
41
- elif isinstance(type_qualifier, str):
42
- values["type_modifier"] = TypeQualifier(
43
- type_qualifier
44
- ).to_modifier()
45
- else:
46
- raise pydantic.ValidationError("Missing a type modifier")
47
- else:
48
- raise pydantic.ValidationError("Missing a type modifier")
49
- return values
50
-
51
29
  @pydantic.field_validator("direction", mode="before")
52
30
  @classmethod
53
31
  def _direction_validator(
File without changes
@@ -6,7 +6,7 @@ from typing import Callable, Optional
6
6
 
7
7
  import numpy as np
8
8
 
9
- from classiq.qmod.utilities import DEFAULT_DECIMAL_PRECISION
9
+ from classiq.interface.constants import DEFAULT_DECIMAL_PRECISION
10
10
 
11
11
  IDENTIFIER = re.compile(r"[a-zA-Z_]\w*")
12
12
  BINARY_OPS: Mapping[type[ast.operator], str] = {
@@ -40,6 +40,10 @@ COMPARE_OPS: Mapping[type[ast.cmpop], str] = {
40
40
  LIST_FORMAT_CHAR_LIMIT = 20
41
41
 
42
42
 
43
+ class PrettyPrinterError(AssertionError):
44
+ pass
45
+
46
+
43
47
  @dataclass
44
48
  class ASTToQMODCode:
45
49
  level: int
@@ -59,10 +63,13 @@ class ASTToQMODCode:
59
63
  elif isinstance(node, ast.Attribute):
60
64
  # Enum attribute access
61
65
  if not isinstance(node.value, ast.Name) or not isinstance(node.attr, str):
62
- raise AssertionError("Error parsing enum attribute access")
66
+ raise PrettyPrinterError("Error parsing enum attribute access")
63
67
  if not (IDENTIFIER.match(node.value.id) and IDENTIFIER.match(node.attr)):
64
- raise AssertionError("Error parsing enum attribute access")
65
- return f"{node.value.id!s}::{node.attr!s}"
68
+ raise PrettyPrinterError("Error parsing enum attribute access")
69
+ # FIXME: identify enum member accesses by type name (CLS-2858)
70
+ if len(node.value.id) > 0 and node.value.id[0].isupper():
71
+ return f"{node.value.id!s}::{node.attr!s}"
72
+ return f"{node.value.id!s}.{node.attr!s}"
66
73
  elif isinstance(node, ast.Name):
67
74
  return node.id
68
75
  elif isinstance(node, ast.Num):
@@ -91,7 +98,7 @@ class ASTToQMODCode:
91
98
  )
92
99
  elif isinstance(node, ast.Compare):
93
100
  if len(node.ops) != 1 or len(node.comparators) != 1:
94
- raise AssertionError("Error parsing comparison expression.")
101
+ raise PrettyPrinterError("Error parsing comparison expression.")
95
102
  return "({} {} {})".format(
96
103
  self.ast_to_code(node.left),
97
104
  COMPARE_OPS[type(node.ops[0])],
@@ -108,20 +115,20 @@ class ASTToQMODCode:
108
115
  elif isinstance(node, ast.Slice):
109
116
  # A QMOD expression does not support slice step
110
117
  if node.lower is None or node.upper is None or node.step is not None:
111
- raise AssertionError("Error parsing slice expression.")
118
+ raise PrettyPrinterError("Error parsing slice expression.")
112
119
  return f"{self.ast_to_code(node.lower)}:{self.ast_to_code(node.upper)}"
113
120
  elif isinstance(node, ast.Call):
114
121
  func = self.ast_to_code(node.func)
115
122
  if func == "get_field":
116
123
  if len(node.args) != 2:
117
- raise AssertionError("Error parsing struct field access.")
124
+ raise PrettyPrinterError("Error parsing struct field access.")
118
125
  field = str(self.ast_to_code(node.args[1])).replace("'", "")
119
126
  if not IDENTIFIER.match(field):
120
- raise AssertionError("Error parsing struct field access.")
127
+ raise PrettyPrinterError("Error parsing struct field access.")
121
128
  return f"{self.ast_to_code(node.args[0])}.{field}"
122
129
  elif func == "struct_literal":
123
130
  if len(node.args) != 1 or not isinstance(node.args[0], ast.Name):
124
- raise AssertionError("Error parsing struct literal.")
131
+ raise PrettyPrinterError("Error parsing struct literal.")
125
132
  keywords = node.keywords
126
133
  initializer_list = self.indent_items(
127
134
  lambda: [
@@ -133,7 +140,7 @@ class ASTToQMODCode:
133
140
  return f"{self.ast_to_code(node.args[0])} {{{initializer_list}}}"
134
141
  elif func == "do_subscript":
135
142
  if len(node.args) != 2:
136
- raise AssertionError("Error parsing array access.")
143
+ raise PrettyPrinterError("Error parsing array access.")
137
144
  return f"{self.ast_to_code(node.args[0])}[{self.ast_to_code(node.args[1])}]"
138
145
  else:
139
146
  return "{}({})".format(
@@ -142,7 +149,7 @@ class ASTToQMODCode:
142
149
  elif isinstance(node, ast.Expr):
143
150
  return self._cleaned_ast_to_code(node.value)
144
151
  else:
145
- raise AssertionError("Error parsing expression: unsupported AST node.")
152
+ raise PrettyPrinterError("Error parsing expression: unsupported AST node.")
146
153
 
147
154
  def indent_items(self, items: Callable[[], list[str]]) -> str:
148
155
  should_indent = (
@@ -91,3 +91,7 @@ IQCC_LIST_AUTH_TARGETS_FULL_PATH = IQCC_PREFIX + IQCC_LIST_AUTH_TARGETS_SUFFIX
91
91
 
92
92
  USER_BUDGETS_SUFFIX = "/all"
93
93
  USER_BUDGETS_FULL_PATH = USER_BUDGETS_PREFIX + USER_BUDGETS_SUFFIX
94
+ USER_BUDGET_SET_LIMIT_SUFFIX = "/set_limit"
95
+ USER_BUDGET_SET_LIMIT_FULL_PATH = USER_BUDGETS_PREFIX + USER_BUDGET_SET_LIMIT_SUFFIX
96
+ USER_BUDGET_CLEAR_LIMIT_SUFFIX = "/clear_limit"
97
+ USER_BUDGET_CLEAR_LIMIT_FULL_PATH = USER_BUDGETS_PREFIX + USER_BUDGET_CLEAR_LIMIT_SUFFIX
@@ -39,7 +39,6 @@ from classiq.interface.generator.functions.classical_function_declaration import
39
39
  from classiq.interface.generator.functions.classical_type import (
40
40
  Bool,
41
41
  ClassicalArray,
42
- ClassicalList,
43
42
  ClassicalTuple,
44
43
  ClassicalType,
45
44
  OpaqueHandle,
@@ -91,7 +90,7 @@ def qmod_val_to_python(val: ExpressionValue, qmod_type: ClassicalType) -> Any:
91
90
  if isinstance(val, (Enum, int)):
92
91
  return val
93
92
 
94
- elif isinstance(qmod_type, (ClassicalArray, ClassicalList)):
93
+ elif isinstance(qmod_type, ClassicalArray):
95
94
  if isinstance(val, list):
96
95
  return [qmod_val_to_python(elem, qmod_type.element_type) for elem in val]
97
96
 
@@ -145,9 +144,9 @@ def python_val_to_qmod(val: Any, qmod_type: ClassicalType) -> ExpressionValue:
145
144
  field_name: python_val_to_qmod(val[field_name], field_type)
146
145
  for field_name, field_type in struct_decl.variables.items()
147
146
  }
148
- return QmodStructInstance(struct_decl.model_copy(), qmod_dict)
147
+ return QmodStructInstance(struct_decl.model_copy(deep=True), qmod_dict)
149
148
 
150
- if isinstance(qmod_type, (ClassicalList, ClassicalArray)):
149
+ if isinstance(qmod_type, ClassicalArray):
151
150
  if not isinstance(val, list):
152
151
  raise ClassiqInternalExpansionError("Bad value for list")
153
152
  return [python_val_to_qmod(elem, qmod_type.element_type) for elem in val]
@@ -182,7 +181,7 @@ def python_call_wrapper(func: Callable, *args: ExpressionValue) -> Any:
182
181
 
183
182
  def struct_literal(struct_type_symbol: Symbol, **kwargs: Any) -> QmodStructInstance:
184
183
  return QmodStructInstance(
185
- QMODULE.type_decls[struct_type_symbol.name].model_copy(),
184
+ QMODULE.type_decls[struct_type_symbol.name].model_copy(deep=True),
186
185
  {field: sympy_to_python(field_value) for field, field_value in kwargs.items()},
187
186
  )
188
187
 
@@ -330,6 +329,40 @@ def mod_inverse(a: Any, b: Any) -> Any:
330
329
  return sympy.mod_inverse(a, b)
331
330
 
332
331
 
332
+ def min_wrapper(*vals: Any) -> Any:
333
+ try:
334
+ return sympy.Min(*vals)
335
+ except ValueError:
336
+ return AnyClassicalValue(f"Min({', '.join(map(str, vals))})")
337
+
338
+
339
+ min_wrapper.__name__ = "min"
340
+
341
+
342
+ def Min_wrapper(*vals: Any) -> Any: # noqa: N802
343
+ return min_wrapper(*vals)
344
+
345
+
346
+ Min_wrapper.__name__ = "Min"
347
+
348
+
349
+ def max_wrapper(*vals: Any) -> Any:
350
+ try:
351
+ return sympy.Max(*vals)
352
+ except ValueError:
353
+ return AnyClassicalValue(f"Max({', '.join(map(str, vals))})")
354
+
355
+
356
+ max_wrapper.__name__ = "max"
357
+
358
+
359
+ def Max_wrapper(*vals: Any) -> Any: # noqa: N802
360
+ return max_wrapper(*vals)
361
+
362
+
363
+ Max_wrapper.__name__ = "Max"
364
+
365
+
333
366
  CORE_LIB_FUNCTIONS_LIST: list[Callable] = [
334
367
  print,
335
368
  do_sum,
@@ -347,6 +380,10 @@ CORE_LIB_FUNCTIONS_LIST: list[Callable] = [
347
380
  RShift,
348
381
  LShift,
349
382
  mod_inverse,
383
+ min_wrapper,
384
+ Min_wrapper,
385
+ max_wrapper,
386
+ Max_wrapper,
350
387
  ]
351
388
 
352
389
 
@@ -39,14 +39,14 @@ from classiq.interface.model.quantum_lambda_function import (
39
39
  )
40
40
  from classiq.interface.model.quantum_statement import QuantumStatement
41
41
 
42
+ from classiq.evaluators.classical_expression import (
43
+ evaluate_classical_expression,
44
+ )
42
45
  from classiq.model_expansions.closure import (
43
46
  Closure,
44
47
  FunctionClosure,
45
48
  )
46
49
  from classiq.model_expansions.debug_flag import debug_mode
47
- from classiq.model_expansions.evaluators.classical_expression import (
48
- evaluate_classical_expression,
49
- )
50
50
  from classiq.model_expansions.function_builder import (
51
51
  FunctionContext,
52
52
  OperationBuilder,
@@ -12,7 +12,7 @@ from classiq.interface.model.quantum_type import (
12
12
  QuantumNumeric,
13
13
  )
14
14
 
15
- from classiq.model_expansions.evaluators.quantum_type_utils import copy_type_information
15
+ from classiq.evaluators.quantum_type_utils import copy_type_information
16
16
  from classiq.model_expansions.quantum_operations.emitter import Emitter
17
17
  from classiq.model_expansions.scope import QuantumSymbol
18
18
 
@@ -24,7 +24,7 @@ from classiq.interface.model.variable_declaration_statement import (
24
24
  )
25
25
  from classiq.interface.model.within_apply_operation import WithinApply
26
26
 
27
- from classiq.model_expansions.evaluators.quantum_type_utils import copy_type_information
27
+ from classiq.evaluators.quantum_type_utils import copy_type_information
28
28
  from classiq.model_expansions.quantum_operations.arithmetic.explicit_boolean_expressions import (
29
29
  convert_assignment_bool_expression,
30
30
  validate_assignment_bool_expression,
@@ -8,10 +8,10 @@ from classiq.interface.exceptions import (
8
8
  from classiq.interface.model.bind_operation import BindOperation
9
9
  from classiq.interface.model.quantum_type import QuantumNumeric
10
10
 
11
- from classiq.model_expansions.evaluators.parameter_types import (
11
+ from classiq.evaluators.parameter_types import (
12
12
  evaluate_types_in_quantum_symbols,
13
13
  )
14
- from classiq.model_expansions.evaluators.quantum_type_utils import (
14
+ from classiq.evaluators.quantum_type_utils import (
15
15
  set_size,
16
16
  validate_bind_targets,
17
17
  )