classiq 0.63.1__py3-none-any.whl → 0.65.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 (77) hide show
  1. classiq/_internals/api_wrapper.py +30 -0
  2. classiq/analyzer/url_utils.py +2 -3
  3. classiq/applications/chemistry/chemistry_model_constructor.py +8 -9
  4. classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py +4 -6
  5. classiq/applications/combinatorial_optimization/combinatorial_problem.py +2 -5
  6. classiq/applications/finance/finance_model_constructor.py +7 -12
  7. classiq/applications/grover/grover_model_constructor.py +4 -6
  8. classiq/applications/qsvm/qsvm_model_constructor.py +6 -4
  9. classiq/execution/execution_session.py +14 -13
  10. classiq/interface/_version.py +1 -1
  11. classiq/interface/analyzer/result.py +1 -2
  12. classiq/interface/backend/backend_preferences.py +1 -9
  13. classiq/interface/executor/result.py +6 -3
  14. classiq/interface/generator/expressions/qmod_qarray_proxy.py +11 -13
  15. classiq/interface/generator/functions/type_name.py +6 -0
  16. classiq/interface/helpers/datastructures.py +26 -0
  17. classiq/interface/interface_version.py +1 -1
  18. classiq/interface/model/allocate.py +16 -0
  19. classiq/interface/model/handle_binding.py +11 -3
  20. classiq/interface/model/quantum_type.py +26 -0
  21. classiq/interface/model/statement_block.py +2 -0
  22. classiq/interface/server/routes.py +5 -0
  23. classiq/model_expansions/atomic_expression_functions_defs.py +6 -6
  24. classiq/model_expansions/capturing/captured_vars.py +27 -10
  25. classiq/model_expansions/evaluators/arg_type_match.py +4 -7
  26. classiq/model_expansions/evaluators/quantum_type_utils.py +25 -8
  27. classiq/model_expansions/expression_evaluator.py +8 -2
  28. classiq/model_expansions/function_builder.py +35 -11
  29. classiq/model_expansions/generative_functions.py +6 -4
  30. classiq/model_expansions/interpreters/__init__.py +0 -0
  31. classiq/model_expansions/interpreters/base_interpreter.py +263 -0
  32. classiq/model_expansions/interpreters/frontend_generative_interpreter.py +28 -0
  33. classiq/model_expansions/interpreters/generative_interpreter.py +249 -0
  34. classiq/model_expansions/model_tables.py +1 -92
  35. classiq/model_expansions/quantum_operations/__init__.py +0 -10
  36. classiq/model_expansions/quantum_operations/call_emitter.py +45 -93
  37. classiq/model_expansions/quantum_operations/declarative_call_emitter.py +87 -0
  38. classiq/model_expansions/quantum_operations/emitter.py +7 -2
  39. classiq/model_expansions/quantum_operations/quantum_function_call.py +11 -2
  40. classiq/model_expansions/quantum_operations/shallow_emitter.py +22 -3
  41. classiq/model_expansions/scope.py +15 -15
  42. classiq/model_expansions/scope_initialization.py +11 -5
  43. classiq/open_library/functions/discrete_sine_cosine_transform.py +8 -2
  44. classiq/open_library/functions/grover.py +1 -1
  45. classiq/open_library/functions/modular_exponentiation.py +8 -2
  46. classiq/open_library/functions/state_preparation.py +23 -13
  47. classiq/open_library/functions/swap_test.py +1 -2
  48. classiq/open_library/functions/variational.py +1 -2
  49. classiq/qmod/builtins/__init__.py +1 -1
  50. classiq/qmod/builtins/operations.py +51 -0
  51. classiq/qmod/declaration_inferrer.py +0 -3
  52. classiq/qmod/generative.py +4 -4
  53. classiq/qmod/native/pretty_printer.py +9 -1
  54. classiq/qmod/pretty_print/pretty_printer.py +12 -1
  55. classiq/qmod/qfunc.py +4 -2
  56. classiq/qmod/qmod_variable.py +55 -48
  57. classiq/qmod/quantum_function.py +7 -5
  58. classiq/qmod/semantics/annotation/__init__.py +0 -0
  59. classiq/qmod/semantics/annotation/call_annotation.py +92 -0
  60. classiq/qmod/semantics/lambdas.py +25 -0
  61. classiq/qmod/semantics/static_semantics_visitor.py +8 -46
  62. classiq/qmod/utilities.py +23 -1
  63. {classiq-0.63.1.dist-info → classiq-0.65.1.dist-info}/METADATA +1 -1
  64. {classiq-0.63.1.dist-info → classiq-0.65.1.dist-info}/RECORD +66 -67
  65. classiq/interface/helpers/dotdict.py +0 -18
  66. classiq/model_expansions/interpreter.py +0 -475
  67. classiq/model_expansions/quantum_operations/control.py +0 -290
  68. classiq/model_expansions/quantum_operations/expression_operation.py +0 -103
  69. classiq/model_expansions/quantum_operations/inplace_binary_operation.py +0 -535
  70. classiq/model_expansions/quantum_operations/invert.py +0 -36
  71. classiq/model_expansions/quantum_operations/phase.py +0 -187
  72. classiq/model_expansions/quantum_operations/power.py +0 -71
  73. classiq/model_expansions/quantum_operations/quantum_assignment_operation.py +0 -230
  74. classiq/model_expansions/quantum_operations/within_apply.py +0 -25
  75. classiq/qmod/semantics/annotation.py +0 -36
  76. /classiq/qmod/semantics/{qstruct_annotator.py → annotation/qstruct_annotator.py} +0 -0
  77. {classiq-0.63.1.dist-info → classiq-0.65.1.dist-info}/WHEEL +0 -0
@@ -22,6 +22,7 @@ from classiq.interface.execution.jobs import (
22
22
  ExecutionJobDetailsV1,
23
23
  ExecutionJobsQueryResultsV1,
24
24
  )
25
+ from classiq.interface.execution.primitives import PrimitivesInput
25
26
  from classiq.interface.executor import execution_request
26
27
  from classiq.interface.generator import quantum_program as generator_result
27
28
  from classiq.interface.hardware import HardwareInformation, Provider
@@ -120,6 +121,35 @@ class ApiWrapper:
120
121
  )
121
122
  return _parse_job_response(result, generator_result.QuantumProgram)
122
123
 
124
+ @classmethod
125
+ async def call_create_execution_session(
126
+ cls,
127
+ circuit: generator_result.QuantumProgram,
128
+ http_client: Optional[httpx.AsyncClient] = None,
129
+ ) -> str:
130
+ raw_result = await cls._call_task_pydantic(
131
+ http_method=HTTPMethod.POST,
132
+ url=routes.EXECUTION_SESSIONS_PREFIX,
133
+ model=circuit,
134
+ http_client=http_client,
135
+ )
136
+ return raw_result["id"]
137
+
138
+ @classmethod
139
+ async def call_create_session_job(
140
+ cls,
141
+ session_id: str,
142
+ primitives_input: PrimitivesInput,
143
+ http_client: Optional[httpx.AsyncClient] = None,
144
+ ) -> execution_request.ExecutionJobDetails:
145
+ data = await cls._call_task_pydantic(
146
+ http_method=HTTPMethod.POST,
147
+ url=routes.EXECUTION_SESSIONS_PREFIX + f"/{session_id}",
148
+ model=primitives_input,
149
+ http_client=http_client,
150
+ )
151
+ return execution_request.ExecutionJobDetails.model_validate(data)
152
+
123
153
  @classmethod
124
154
  async def call_convert_quantum_program(
125
155
  cls,
@@ -1,6 +1,5 @@
1
1
  import urllib
2
2
  from urllib.parse import urljoin
3
- from uuid import UUID
4
3
 
5
4
  from classiq.interface.server import routes
6
5
 
@@ -21,7 +20,7 @@ def versioned_url_params(circuit_version: str) -> str:
21
20
  )
22
21
 
23
22
 
24
- def circuit_page_uri(circuit_id: UUID, circuit_version: str) -> str:
25
- url = urljoin(f"{routes.ANALYZER_CIRCUIT_PAGE}/", str(circuit_id))
23
+ def circuit_page_uri(circuit_id: str, circuit_version: str) -> str:
24
+ url = urljoin(f"{routes.ANALYZER_CIRCUIT_PAGE}/", circuit_id)
26
25
  url += versioned_url_params(circuit_version=circuit_version)
27
26
  return url
@@ -7,6 +7,8 @@ from classiq.interface.chemistry.fermionic_operator import (
7
7
  FermionicOperator,
8
8
  SummedFermionicOperator,
9
9
  )
10
+ from classiq.interface.model.allocate import Allocate
11
+ from classiq.interface.model.quantum_statement import QuantumStatement
10
12
  from classiq.qmod.builtins.structs import (
11
13
  MoleculeProblem as QmodMoleculeProblem,
12
14
  Molecule as QmodMolecule,
@@ -441,16 +443,13 @@ def _get_chemistry_quantum_main(
441
443
  use_hartree_fock: bool,
442
444
  ansatz_parameters: AnsatzParameters,
443
445
  ) -> NativeFunctionDefinition:
444
- body = []
446
+ body: list[QuantumStatement] = []
445
447
  body.append(
446
- QuantumFunctionCall(
447
- function="allocate",
448
- positional_args=[
449
- Expression(
450
- expr=f"get_field(get_field({_get_problem_to_hamiltonian_name(chemistry_problem)}({_convert_library_problem_to_qmod_problem(chemistry_problem)})[0], 'pauli'), 'len')"
451
- ),
452
- HandleBinding(name="qbv"),
453
- ],
448
+ Allocate(
449
+ size=Expression(
450
+ expr=f"get_field(get_field({_get_problem_to_hamiltonian_name(chemistry_problem)}({_convert_library_problem_to_qmod_problem(chemistry_problem)})[0], 'pauli'), 'len')"
451
+ ),
452
+ target=HandleBinding(name="qbv"),
454
453
  ),
455
454
  )
456
455
  if use_hartree_fock:
@@ -14,6 +14,7 @@ from classiq.interface.generator.functions.port_declaration import (
14
14
  PortDeclarationDirection,
15
15
  )
16
16
  from classiq.interface.generator.functions.type_name import Struct
17
+ from classiq.interface.model.allocate import Allocate
17
18
  from classiq.interface.model.classical_parameter_declaration import (
18
19
  ClassicalParameterDeclaration,
19
20
  )
@@ -89,12 +90,9 @@ def construct_combi_opt_py_model(
89
90
  ),
90
91
  ],
91
92
  body=[
92
- QuantumFunctionCall(
93
- function="allocate",
94
- positional_args=[
95
- Expression(expr="get_field(target, 'len')"),
96
- HandleBinding(name="target"),
97
- ],
93
+ Allocate(
94
+ size=Expression(expr="get_field(target, 'len')"),
95
+ target=HandleBinding(name="target"),
98
96
  ),
99
97
  QuantumFunctionCall(
100
98
  function="qaoa_penalty",
@@ -21,11 +21,8 @@ from classiq.open_library.functions.utility_functions import (
21
21
  apply_to_all,
22
22
  hadamard_transform,
23
23
  )
24
- from classiq.qmod.builtins.functions import (
25
- RX,
26
- allocate,
27
- )
28
- from classiq.qmod.builtins.operations import phase, repeat
24
+ from classiq.qmod.builtins.functions import RX
25
+ from classiq.qmod.builtins.operations import allocate, phase, repeat
29
26
  from classiq.qmod.cparam import CReal
30
27
  from classiq.qmod.create_model_function import create_model
31
28
  from classiq.qmod.qfunc import qfunc
@@ -9,6 +9,7 @@ from classiq.interface.generator.expressions.expression import Expression
9
9
  from classiq.interface.generator.functions.port_declaration import (
10
10
  PortDeclarationDirection,
11
11
  )
12
+ from classiq.interface.model.allocate import Allocate
12
13
  from classiq.interface.model.handle_binding import HandleBinding
13
14
  from classiq.interface.model.model import Model, SerializedModel
14
15
  from classiq.interface.model.native_function_definition import NativeFunctionDefinition
@@ -78,19 +79,13 @@ def construct_finance_model(
78
79
  ],
79
80
  body=[
80
81
  VariableDeclarationStatement(name="unitary_port"),
81
- QuantumFunctionCall(
82
- function="allocate",
83
- positional_args=[
84
- Expression(expr=f"{num_unitary_qubits}"),
85
- HandleBinding(name="unitary_port"),
86
- ],
82
+ Allocate(
83
+ size=Expression(expr=f"{num_unitary_qubits}"),
84
+ target=HandleBinding(name="unitary_port"),
87
85
  ),
88
- QuantumFunctionCall(
89
- function="allocate",
90
- positional_args=[
91
- Expression(expr=f"{phase_port_size}"),
92
- HandleBinding(name="phase_port"),
93
- ],
86
+ Allocate(
87
+ size=Expression(expr=f"{phase_port_size}"),
88
+ target=HandleBinding(name="phase_port"),
94
89
  ),
95
90
  QuantumFunctionCall(
96
91
  function="qmci",
@@ -2,6 +2,7 @@ from classiq.interface.generator.expressions.expression import Expression
2
2
  from classiq.interface.generator.functions.port_declaration import (
3
3
  PortDeclarationDirection,
4
4
  )
5
+ from classiq.interface.model.allocate import Allocate
5
6
  from classiq.interface.model.bind_operation import BindOperation
6
7
  from classiq.interface.model.handle_binding import HandleBinding, SlicedHandleBinding
7
8
  from classiq.interface.model.model import Model, SerializedModel
@@ -121,12 +122,9 @@ def construct_grover_model(
121
122
  ),
122
123
  body=[
123
124
  VariableDeclarationStatement(name="packed_vars"),
124
- QuantumFunctionCall(
125
- function="allocate",
126
- positional_args=[
127
- Expression(expr=f"{num_qubits}"),
128
- HandleBinding(name="packed_vars"),
129
- ],
125
+ Allocate(
126
+ size=Expression(expr=f"{num_qubits}"),
127
+ target=HandleBinding(name="packed_vars"),
130
128
  ),
131
129
  QuantumFunctionCall(
132
130
  function="grover_search",
@@ -6,11 +6,13 @@ from classiq.interface.generator.expressions.expression import Expression
6
6
  from classiq.interface.generator.functions.port_declaration import (
7
7
  PortDeclarationDirection,
8
8
  )
9
+ from classiq.interface.model.allocate import Allocate
9
10
  from classiq.interface.model.handle_binding import HandleBinding
10
11
  from classiq.interface.model.model import Model, SerializedModel
11
12
  from classiq.interface.model.native_function_definition import NativeFunctionDefinition
12
13
  from classiq.interface.model.port_declaration import PortDeclaration
13
14
  from classiq.interface.model.quantum_function_call import QuantumFunctionCall
15
+ from classiq.interface.model.quantum_statement import QuantumStatement
14
16
 
15
17
  from classiq.qmod.builtins.enums import Pauli, QSVMFeatureMapEntanglement
16
18
  from classiq.qmod.utilities import qmod_val_to_expr_str
@@ -61,7 +63,7 @@ def _pauli_feature_map_function_params(
61
63
 
62
64
  def get_qsvm_qmain_body(
63
65
  feature_map_function_name: str, **kwargs: Any
64
- ) -> list[QuantumFunctionCall]:
66
+ ) -> list[QuantumStatement]:
65
67
  if feature_map_function_name == "bloch_sphere_feature_map":
66
68
  params, size_expr = _bloch_sphere_feature_map_function_params(**kwargs)
67
69
  elif feature_map_function_name == "pauli_feature_map":
@@ -70,9 +72,9 @@ def get_qsvm_qmain_body(
70
72
  raise ClassiqValueError(INVALID_FEATURE_MAP_FUNC_NAME_MSG)
71
73
 
72
74
  return [
73
- QuantumFunctionCall(
74
- function="allocate",
75
- positional_args=[Expression(expr=size_expr), HandleBinding(name="qbv")],
75
+ Allocate(
76
+ size=Expression(expr=size_expr),
77
+ target=HandleBinding(name="qbv"),
76
78
  ),
77
79
  QuantumFunctionCall(
78
80
  function=feature_map_function_name,
@@ -1,6 +1,5 @@
1
1
  import json
2
2
  import random
3
- from functools import cached_property
4
3
  from types import TracebackType
5
4
  from typing import Callable, Optional, Union, cast
6
5
 
@@ -110,6 +109,8 @@ class ExecutionSession:
110
109
 
111
110
  self._async_client = client().async_client()
112
111
 
112
+ self._session_id: str | None = None
113
+
113
114
  def __enter__(self) -> "ExecutionSession":
114
115
  return self
115
116
 
@@ -127,22 +128,22 @@ class ExecutionSession:
127
128
  """
128
129
  async_utils.run(self._async_client.aclose())
129
130
 
130
- @cached_property
131
- def _execution_input(self) -> dict:
132
- return async_utils.run(
133
- ApiWrapper.call_convert_quantum_program(self.program, self._async_client)
134
- )
131
+ def get_session_id(self) -> str:
132
+ if self._session_id is None:
133
+ self._session_id = async_utils.run(
134
+ ApiWrapper.call_create_execution_session(
135
+ self.program, self._async_client
136
+ )
137
+ )
138
+ return self._session_id
135
139
 
136
140
  def _execute(self, primitives_input: PrimitivesInput) -> ExecutionJob:
137
141
  primitives_input.random_seed = self._random_seed
138
142
  self._random_seed = self._rng.randint(0, 2**32 - 1)
139
- execution_input = self._execution_input.copy()
140
- # The use of `model_dump_json` is necessary for complex numbers serialization
141
- execution_input["primitives_input"] = json.loads(
142
- primitives_input.model_dump_json()
143
- )
144
143
  result = async_utils.run(
145
- ApiWrapper.call_execute_execution_input(execution_input, self._async_client)
144
+ ApiWrapper.call_create_session_job(
145
+ self.get_session_id(), primitives_input, self._async_client
146
+ )
146
147
  )
147
148
  return ExecutionJob(details=result)
148
149
 
@@ -360,7 +361,7 @@ class ExecutionSession:
360
361
  output_name: The name of the register to filter
361
362
  condition: Filter out values of the statevector for which this callable is False
362
363
  """
363
- if "_execution_input" in self.__dict__:
364
+ if self._session_id is not None:
364
365
  raise ClassiqError(
365
366
  "set_measured_state_filter must be called before use of the first primitive (sample, estimate...)"
366
367
  )
@@ -3,5 +3,5 @@ from packaging.version import Version
3
3
  # This file was generated automatically
4
4
  # Please don't track in version control (DONTTRACK)
5
5
 
6
- SEMVER_VERSION = '0.63.1'
6
+ SEMVER_VERSION = '0.65.1'
7
7
  VERSION = str(Version(SEMVER_VERSION))
@@ -1,5 +1,4 @@
1
1
  from typing import Annotated, Literal, Optional, Union
2
- from uuid import UUID
3
2
 
4
3
  import pydantic
5
4
  from pydantic import Field
@@ -34,7 +33,7 @@ class RbResults(VersionedModel):
34
33
 
35
34
 
36
35
  class DataID(pydantic.BaseModel):
37
- id: UUID
36
+ id: str
38
37
 
39
38
 
40
39
  class QasmCode(pydantic.BaseModel):
@@ -22,7 +22,7 @@ from classiq.interface.backend.quantum_backend_providers import (
22
22
  ProviderTypeVendor,
23
23
  ProviderVendor,
24
24
  )
25
- from classiq.interface.exceptions import ClassiqDeprecationWarning, ClassiqValueError
25
+ from classiq.interface.exceptions import ClassiqDeprecationWarning
26
26
  from classiq.interface.hardware import Provider
27
27
 
28
28
 
@@ -225,14 +225,6 @@ class AwsBackendPreferences(BackendPreferences):
225
225
  description="Run through Classiq's credentials while using user's allocated budget.",
226
226
  )
227
227
 
228
- @pydantic.field_validator("s3_bucket_name", mode="before")
229
- @classmethod
230
- def _validate_s3_bucket_name(cls, s3_bucket_name: str) -> str:
231
- s3_bucket_name = s3_bucket_name.strip()
232
- if not s3_bucket_name.startswith("amazon-braket-"):
233
- raise ClassiqValueError('S3 bucket name should start with "amazon-braket-"')
234
- return s3_bucket_name
235
-
236
228
 
237
229
  class IBMBackendProvider(BaseModel):
238
230
  """
@@ -20,7 +20,7 @@ from classiq.interface.generator.arith import number_utils
20
20
  from classiq.interface.generator.complex_type import Complex
21
21
  from classiq.interface.generator.functions.classical_type import QmodPyObject
22
22
  from classiq.interface.helpers.custom_pydantic_types import PydanticNonNegIntTuple
23
- from classiq.interface.helpers.dotdict import get_recursive_dotdict
23
+ from classiq.interface.helpers.datastructures import get_sdk_compatible_python_object
24
24
  from classiq.interface.helpers.versioned_model import VersionedModel
25
25
 
26
26
  _ILLEGAL_QUBIT_ERROR_MSG: str = "Illegal qubit index requested"
@@ -51,8 +51,11 @@ class SampledState(BaseModel):
51
51
 
52
52
  @pydantic.field_validator("state", mode="after")
53
53
  @classmethod
54
- def _convert_state_to_dotdict(cls, state: ParsedState) -> DotAccessParsedState:
55
- return {name: get_recursive_dotdict(value) for name, value in state.items()}
54
+ def _make_state_sdk_compatible(cls, state: ParsedState) -> DotAccessParsedState:
55
+ return {
56
+ name: get_sdk_compatible_python_object(value)
57
+ for name, value in state.items()
58
+ }
56
59
 
57
60
 
58
61
  ParsedCounts: TypeAlias = list[SampledState]
@@ -3,7 +3,10 @@ from typing import TYPE_CHECKING, Any, Union
3
3
 
4
4
  from sympy import Integer
5
5
 
6
- from classiq.interface.exceptions import ClassiqValueError
6
+ from classiq.interface.exceptions import (
7
+ ClassiqInternalExpansionError,
8
+ ClassiqValueError,
9
+ )
7
10
  from classiq.interface.generator.expressions.expression import Expression
8
11
  from classiq.interface.generator.expressions.non_symbolic_expr import NonSymbolicExpr
9
12
  from classiq.interface.generator.expressions.qmod_sized_proxy import QmodSizedProxy
@@ -18,12 +21,7 @@ if TYPE_CHECKING:
18
21
 
19
22
 
20
23
  ILLEGAL_SLICING_STEP_MSG = "Slicing with a step of a quantum variable is not supported"
21
- SLICE_OUT_OF_BOUNDS_MSG = "Slice indices out of bounds"
22
- SUBSCRIPT_OUT_OF_BOUNDS_MSG = "Subscript index out of bounds"
23
24
  ILLEGAL_SLICE_MSG = "Quantum array slice must be of the form [<int-value>:<int-value>]."
24
- ILLEGAL_SLICE_BOUNDS_MSG = (
25
- "The quantum array slice start value ({}) must be lower than its stop value ({})."
26
- )
27
25
 
28
26
 
29
27
  class QmodQArrayProxy(NonSymbolicExpr, QmodSizedProxy):
@@ -48,7 +46,7 @@ class QmodQArrayProxy(NonSymbolicExpr, QmodSizedProxy):
48
46
  if isinstance(index, Integer):
49
47
  index = int(index)
50
48
  if index < 0 or index >= self._length:
51
- raise ClassiqValueError(SUBSCRIPT_OUT_OF_BOUNDS_MSG)
49
+ raise ClassiqInternalExpansionError
52
50
 
53
51
  return self._element_type.get_proxy(
54
52
  SubscriptHandleBinding(
@@ -66,12 +64,12 @@ class QmodQArrayProxy(NonSymbolicExpr, QmodSizedProxy):
66
64
  slice_ = slice(slice_.start, int(slice_.stop))
67
65
  if not isinstance(slice_.start, int) or not isinstance(slice_.stop, int):
68
66
  raise ClassiqValueError(ILLEGAL_SLICE_MSG)
69
- if slice_.start >= slice_.stop:
70
- raise ClassiqValueError(
71
- ILLEGAL_SLICE_BOUNDS_MSG.format(slice_.start, slice_.stop)
72
- )
73
- if slice_.start < 0 or slice_.stop > self._length:
74
- raise ClassiqValueError(SLICE_OUT_OF_BOUNDS_MSG)
67
+ if (
68
+ slice_.start >= slice_.stop
69
+ or slice_.start < 0
70
+ or slice_.stop > self._length
71
+ ):
72
+ raise ClassiqInternalExpansionError
75
73
 
76
74
  return QmodQArrayProxy(
77
75
  SlicedHandleBinding(
@@ -75,6 +75,12 @@ class TypeName(ClassicalType, QuantumType):
75
75
  field_type.is_instantiated for field_type in self.fields.values()
76
76
  )
77
77
 
78
+ @property
79
+ def is_evaluated(self) -> bool:
80
+ return self.has_fields and all(
81
+ field_type.is_evaluated for field_type in self.fields.values()
82
+ )
83
+
78
84
 
79
85
  class Enum(TypeName):
80
86
  pass
@@ -0,0 +1,26 @@
1
+ from typing import Any
2
+
3
+
4
+ class DotDict(dict):
5
+ def __getattr__(self, key: str) -> Any:
6
+ return super().get(key)
7
+
8
+ def __setattr__(self, key: str, value: Any) -> None:
9
+ super().__setitem__(key, value)
10
+
11
+ def __delattr__(self, key: str) -> None:
12
+ super().__delitem__(key)
13
+
14
+
15
+ class LenList(list):
16
+ @property
17
+ def len(self) -> int:
18
+ return len(self)
19
+
20
+
21
+ def get_sdk_compatible_python_object(obj: Any) -> Any:
22
+ if isinstance(obj, list):
23
+ return LenList([get_sdk_compatible_python_object(item) for item in obj])
24
+ if isinstance(obj, dict):
25
+ return DotDict({k: get_sdk_compatible_python_object(v) for k, v in obj.items()})
26
+ return obj
@@ -1 +1 @@
1
- INTERFACE_VERSION = "6"
1
+ INTERFACE_VERSION = "7"
@@ -0,0 +1,16 @@
1
+ from collections.abc import Mapping
2
+ from typing import Literal, Optional
3
+
4
+ from classiq.interface.generator.expressions.expression import Expression
5
+ from classiq.interface.model.handle_binding import ConcreteHandleBinding, HandleBinding
6
+ from classiq.interface.model.quantum_statement import QuantumOperation
7
+
8
+
9
+ class Allocate(QuantumOperation):
10
+ kind: Literal["Allocate"]
11
+ size: Optional[Expression] = None
12
+ target: ConcreteHandleBinding
13
+
14
+ @property
15
+ def wiring_outputs(self) -> Mapping[str, HandleBinding]:
16
+ return {"out": self.target}
@@ -243,15 +243,23 @@ class SlicedHandleBinding(NestedHandleBinding):
243
243
  def _get_collapsed_stop(self) -> Expression:
244
244
  if TYPE_CHECKING:
245
245
  assert isinstance(self.base_handle, SlicedHandleBinding)
246
- if self.end.is_evaluated() and self.base_handle.end.is_evaluated():
246
+ if self._is_evaluated() and self.base_handle.start.is_evaluated():
247
247
  return Expression(
248
- expr=str(self.base_handle.end.to_int_value() - self.end.to_int_value())
248
+ expr=str(
249
+ self.end.to_int_value()
250
+ - self.start.to_int_value()
251
+ + self.base_handle.start.to_int_value()
252
+ )
249
253
  )
250
- return Expression(expr=f"({self.base_handle.end})-({self.end})")
254
+ return Expression(
255
+ expr=f"({self.end})-({self.start})+({self.base_handle.start})"
256
+ )
251
257
 
252
258
  def replace_prefix(
253
259
  self, prefix: HandleBinding, replacement: HandleBinding
254
260
  ) -> HandleBinding:
261
+ if self == prefix:
262
+ return replacement
255
263
  if (
256
264
  isinstance(prefix, SlicedHandleBinding)
257
265
  and self.base_handle == prefix.base_handle
@@ -63,6 +63,10 @@ class QuantumType(HashableASTNode):
63
63
  def is_instantiated(self) -> bool:
64
64
  raise NotImplementedError
65
65
 
66
+ @property
67
+ def is_evaluated(self) -> bool:
68
+ raise NotImplementedError
69
+
66
70
 
67
71
  class QuantumScalar(QuantumType):
68
72
  def get_proxy(self, handle: "HandleBinding") -> QmodQScalarProxy:
@@ -96,6 +100,10 @@ class QuantumBit(QuantumScalar):
96
100
  def is_instantiated(self) -> bool:
97
101
  return True
98
102
 
103
+ @property
104
+ def is_evaluated(self) -> bool:
105
+ return True
106
+
99
107
 
100
108
  class QuantumBitvector(QuantumType):
101
109
  element_type: "ConcreteQuantumType" = Field(
@@ -154,6 +162,14 @@ class QuantumBitvector(QuantumType):
154
162
  def is_instantiated(self) -> bool:
155
163
  return self.length is not None and self.element_type.is_instantiated
156
164
 
165
+ @property
166
+ def is_evaluated(self) -> bool:
167
+ return (
168
+ self.length is not None
169
+ and self.length.is_evaluated()
170
+ and self.element_type.is_evaluated
171
+ )
172
+
157
173
 
158
174
  class QuantumNumeric(QuantumScalar):
159
175
  kind: Literal["qnum"]
@@ -227,6 +243,16 @@ class QuantumNumeric(QuantumScalar):
227
243
  def is_instantiated(self) -> bool:
228
244
  return self.size is not None
229
245
 
246
+ @property
247
+ def is_evaluated(self) -> bool:
248
+ if self.size is None or not self.size.is_evaluated():
249
+ return False
250
+ if self.is_signed is not None and not self.is_signed.is_evaluated():
251
+ return False
252
+ return not (
253
+ self.fraction_digits is not None and not self.fraction_digits.is_evaluated()
254
+ )
255
+
230
256
 
231
257
  class RegisterQuantumType(BaseModel):
232
258
  quantum_types: "ConcreteQuantumType"
@@ -2,6 +2,7 @@ from typing import Annotated, Union
2
2
 
3
3
  from pydantic import Field
4
4
 
5
+ from classiq.interface.model.allocate import Allocate
5
6
  from classiq.interface.model.bind_operation import BindOperation
6
7
  from classiq.interface.model.classical_if import ClassicalIf
7
8
  from classiq.interface.model.control import Control
@@ -26,6 +27,7 @@ from classiq.interface.model.within_apply_operation import WithinApply
26
27
 
27
28
  ConcreteQuantumStatement = Annotated[
28
29
  Union[
30
+ Allocate,
29
31
  QuantumFunctionCall,
30
32
  ArithmeticOperation,
31
33
  AmplitudeLoadingOperation,
@@ -1,6 +1,7 @@
1
1
  ANALYZER_PREFIX = "/analyzer"
2
2
  CHEMISTRY_PREFIX = "/chemistry"
3
3
  EXECUTION_PREFIX = "/execution"
4
+ EXECUTION_SESSIONS_PREFIX = EXECUTION_PREFIX + "/sessions"
4
5
  CONVERSION_PREFIX = "/conversion"
5
6
  PROVIDERS_PREFIX = "/providers"
6
7
 
@@ -24,12 +25,16 @@ TASKS_SUFFIX = "/tasks"
24
25
  RB = "/rb"
25
26
  ANALYZER_DATA_TASK = f"{TASKS_SUFFIX}/data"
26
27
  ANALYZER_QASM_TASK = f"{TASKS_SUFFIX}/qasm"
28
+ ANALYZER_GET_VISUAL_MODEL = "/get_visual_model"
29
+ ANALYZER_GET_IDE_DATA = "/get_ide_data"
27
30
  IDE_EVENT_TASK = f"{TASKS_SUFFIX}/event"
28
31
  DATA_DOG_EVENT_TASK = f"{TASKS_SUFFIX}/data_dog_event"
29
32
 
30
33
  ANALYZER_DATA_TASK_UPLOAD_FILE = f"{TASKS_SUFFIX}/data/file_upload"
31
34
  ANALYZER_DATA_FULL_PATH = f"{ANALYZER_PREFIX}{ANALYZER_DATA_TASK}"
32
35
  ANALYZER_QASM_FULL_PATH = f"{ANALYZER_PREFIX}{ANALYZER_QASM_TASK}"
36
+ ANALYZER_GET_VISUAL_MODEL_FULL_PATH = f"{ANALYZER_PREFIX}{ANALYZER_GET_VISUAL_MODEL}"
37
+ ANALYZER_GET_IDE_DATA_FULL_PATH = f"{ANALYZER_PREFIX}{ANALYZER_GET_IDE_DATA}"
33
38
  IDE_EVENT_TASK_FULL_PATH = f"{ANALYZER_PREFIX}{IDE_EVENT_TASK}"
34
39
  DATA_DOG_EVENT_TASK_FULL_PATH = f"{ANALYZER_PREFIX}{DATA_DOG_EVENT_TASK}"
35
40
 
@@ -33,7 +33,6 @@ from classiq.interface.generator.functions.type_name import TypeName
33
33
  from classiq.model_expansions.model_tables import (
34
34
  HandleIdentifier,
35
35
  HandleTable,
36
- SymbolTable,
37
36
  )
38
37
  from classiq.model_expansions.sympy_conversion.arithmetics import (
39
38
  BitwiseAnd,
@@ -48,13 +47,14 @@ from classiq.model_expansions.sympy_conversion.expression_to_sympy import (
48
47
  from classiq.model_expansions.sympy_conversion.sympy_to_python import (
49
48
  sympy_to_python,
50
49
  )
50
+ from classiq.qmod.model_state_container import QMODULE
51
51
 
52
52
 
53
53
  def qmod_val_to_python(val: ExpressionValue, qmod_type: ClassicalType) -> Any:
54
54
  if isinstance(qmod_type, TypeName):
55
55
  if (
56
56
  isinstance(val, QmodStructInstance)
57
- and val.struct_declaration == SymbolTable.type_table[qmod_type.name]
57
+ and val.struct_declaration == QMODULE.type_decls[qmod_type.name]
58
58
  ):
59
59
  return {
60
60
  field_name: qmod_val_to_python(val.fields[field_name], field_type)
@@ -97,10 +97,10 @@ def qmod_val_to_python(val: ExpressionValue, qmod_type: ClassicalType) -> Any:
97
97
 
98
98
  def python_val_to_qmod(val: Any, qmod_type: ClassicalType) -> ExpressionValue:
99
99
  if isinstance(qmod_type, TypeName):
100
- if qmod_type.name in SymbolTable.enum_table:
100
+ if qmod_type.name in QMODULE.enum_decls:
101
101
  return val
102
102
 
103
- struct_decl = SymbolTable.type_table[qmod_type.name]
103
+ struct_decl = QMODULE.type_decls[qmod_type.name]
104
104
  if not isinstance(val, Mapping):
105
105
  raise ClassiqInternalExpansionError(
106
106
  f"Bad value for struct {struct_decl.name}"
@@ -138,7 +138,7 @@ def python_call_wrapper(func: Callable, *args: ExpressionValue) -> Any:
138
138
 
139
139
  def struct_literal(struct_type_symbol: Symbol, **kwargs: Any) -> QmodStructInstance:
140
140
  return QmodStructInstance(
141
- SymbolTable.type_table[struct_type_symbol.name],
141
+ QMODULE.type_decls[struct_type_symbol.name],
142
142
  {field: sympy_to_python(field_value) for field, field_value in kwargs.items()},
143
143
  )
144
144
 
@@ -179,7 +179,7 @@ def get_field(
179
179
 
180
180
 
181
181
  def get_type(struct_type: Symbol) -> TypeProxy:
182
- return TypeProxy(SymbolTable.type_table[struct_type.name])
182
+ return TypeProxy(QMODULE.type_decls[struct_type.name])
183
183
 
184
184
 
185
185
  def _unwrap_sympy_numeric(n: Any) -> Any: