classiq 0.41.2__py3-none-any.whl → 0.42.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 (48) hide show
  1. classiq/applications/chemistry/chemistry_model_constructor.py +31 -31
  2. classiq/execution/execution_session.py +42 -3
  3. classiq/interface/_version.py +1 -1
  4. classiq/interface/analyzer/analysis_params.py +16 -6
  5. classiq/interface/analyzer/result.py +2 -1
  6. classiq/interface/ast_node.py +2 -2
  7. classiq/interface/backend/pydantic_backend.py +1 -3
  8. classiq/interface/chemistry/fermionic_operator.py +17 -7
  9. classiq/interface/generator/amplitude_loading.py +12 -3
  10. classiq/interface/generator/application_apis/finance_declarations.py +22 -1
  11. classiq/interface/generator/expressions/atomic_expression_functions.py +2 -1
  12. classiq/interface/generator/expressions/enums/classical_enum.py +11 -0
  13. classiq/interface/generator/expressions/enums/ladder_operator.py +0 -10
  14. classiq/interface/generator/expressions/expression_constants.py +1 -0
  15. classiq/interface/generator/expressions/qmod_qarray_proxy.py +14 -1
  16. classiq/interface/generator/expressions/qmod_qscalar_proxy.py +7 -2
  17. classiq/interface/generator/expressions/qmod_sized_proxy.py +8 -3
  18. classiq/interface/generator/expressions/qmod_struct_instance.py +12 -1
  19. classiq/interface/generator/functions/builtins/core_library/atomic_quantum_functions.py +262 -195
  20. classiq/interface/generator/functions/builtins/internal_operators.py +1 -0
  21. classiq/interface/generator/functions/builtins/open_lib_functions.py +1645 -44
  22. classiq/interface/generator/functions/classical_type.py +21 -3
  23. classiq/interface/generator/generated_circuit_data.py +2 -0
  24. classiq/interface/generator/model/model.py +1 -1
  25. classiq/interface/{model → generator/model}/quantum_register.py +3 -0
  26. classiq/interface/helpers/classproperty.py +8 -0
  27. classiq/interface/ide/visual_model.py +68 -0
  28. classiq/interface/model/control.py +11 -1
  29. classiq/interface/model/quantum_expressions/amplitude_loading_operation.py +3 -8
  30. classiq/interface/model/quantum_expressions/quantum_expression.py +1 -30
  31. classiq/interface/model/quantum_function_call.py +0 -12
  32. classiq/interface/model/validations/handles_validator.py +2 -7
  33. classiq/interface/server/routes.py +1 -0
  34. classiq/qmod/builtins/classical_execution_primitives.py +1 -1
  35. classiq/qmod/builtins/functions.py +83 -31
  36. classiq/qmod/builtins/operations.py +16 -1
  37. classiq/qmod/declaration_inferrer.py +28 -4
  38. classiq/qmod/pretty_print/pretty_printer.py +22 -2
  39. classiq/qmod/qmod_constant.py +2 -1
  40. classiq/qmod/qmod_parameter.py +9 -2
  41. classiq/qmod/quantum_expandable.py +35 -11
  42. classiq/qmod/quantum_function.py +6 -5
  43. classiq/qmod/symbolic.py +22 -1
  44. classiq/qmod/utilities.py +5 -5
  45. {classiq-0.41.2.dist-info → classiq-0.42.0.dist-info}/METADATA +1 -1
  46. {classiq-0.41.2.dist-info → classiq-0.42.0.dist-info}/RECORD +47 -46
  47. classiq/interface/model/call_synthesis_data.py +0 -57
  48. {classiq-0.41.2.dist-info → classiq-0.42.0.dist-info}/WHEEL +0 -0
@@ -6,6 +6,12 @@ from classiq.interface.chemistry.fermionic_operator import (
6
6
  FermionicOperator,
7
7
  SummedFermionicOperator,
8
8
  )
9
+ from classiq.qmod.builtins.structs import (
10
+ MoleculeProblem as QmodMoleculeProblem,
11
+ Molecule as QmodMolecule,
12
+ ChemistryAtom as QmodChemistryAtom,
13
+ Position as QmodPosition,
14
+ )
9
15
  from classiq.interface.chemistry.ground_state_problem import (
10
16
  CHEMISTRY_PROBLEMS_TYPE,
11
17
  HamiltonianProblem,
@@ -185,42 +191,36 @@ _HAE_GATE_MAPPING: Dict[str, QuantumFunctionCall] = {
185
191
  }
186
192
 
187
193
 
188
- def _atoms_to_qmod_atoms(atoms: List[Atom]) -> str:
189
- # fmt: off
190
- atom_struct_literals = [
191
- "struct_literal(ChemistryAtom,"
192
- f"element={Element[atom.symbol]},"
193
- "position=struct_literal(Position,"
194
- f"x={atom.x},"
195
- f"y={atom.y},"
196
- f"z={atom.z}"
197
- ")"
198
- ")"
194
+ def _atoms_to_qmod_atoms(atoms: List[Atom]) -> List[QmodChemistryAtom]:
195
+ return [
196
+ QmodChemistryAtom(
197
+ element=Element[atom.symbol],
198
+ position=QmodPosition(
199
+ x=atom.x, # type:ignore[arg-type]
200
+ y=atom.y, # type:ignore[arg-type]
201
+ z=atom.z, # type:ignore[arg-type]
202
+ ),
203
+ )
199
204
  for atom in atoms
200
205
  ]
201
- # fmt: on
202
- return ",".join(atom_struct_literals)
203
206
 
204
207
 
205
208
  def molecule_problem_to_qmod(
206
209
  molecule_problem: MoleculeProblem,
207
- ) -> str:
208
- # fmt: off
209
- return (
210
- "struct_literal("
211
- "MoleculeProblem,"
212
- f"mapping={FermionMapping[molecule_problem.mapping.value.upper()]},"
213
- f"z2_symmetries={molecule_problem.z2_symmetries},"
214
- "molecule=struct_literal("
215
- "Molecule,"
216
- f"atoms=[{_atoms_to_qmod_atoms(molecule_problem.molecule.atoms)}],"
217
- f"spin={molecule_problem.molecule.spin},"
218
- f"charge={molecule_problem.molecule.charge}"
219
- "),"
220
- f"freeze_core={molecule_problem.freeze_core},"
221
- f"remove_orbitals={molecule_problem.remove_orbitals}"
222
- ")")
223
- # fmt: on
210
+ ) -> QmodMoleculeProblem:
211
+ return QmodMoleculeProblem(
212
+ mapping=FermionMapping[molecule_problem.mapping.value.upper()],
213
+ z2_symmetries=molecule_problem.z2_symmetries, # type:ignore[arg-type]
214
+ molecule=QmodMolecule(
215
+ atoms=_atoms_to_qmod_atoms(
216
+ molecule_problem.molecule.atoms
217
+ ), # type:ignore[arg-type]
218
+ spin=molecule_problem.molecule.spin, # type:ignore[arg-type]
219
+ charge=molecule_problem.molecule.charge, # type:ignore[arg-type]
220
+ ),
221
+ freeze_core=molecule_problem.freeze_core, # type:ignore[arg-type]
222
+ remove_orbitals=molecule_problem.remove_orbitals, # type:ignore[arg-type]
223
+ )
224
224
 
225
225
 
226
226
  def _fermionic_operator_to_qmod_ladder_ops(
@@ -271,7 +271,7 @@ def _hamiltonian_problem_to_qmod_fock_hamiltonian_problem(
271
271
 
272
272
  def _convert_library_problem_to_qmod_problem(problem: CHEMISTRY_PROBLEMS_TYPE) -> str:
273
273
  if isinstance(problem, MoleculeProblem):
274
- return molecule_problem_to_qmod(problem)
274
+ return str(molecule_problem_to_qmod(problem))
275
275
  elif isinstance(problem, HamiltonianProblem):
276
276
  return _hamiltonian_problem_to_qmod_fock_hamiltonian_problem(problem)
277
277
  else:
@@ -1,5 +1,5 @@
1
1
  import json
2
- from typing import Any, Callable, Dict, List, Optional, Union, cast
2
+ from typing import Any, Callable, Dict, List, Optional, Tuple, Union, cast
3
3
 
4
4
  from classiq.interface.executor.execution_preferences import ExecutionPreferences
5
5
  from classiq.interface.executor.execution_result import ResultsCollection
@@ -24,7 +24,12 @@ from classiq.synthesis import SerializedQuantumProgram
24
24
 
25
25
  Hamiltonian = Union[List[QmodPyStruct], List[PauliTerm]]
26
26
  Program = Union[SerializedQuantumProgram, QuantumProgram]
27
- ExecutionParameters = Union[None, ExecutionParams, List[ExecutionParams]]
27
+ ParsedExecutionParams = Dict[str, Union[float, int]]
28
+ ExecutionParameters = Optional[Union[ExecutionParams, List[ExecutionParams]]]
29
+ ParsedExecutionParameters = Optional[
30
+ Union[ParsedExecutionParams, List[ParsedExecutionParams]]
31
+ ]
32
+
28
33
 
29
34
  SAVE_RESULT = "\nsave({'result': result})\n"
30
35
 
@@ -52,8 +57,42 @@ def to_hamiltonian_str(hamiltonian: Hamiltonian) -> str:
52
57
  )
53
58
 
54
59
 
60
+ def serialize(
61
+ item: Union[float, int, Tuple[int, ...], Tuple[float, ...]]
62
+ ) -> Union[str, List]:
63
+ if isinstance(item, tuple):
64
+ return list(item)
65
+ return str(item)
66
+
67
+
68
+ def parse_params(params: ExecutionParams) -> ParsedExecutionParams:
69
+ result = {}
70
+ for key, values in params.items():
71
+ if isinstance(values, list):
72
+ for index, value in enumerate(values):
73
+ new_key = f"{key}_{index}"
74
+ result[new_key] = value
75
+ elif isinstance(values, (int, float)):
76
+ result[key] = values
77
+ else:
78
+ raise TypeError("Parameters were provided in un-supported format")
79
+ return result
80
+
81
+
55
82
  def format_parameters(execution_params: ExecutionParameters) -> str:
56
- return json.dumps(execution_params, default=str) if execution_params else ""
83
+ parsed_parameters: ParsedExecutionParameters = None
84
+ if execution_params is None:
85
+ return ""
86
+ if isinstance(execution_params, dict):
87
+ parsed_parameters = parse_params(execution_params)
88
+
89
+ elif isinstance(execution_params, list):
90
+ parsed_parameters = [
91
+ parse_params(ep) if isinstance(ep, dict) else ep for ep in execution_params
92
+ ]
93
+
94
+ execution_params = cast(ExecutionParams, parsed_parameters)
95
+ return json.dumps(execution_params, default=serialize, indent=2)
57
96
 
58
97
 
59
98
  def create_estimate_execution_code(operation: str, **kwargs: Any) -> str:
@@ -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.41.2'
6
+ SEMVER_VERSION = '0.42.0'
7
7
  VERSION = str(Version(SEMVER_VERSION))
@@ -2,7 +2,8 @@ from typing import Dict, List, Optional
2
2
 
3
3
  import numpy
4
4
  import pydantic
5
- from pydantic import Field
5
+ from pydantic import Field, conint, constr
6
+ from typing_extensions import Annotated
6
7
 
7
8
  from classiq.interface.backend.quantum_backend_providers import AnalyzerProviderVendor
8
9
  from classiq.interface.chemistry.ground_state_problem import MoleculeProblem
@@ -17,6 +18,12 @@ from classiq.interface.helpers.custom_pydantic_types import PydanticNonEmptyStri
17
18
  MAX_KB_OF_FILE = 500
18
19
  MAX_FILE_LENGTH = MAX_KB_OF_FILE * 1024
19
20
 
21
+ MAX_QUBITS = 100
22
+ MIN_QUBITS = 0
23
+ MAX_COUNTS = 1000
24
+ MAX_NUM_CLIFFORD = 1000
25
+ MAX_NAME_LENGTH = 100
26
+
20
27
 
21
28
  class AnalysisParams(pydantic.BaseModel):
22
29
  qasm: PydanticNonEmptyString = Field(..., max_length=MAX_FILE_LENGTH)
@@ -40,13 +47,16 @@ class HardwareListParams(pydantic.BaseModel):
40
47
 
41
48
  class AnalysisOptionalDevicesParams(HardwareListParams):
42
49
  qubit_count: int = pydantic.Field(
43
- default=..., description="number of qubits in the data"
50
+ default=...,
51
+ description="number of qubits in the data",
52
+ ge=MIN_QUBITS,
53
+ le=MAX_QUBITS,
44
54
  )
45
55
 
46
56
 
47
57
  class GateNamsMapping(pydantic.BaseModel):
48
- qasm_name: str
49
- display_name: str
58
+ qasm_name: Annotated[str, constr(max_length=MAX_NAME_LENGTH)]
59
+ display_name: Annotated[str, constr(max_length=MAX_NAME_LENGTH)]
50
60
 
51
61
 
52
62
  class LatexParams(AnalysisParams):
@@ -81,8 +91,8 @@ class CircuitAnalysisHardwareParams(AnalysisParams):
81
91
 
82
92
  class AnalysisRBParams(pydantic.BaseModel):
83
93
  hardware: str
84
- counts: List[Dict[str, int]]
85
- num_clifford: List[int]
94
+ counts: List[Dict[str, Annotated[int, conint(strict=True, gt=0, le=MAX_COUNTS)]]]
95
+ num_clifford: List[Annotated[int, conint(strict=True, gt=0, le=MAX_NUM_CLIFFORD)]]
86
96
 
87
97
 
88
98
  class ChemistryGenerationParams(pydantic.BaseModel):
@@ -5,6 +5,7 @@ import pydantic
5
5
  from pydantic import Field
6
6
  from typing_extensions import Annotated
7
7
 
8
+ from classiq.interface.analyzer.analysis_params import MAX_FILE_LENGTH
8
9
  from classiq.interface.helpers.custom_pydantic_types import PydanticNonEmptyString
9
10
  from classiq.interface.helpers.versioned_model import VersionedModel
10
11
 
@@ -38,7 +39,7 @@ class DataID(pydantic.BaseModel):
38
39
 
39
40
 
40
41
  class QasmCode(pydantic.BaseModel):
41
- code: str
42
+ code: str = Field(..., max_length=MAX_FILE_LENGTH)
42
43
 
43
44
 
44
45
  class AnalysisStatus(StrEnum):
@@ -20,9 +20,9 @@ class SourceReference(HashablePydanticBaseModel):
20
20
  f"file {os.path.basename(self.file_name)} " if self.file_name else ""
21
21
  )
22
22
  start_character_string = (
23
- f" character {self.start_column}" if self.start_column else ""
23
+ f" character {self.start_column + 1}" if self.start_column > 0 else ""
24
24
  )
25
- return f"{file_string}line {self.start_line}{start_character_string}"
25
+ return f"{file_string}line {self.start_line + 1}{start_character_string}"
26
26
 
27
27
 
28
28
  class ASTNode(HashablePydanticBaseModel):
@@ -40,9 +40,7 @@ else:
40
40
  regex=f"[A-Za-z0-9]{{{_IONQ_API_KEY_LENGTH}}}"
41
41
  )
42
42
 
43
- PydanticAliceBobApiKeyType = pydantic.constr(
44
- regex=f"[A-Za-z0-9]{{{_ALICE_BOB_API_KEY_LENGTH}}}"
45
- )
43
+ PydanticAliceBobApiKeyType = pydantic.constr(min_length=1, strip_whitespace=True)
46
44
 
47
45
  PydanticExecutionTimeout = pydantic.conint(gt=0, le=MAX_EXECUTION_TIMEOUT_SECONDS)
48
46
 
@@ -39,7 +39,10 @@ class FermionicOperator(HashablePydanticBaseModel):
39
39
  """
40
40
 
41
41
  op_list: list = pydantic.Field(
42
- description="A list of tuples each containing an index and a character; for example [('+', 0), ('-', 1)].",
42
+ description=(
43
+ "A list of tuples each containing an index and a character; for "
44
+ "example [('+', 0), ('-', 1)]."
45
+ ),
43
46
  )
44
47
 
45
48
  @staticmethod
@@ -51,20 +54,27 @@ class FermionicOperator(HashablePydanticBaseModel):
51
54
  raise ClassiqValueError("Ladder operator should be a tuple.") from exc
52
55
  if len(op) != 2:
53
56
  raise ClassiqValueError(
54
- "Ladder operator tuple should be of length two; for example (1, '+')."
57
+ "Ladder operator tuple should be of length two; for example ('+', 1)."
55
58
  )
56
59
 
57
- if op[0] not in ("+", "-"):
60
+ op_symbol = op[0]
61
+ if op_symbol == "LadderOperator.PLUS":
62
+ op_symbol = "+"
63
+ elif op_symbol == "LadderOperator.MINUS":
64
+ op_symbol = "-"
65
+ if op_symbol not in ("+", "-"):
58
66
  raise ClassiqValueError(
59
- "The first term in a ladder operator tuple indicates if its a raising ('+')"
60
- f" or lowering ('-') operator. Allowed input is: '+' or '-', received {op[0]}"
67
+ f"The first term in a ladder operator tuple indicates if its a raising "
68
+ f"(LadderOperator.PLUS / '+') or lowering (LadderOperator.MINUS / '-') "
69
+ f"operator. Received {op_symbol}"
61
70
  )
62
- if not isinstance(op[1], int):
71
+ op_index = op[1]
72
+ if not isinstance(op_index, int):
63
73
  raise ClassiqValueError(
64
74
  "The second term in a ladder operator tuple indicates its index and should be of type int"
65
75
  )
66
76
 
67
- return op # type: ignore[return-value] # mypy thinks that it is `Tuple[Any, ...]`, though the asserts here tell otherwise..
77
+ return (op_symbol, op_index)
68
78
 
69
79
  @pydantic.validator("op_list")
70
80
  def _validate_op_list(cls, op_list: list) -> list:
@@ -9,6 +9,7 @@ from classiq.interface.generator.arith.arithmetic_expression_validator import (
9
9
  )
10
10
  from classiq.interface.generator.arith.register_user_input import RegisterUserInput
11
11
  from classiq.interface.generator.expressions.expression_constants import (
12
+ BOOLEAN_LITERALS,
12
13
  FORBIDDEN_LITERALS,
13
14
  SUPPORTED_FUNC_NAMES,
14
15
  SUPPORTED_VAR_NAMES_REG,
@@ -36,6 +37,12 @@ class AmplitudeLoading(FunctionParams):
36
37
  size: pydantic.PositiveInt = pydantic.Field(
37
38
  description="The number of qubits of the amplitude input."
38
39
  )
40
+ fraction_digits: pydantic.NonNegativeInt = pydantic.Field(
41
+ description="The number of fraction digits of the amplitude input."
42
+ )
43
+ is_signed: bool = pydantic.Field(
44
+ description="Whether the amplitude input has a sign qubit."
45
+ )
39
46
  expression: PydanticExpressionStr = pydantic.Field(
40
47
  description="The mathematical expression of the amplitude loading function."
41
48
  )
@@ -64,8 +71,8 @@ class AmplitudeLoading(FunctionParams):
64
71
  expression = values.get("expression", "")
65
72
  literals = set(re.findall(SUPPORTED_VAR_NAMES_REG, expression))
66
73
 
67
- not_allowed = literals.intersection(FORBIDDEN_LITERALS)
68
- variables = literals.difference(SUPPORTED_FUNC_NAMES)
74
+ not_allowed = literals.intersection(FORBIDDEN_LITERALS) - BOOLEAN_LITERALS
75
+ variables = literals.difference(SUPPORTED_FUNC_NAMES) - BOOLEAN_LITERALS
69
76
  if not_allowed:
70
77
  raise ClassiqValueError(
71
78
  f"The following names: {not_allowed} are not allowed"
@@ -89,5 +96,7 @@ class AmplitudeLoading(FunctionParams):
89
96
 
90
97
  @property
91
98
  def variable(self) -> str:
92
- literals = set(re.findall(SUPPORTED_VAR_NAMES_REG, self.expression))
99
+ literals = (
100
+ set(re.findall(SUPPORTED_VAR_NAMES_REG, self.expression)) - BOOLEAN_LITERALS
101
+ )
93
102
  return list(literals.difference(SUPPORTED_FUNC_NAMES))[0]
@@ -1,5 +1,5 @@
1
1
  from enum import Enum
2
- from typing import Mapping
2
+ from typing import TYPE_CHECKING, Callable, Mapping
3
3
 
4
4
  from classiq.interface.generator.expressions.expression import Expression
5
5
  from classiq.interface.generator.functions.classical_function_declaration import (
@@ -21,6 +21,10 @@ from classiq.interface.model.quantum_function_declaration import (
21
21
  QuantumFunctionDeclaration,
22
22
  )
23
23
 
24
+ if TYPE_CHECKING:
25
+ from classiq.qmod.builtins.structs import GaussianModel
26
+ from classiq.qmod.symbolic_expr import SymbolicExpr
27
+
24
28
  FUNCTION_PORT_NAME = "func_port"
25
29
  OBJECTIVE_PORT_NAME = "obj_port"
26
30
 
@@ -36,6 +40,23 @@ FINANCE_FUNCTION_PORT_SIZE_MAPPING: Mapping[FinanceModelType, str] = {
36
40
  }
37
41
 
38
42
 
43
+ def _get_gaussian_size(finance_model: "GaussianModel") -> "SymbolicExpr":
44
+ from classiq.qmod.symbolic import floor, log, sum as sym_sum
45
+
46
+ return (
47
+ finance_model.num_qubits
48
+ + finance_model.rhos.len
49
+ + floor(log(sym_sum(finance_model.loss), 2))
50
+ + 1
51
+ )
52
+
53
+
54
+ FINANCE_FUNCTION_PORT_SIZE_FUNCTION_MAPPING: Mapping[FinanceModelType, Callable] = {
55
+ FinanceModelType.Gaussian: _get_gaussian_size,
56
+ FinanceModelType.LogNormal: lambda finance_model: finance_model.num_qubits,
57
+ }
58
+
59
+
39
60
  def _generate_finance_function(
40
61
  finance_model: FinanceModelType,
41
62
  ) -> QuantumFunctionDeclaration:
@@ -1,8 +1,9 @@
1
1
  from classiq.interface.generator.functions.classical_type import CLASSICAL_ATTRIBUTES
2
2
 
3
- SUPPORTED_BUILTIN_FUNCTIONS = {"len", "sum", "print"}
3
+ SUPPORTED_BUILTIN_FUNCTIONS = ["len", "sum", "print"]
4
4
 
5
5
  SUPPORTED_ATOMIC_EXPRESSION_FUNCTIONS = {
6
+ "do_subscript",
6
7
  "hypercube_entangler_graph",
7
8
  "grid_entangler_graph",
8
9
  "qft_const_adder_phase",
@@ -1,4 +1,7 @@
1
1
  import enum
2
+ from typing import Any, Mapping
3
+
4
+ from classiq.interface.helpers.classproperty import classproperty
2
5
 
3
6
 
4
7
  class ClassicalEnum(int, enum.Enum):
@@ -7,3 +10,11 @@ class ClassicalEnum(int, enum.Enum):
7
10
 
8
11
  def __repr__(self) -> str:
9
12
  return str(self)
13
+
14
+ @classproperty
15
+ def type_name(cls) -> str: # noqa: N805
16
+ return "Enum"
17
+
18
+ @classproperty
19
+ def fields(cls) -> Mapping[str, Any]: # noqa: N805
20
+ return {i.name: i for i in cls} # type:ignore[attr-defined]
@@ -1,16 +1,6 @@
1
- from typing_extensions import assert_never
2
-
3
1
  from classiq.interface.generator.expressions.enums.classical_enum import ClassicalEnum
4
2
 
5
3
 
6
4
  class LadderOperator(ClassicalEnum):
7
5
  PLUS = 0
8
6
  MINUS = 1
9
-
10
- def __str__(self) -> str:
11
- if self is LadderOperator.PLUS:
12
- return "+"
13
- elif self is LadderOperator.MINUS:
14
- return "-"
15
- else:
16
- assert_never(self)
@@ -16,4 +16,5 @@ SUPPORTED_FUNC_NAMES: Set[str] = (
16
16
  .union(DEFAULT_SUPPORTED_FUNC_NAMES)
17
17
  .union(set(SYMPY_SUPPORTED_EXPRESSIONS))
18
18
  )
19
+ BOOLEAN_LITERALS = {"True", "False"}
19
20
  FORBIDDEN_LITERALS: Set[str] = set(keyword.kwlist) - SUPPORTED_FUNC_NAMES
@@ -1,4 +1,4 @@
1
- from typing import Optional, Tuple, Union
1
+ from typing import Any, Mapping, Optional, Tuple, Union
2
2
 
3
3
  from classiq.interface.generator.expressions.expression import Expression
4
4
  from classiq.interface.generator.expressions.qmod_sized_proxy import QmodSizedProxy
@@ -56,6 +56,10 @@ class QmodQArrayProxy(QmodSizedProxy):
56
56
  return self._slice[0] + start, self._slice[0] + end
57
57
  return start, end
58
58
 
59
+ @property
60
+ def type_name(self) -> str:
61
+ return "Quantum array"
62
+
59
63
  @property
60
64
  def index(self) -> Optional[int]:
61
65
  return self._index
@@ -81,9 +85,18 @@ class QmodQArrayProxy(QmodSizedProxy):
81
85
 
82
86
  return HandleBinding(name=self._name)
83
87
 
88
+ @property
89
+ def fields(self) -> Mapping[str, Any]:
90
+ return {
91
+ "len": self.len,
92
+ }
93
+
84
94
  def __len__(self) -> int:
85
95
  if (slice_ := self.slice) is not None:
86
96
  return slice_[1] - slice_[0]
87
97
  elif self.index is not None:
88
98
  return 1
89
99
  return self._size
100
+
101
+ def __str__(self) -> str:
102
+ return str(self.handle)
@@ -20,11 +20,12 @@ class QmodQScalarProxy(Symbol, QmodSizedProxy):
20
20
 
21
21
 
22
22
  class QmodQBitProxy(QmodQScalarProxy):
23
- pass
23
+ @property
24
+ def type_name(self) -> str:
25
+ return "Quantum bit"
24
26
 
25
27
 
26
28
  class QmodQNumProxy(QmodQScalarProxy):
27
-
28
29
  def __init__(
29
30
  self, name: str, size: int, fraction_digits: int, is_signed: bool
30
31
  ) -> None:
@@ -32,6 +33,10 @@ class QmodQNumProxy(QmodQScalarProxy):
32
33
  self._fraction_digits = fraction_digits
33
34
  self._is_signed = is_signed
34
35
 
36
+ @property
37
+ def type_name(self) -> str:
38
+ return "Quantum numeric"
39
+
35
40
  @property
36
41
  def size(self) -> int:
37
42
  return self._size
@@ -13,6 +13,13 @@ class QmodSizedProxy:
13
13
  def __len__(self) -> int:
14
14
  return self._size
15
15
 
16
+ def __str__(self) -> str:
17
+ return str(self.handle)
18
+
19
+ @property
20
+ def type_name(self) -> str:
21
+ raise NotImplementedError
22
+
16
23
  @property
17
24
  def handle(self) -> "HandleBinding":
18
25
  raise ClassiqNotImplementedError("cannot compute handle")
@@ -23,6 +30,4 @@ class QmodSizedProxy:
23
30
 
24
31
  @property
25
32
  def fields(self) -> Mapping[str, Any]:
26
- return {
27
- "len": self.len,
28
- }
33
+ return {}
@@ -16,9 +16,20 @@ class QmodStructInstance:
16
16
  self.struct_declaration = struct_declaration
17
17
  self._fields = fields
18
18
 
19
+ @property
20
+ def type_name(self) -> str:
21
+ return f"Struct {self.struct_declaration.name}"
22
+
19
23
  @property
20
24
  def fields(self) -> Mapping[str, Any]:
21
25
  return types.MappingProxyType(self._fields)
22
26
 
27
+ def __str__(self) -> str:
28
+ return repr(self)
29
+
23
30
  def __repr__(self) -> str:
24
- return repr(self._fields)
31
+ fields = ", ".join(
32
+ f"{field_name}={field_value}"
33
+ for field_name, field_value in self._fields.items()
34
+ )
35
+ return f"{self.struct_declaration.name}({fields})"