classiq 0.87.0__py3-none-any.whl → 0.88.0__py3-none-any.whl

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

Potentially problematic release.


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

Files changed (67) hide show
  1. classiq/applications/__init__.py +1 -2
  2. classiq/applications/combinatorial_helpers/combinatorial_problem_utils.py +1 -1
  3. classiq/applications/hamiltonian/pauli_decomposition.py +1 -1
  4. classiq/evaluators/qmod_annotated_expression.py +30 -7
  5. classiq/evaluators/qmod_expression_visitors/qmod_expression_bwc.py +0 -5
  6. classiq/evaluators/qmod_expression_visitors/qmod_expression_evaluator.py +18 -11
  7. classiq/evaluators/qmod_expression_visitors/qmod_expression_renamer.py +14 -7
  8. classiq/evaluators/qmod_expression_visitors/qmod_expression_simplifier.py +39 -16
  9. classiq/evaluators/qmod_node_evaluators/attribute_evaluation.py +1 -1
  10. classiq/evaluators/qmod_node_evaluators/classical_function_evaluation.py +18 -8
  11. classiq/evaluators/qmod_node_evaluators/compare_evaluation.py +8 -0
  12. classiq/evaluators/qmod_node_evaluators/constant_evaluation.py +4 -1
  13. classiq/evaluators/qmod_node_evaluators/numeric_attrs_utils.py +1 -1
  14. classiq/evaluators/qmod_node_evaluators/struct_instantiation_evaluation.py +1 -1
  15. classiq/evaluators/qmod_node_evaluators/subscript_evaluation.py +3 -3
  16. classiq/evaluators/qmod_node_evaluators/utils.py +1 -1
  17. classiq/evaluators/qmod_type_inference/classical_type_inference.py +4 -4
  18. classiq/evaluators/qmod_type_inference/quantum_type_inference.py +38 -0
  19. classiq/evaluators/type_type_match.py +1 -1
  20. classiq/execution/execution_session.py +17 -2
  21. classiq/interface/_version.py +1 -1
  22. classiq/interface/execution/primitives.py +1 -0
  23. classiq/interface/generator/application_apis/__init__.py +0 -1
  24. classiq/interface/generator/expressions/atomic_expression_functions.py +0 -2
  25. classiq/interface/generator/function_param_list.py +0 -4
  26. classiq/interface/generator/functions/classical_type.py +8 -0
  27. classiq/interface/generator/functions/type_name.py +6 -0
  28. classiq/interface/generator/transpiler_basis_gates.py +5 -1
  29. classiq/interface/generator/types/builtin_enum_declarations.py +0 -8
  30. classiq/interface/model/classical_if.py +16 -8
  31. classiq/interface/model/classical_parameter_declaration.py +4 -0
  32. classiq/interface/model/port_declaration.py +12 -0
  33. classiq/interface/model/quantum_function_declaration.py +12 -0
  34. classiq/interface/model/quantum_type.py +56 -0
  35. classiq/interface/pretty_print/expression_to_qmod.py +3 -17
  36. classiq/model_expansions/quantum_operations/allocate.py +1 -1
  37. classiq/model_expansions/quantum_operations/handle_evaluator.py +2 -8
  38. classiq/open_library/functions/__init__.py +1 -0
  39. classiq/open_library/functions/lcu.py +2 -2
  40. classiq/open_library/functions/state_preparation.py +47 -5
  41. classiq/qmod/builtins/__init__.py +0 -3
  42. classiq/qmod/builtins/classical_functions.py +0 -28
  43. classiq/qmod/builtins/enums.py +24 -18
  44. classiq/qmod/builtins/functions/__init__.py +0 -5
  45. classiq/qmod/builtins/operations.py +142 -0
  46. classiq/qmod/builtins/structs.py +0 -11
  47. classiq/qmod/native/pretty_printer.py +1 -1
  48. classiq/qmod/pretty_print/expression_to_python.py +3 -6
  49. classiq/qmod/pretty_print/pretty_printer.py +4 -1
  50. classiq/qmod/qmod_variable.py +94 -2
  51. classiq/qmod/semantics/annotation/call_annotation.py +4 -2
  52. classiq/qmod/semantics/annotation/qstruct_annotator.py +20 -5
  53. {classiq-0.87.0.dist-info → classiq-0.88.0.dist-info}/METADATA +3 -3
  54. {classiq-0.87.0.dist-info → classiq-0.88.0.dist-info}/RECORD +55 -67
  55. classiq/applications/finance/__init__.py +0 -15
  56. classiq/interface/finance/__init__.py +0 -0
  57. classiq/interface/finance/finance_modelling_params.py +0 -11
  58. classiq/interface/finance/function_input.py +0 -102
  59. classiq/interface/finance/gaussian_model_input.py +0 -50
  60. classiq/interface/finance/log_normal_model_input.py +0 -40
  61. classiq/interface/finance/model_input.py +0 -22
  62. classiq/interface/generator/application_apis/finance_declarations.py +0 -108
  63. classiq/interface/generator/expressions/enums/__init__.py +0 -0
  64. classiq/interface/generator/expressions/enums/finance_functions.py +0 -12
  65. classiq/interface/generator/finance.py +0 -107
  66. classiq/qmod/builtins/functions/finance.py +0 -34
  67. {classiq-0.87.0.dist-info → classiq-0.88.0.dist-info}/WHEEL +0 -0
@@ -340,6 +340,7 @@ class ExecutionSession:
340
340
  initial_params: ExecutionParams,
341
341
  max_iteration: int,
342
342
  quantile: float = 1.0,
343
+ tolerance: Optional[float] = None,
343
344
  ) -> list[tuple[float, ExecutionParams]]:
344
345
  """
345
346
  Minimizes the given cost function using the quantum program.
@@ -355,6 +356,7 @@ class ExecutionSession:
355
356
  - The value is either a float or a list of floats.
356
357
  max_iteration: The maximum number of iterations for the minimization.
357
358
  quantile: The quantile to use for cost estimation.
359
+ tolerance: The tolerance for the minimization.
358
360
  Returns:
359
361
  A list of tuples, each containing the estimated cost and the corresponding parameters for that iteration.
360
362
  `cost` is a float, and `parameters` is a dictionary matching the execution parameter format.
@@ -365,6 +367,7 @@ class ExecutionSession:
365
367
  initial_params=initial_params,
366
368
  max_iteration=max_iteration,
367
369
  quantile=quantile,
370
+ tolerance=tolerance,
368
371
  _check_deprecation=False,
369
372
  )
370
373
  result = job.get_minimization_result(_http_client=self._async_client)
@@ -379,6 +382,7 @@ class ExecutionSession:
379
382
  initial_params: ExecutionParams,
380
383
  max_iteration: int,
381
384
  quantile: float = 1.0,
385
+ tolerance: Optional[float] = None,
382
386
  *,
383
387
  _check_deprecation: bool = True,
384
388
  ) -> ExecutionJob:
@@ -400,6 +404,7 @@ class ExecutionSession:
400
404
  - The value is either a float or a list of floats.
401
405
  max_iteration: The maximum number of iterations for the minimization.
402
406
  quantile: The quantile to use for cost estimation.
407
+ tolerance: The tolerance for the minimization.
403
408
 
404
409
  Returns:
405
410
  The execution job.
@@ -424,6 +429,7 @@ class ExecutionSession:
424
429
  initial_params=_initial_params,
425
430
  max_iteration=max_iteration,
426
431
  quantile=quantile,
432
+ tolerance=tolerance,
427
433
  )
428
434
  else:
429
435
  _cost_function = self._hamiltonian_to_pauli_operator(cost_function)
@@ -432,6 +438,7 @@ class ExecutionSession:
432
438
  initial_params=_initial_params,
433
439
  max_iteration=max_iteration,
434
440
  quantile=quantile,
441
+ tolerance=tolerance,
435
442
  )
436
443
 
437
444
  execution_primitives_input = PrimitivesInput(minimize=minimize)
@@ -545,10 +552,18 @@ class ExecutionSession:
545
552
  name: create_qvar_from_quantum_type(reg.quantum_types, name)
546
553
  for name, reg in circuit_output_types.items()
547
554
  }
548
- for name in inspect.signature(qmod_expression_creator).parameters.keys():
555
+ creator_parameters = inspect.signature(
556
+ qmod_expression_creator
557
+ ).parameters.keys()
558
+ for name in creator_parameters:
549
559
  if name not in symbolic_output:
550
560
  raise ClassiqValueError(
551
- f"The provided QVar: {name} does not match the model outputs: {tuple(circuit_output_types.keys())}. "
561
+ f"Expected cost function with parameters {tuple(symbolic_output.keys())} corresponding to the quantum program outputs, but found '{name}'. "
562
+ )
563
+ for name in symbolic_output:
564
+ if name not in creator_parameters:
565
+ raise ClassiqValueError(
566
+ f"Expected cost function with parameter '{name}' corresponding to the quantum program outputs. "
552
567
  )
553
568
 
554
569
  qmod_expression = qmod_expression_creator(**symbolic_output)
@@ -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.87.0'
6
+ SEMVER_VERSION = '0.88.0'
7
7
  VERSION = str(Version(SEMVER_VERSION))
@@ -17,6 +17,7 @@ class MinimizeCostInput(BaseModel, json_encoders=CUSTOM_ENCODERS):
17
17
  initial_params: Arguments
18
18
  max_iteration: int
19
19
  quantile: float
20
+ tolerance: Optional[float]
20
21
 
21
22
 
22
23
  class MinimizeClassicalCostInput(MinimizeCostInput):
@@ -6,7 +6,6 @@ from .arithmetic_declarations import * # noqa: F403
6
6
  from .chemistry_declarations import * # noqa: F403
7
7
  from .combinatorial_optimization_declarations import * # noqa: F403
8
8
  from .entangler_declarations import * # noqa: F403
9
- from .finance_declarations import * # noqa: F403
10
9
  from .qsvm_declarations import * # noqa: F403
11
10
 
12
11
  populate_builtin_declarations(vars().values())
@@ -4,8 +4,6 @@ CLASSIQ_BUILTIN_CLASSICAL_FUNCTIONS = {
4
4
  "hypercube_entangler_graph",
5
5
  "grid_entangler_graph",
6
6
  "qft_const_adder_phase",
7
- "log_normal_finance_post_process",
8
- "gaussian_finance_post_process",
9
7
  "molecule_problem_to_hamiltonian",
10
8
  "fock_hamiltonian_problem_to_hamiltonian",
11
9
  "molecule_ground_state_solution_post_process",
@@ -33,7 +33,6 @@ from classiq.interface.generator.entangler_params import (
33
33
  HypercubeEntangler,
34
34
  TwoDimensionalEntangler,
35
35
  )
36
- from classiq.interface.generator.finance import Finance, FinanceModels, FinancePayoff
37
36
  from classiq.interface.generator.function_param_library import FunctionParamLibrary
38
37
  from classiq.interface.generator.hadamard_transform import HadamardTransform
39
38
  from classiq.interface.generator.hamiltonian_evolution.exponentiation import (
@@ -106,9 +105,6 @@ function_param_library: FunctionParamLibrary = FunctionParamLibrary(
106
105
  CyclicShift,
107
106
  Modulo,
108
107
  TwoDimensionalEntangler,
109
- Finance,
110
- FinanceModels,
111
- FinancePayoff,
112
108
  HypercubeEntangler,
113
109
  GridEntangler,
114
110
  Mcx,
@@ -144,6 +144,14 @@ class ClassicalArray(ClassicalType):
144
144
  def has_length(self) -> bool:
145
145
  return self.length is not None and self.length.is_evaluated()
146
146
 
147
+ @property
148
+ def has_constant_length(self) -> bool:
149
+ return (
150
+ self.length is not None
151
+ and self.length.is_evaluated()
152
+ and self.length.is_constant()
153
+ )
154
+
147
155
  @property
148
156
  def length_value(self) -> int:
149
157
  if not self.has_length:
@@ -101,6 +101,12 @@ class TypeName(ClassicalType, QuantumType):
101
101
  field_type.is_evaluated for field_type in self.fields.values()
102
102
  )
103
103
 
104
+ @property
105
+ def is_constant(self) -> bool:
106
+ return self.has_fields and all(
107
+ field_type.is_constant for field_type in self.fields.values()
108
+ )
109
+
104
110
  @property
105
111
  def has_classical_struct_decl(self) -> bool:
106
112
  return self._classical_struct_decl is not None
@@ -57,11 +57,15 @@ EXTRA_TWO_QUBIT_GATES: BasisGates = frozenset(
57
57
  )
58
58
  )
59
59
 
60
+ NON_UNITARY_GATES: BasisGates = frozenset(("if_else",))
61
+
60
62
  TWO_QUBIT_GATES = BASIC_TWO_QUBIT_GATES | EXTRA_TWO_QUBIT_GATES
61
63
 
62
64
  THREE_QUBIT_GATES: BasisGates = frozenset(("ccx", "cswap"))
63
65
  DEFAULT_BASIS_GATES: BasisGates = SINGLE_QUBIT_GATES | BASIC_TWO_QUBIT_GATES
64
- ALL_GATES: BasisGates = SINGLE_QUBIT_GATES | TWO_QUBIT_GATES | THREE_QUBIT_GATES
66
+ ALL_GATES: BasisGates = (
67
+ SINGLE_QUBIT_GATES | TWO_QUBIT_GATES | THREE_QUBIT_GATES | NON_UNITARY_GATES
68
+ )
65
69
 
66
70
  ROUTING_TWO_QUBIT_BASIS_GATES: BasisGates = frozenset(
67
71
  ("cx", "ecr", "rzx", "ryy", "rxx", "rzz", "cy", "cz", "cp", "swap")
@@ -132,13 +132,6 @@ class FermionMapping(IntEnum):
132
132
  FAST_BRAVYI_KITAEV = 3
133
133
 
134
134
 
135
- class FinanceFunctionType(IntEnum):
136
- VAR = 0
137
- SHORTFALL = 1
138
- X_SQUARE = 2
139
- EUROPEAN_CALL_OPTION = 3
140
-
141
-
142
135
  class LadderOperator(IntEnum):
143
136
  PLUS = 0
144
137
  MINUS = 1
@@ -171,7 +164,6 @@ class QSVMFeatureMapEntanglement(IntEnum):
171
164
  __all__ = [
172
165
  "Element",
173
166
  "FermionMapping",
174
- "FinanceFunctionType",
175
167
  "LadderOperator",
176
168
  "Optimizer",
177
169
  "Pauli",
@@ -3,6 +3,8 @@ import operator
3
3
  from collections.abc import Mapping
4
4
  from typing import TYPE_CHECKING, Literal
5
5
 
6
+ import pydantic
7
+
6
8
  from classiq.interface.ast_node import ASTNodeType, reset_lists
7
9
  from classiq.interface.generator.expressions.expression import Expression
8
10
  from classiq.interface.model.handle_binding import ConcreteHandleBinding, HandleBinding
@@ -18,6 +20,9 @@ class ClassicalIf(QuantumOperation):
18
20
  condition: Expression
19
21
  then: "StatementBlock"
20
22
  else_: "StatementBlock"
23
+ _condition_wiring_inouts: dict[str, HandleBinding] = pydantic.PrivateAttr(
24
+ default_factory=dict
25
+ )
21
26
 
22
27
  def _as_back_ref(self: ASTNodeType) -> ASTNodeType:
23
28
  return reset_lists(self, ["then", "else_"])
@@ -40,14 +45,17 @@ class ClassicalIf(QuantumOperation):
40
45
 
41
46
  @property
42
47
  def wiring_inouts(self) -> Mapping[str, ConcreteHandleBinding]:
43
- return functools.reduce(
44
- operator.ior,
45
- (
46
- op.wiring_inouts
47
- for op in (*self.then, *self.else_)
48
- if isinstance(op, QuantumOperation)
49
- ),
50
- dict(),
48
+ return (
49
+ functools.reduce(
50
+ operator.ior,
51
+ (
52
+ op.wiring_inouts
53
+ for op in (*self.then, *self.else_)
54
+ if isinstance(op, QuantumOperation)
55
+ ),
56
+ dict(),
57
+ )
58
+ | self._condition_wiring_inouts
51
59
  )
52
60
 
53
61
  @property
@@ -33,6 +33,10 @@ class AnonClassicalParameterDeclaration(Parameter):
33
33
  }
34
34
  )
35
35
 
36
+ @property
37
+ def qmod_type_name(self) -> str:
38
+ return self.classical_type.qmod_type_name
39
+
36
40
 
37
41
  class ClassicalParameterDeclaration(AnonClassicalParameterDeclaration):
38
42
  name: str
@@ -44,6 +44,18 @@ class AnonPortDeclaration(Parameter):
44
44
  raise ClassiqInternalError
45
45
  return PortDeclaration(**{**self.__dict__, "name": new_name})
46
46
 
47
+ @property
48
+ def qmod_type_name(self) -> str:
49
+ prefix = ""
50
+ suffix = ""
51
+ if self.type_modifier in (TypeModifier.Const, TypeModifier.Permutable):
52
+ prefix += f"{self.type_modifier.name}["
53
+ suffix += "]"
54
+ if self.direction != PortDeclarationDirection.Inout:
55
+ prefix += f"{self.direction.name}["
56
+ suffix += "]"
57
+ return f"{prefix}{self.quantum_type.qmod_type_name}{suffix}"
58
+
47
59
 
48
60
  class PortDeclaration(AnonPortDeclaration):
49
61
  name: str
@@ -190,6 +190,18 @@ class AnonQuantumOperandDeclaration(AnonQuantumFunctionDeclaration):
190
190
  def is_generative(self) -> bool:
191
191
  return self._is_generative
192
192
 
193
+ @property
194
+ def qmod_type_name(self) -> str:
195
+ if self.is_list:
196
+ type_name = "QCallableList"
197
+ else:
198
+ type_name = "QCallable"
199
+ if len(self.positional_arg_declarations) == 0:
200
+ params = ""
201
+ else:
202
+ params = f"[{', '.join(param.qmod_type_name for param in self.positional_arg_declarations)}]"
203
+ return f"{type_name}{params}"
204
+
193
205
 
194
206
  AnonQuantumFunctionDeclaration.model_rebuild()
195
207
 
@@ -84,6 +84,10 @@ class QuantumType(HashableASTNode):
84
84
  def is_evaluated(self) -> bool:
85
85
  raise NotImplementedError
86
86
 
87
+ @property
88
+ def is_constant(self) -> bool:
89
+ raise NotImplementedError
90
+
87
91
  @property
88
92
  def expressions(self) -> list[Expression]:
89
93
  return []
@@ -109,6 +113,9 @@ class QuantumScalar(QuantumType):
109
113
  def fraction_digits_value(self) -> int:
110
114
  raise NotImplementedError
111
115
 
116
+ def get_bounds(self) -> Optional[tuple[float, float]]:
117
+ return None
118
+
112
119
  def get_effective_bounds(
113
120
  self, machine_precision: Optional[int] = None
114
121
  ) -> tuple[float, float]:
@@ -154,6 +161,10 @@ class QuantumBit(QuantumScalar):
154
161
  def is_evaluated(self) -> bool:
155
162
  return True
156
163
 
164
+ @property
165
+ def is_constant(self) -> bool:
166
+ return True
167
+
157
168
  @property
158
169
  def has_sign(self) -> bool:
159
170
  return True
@@ -257,6 +268,15 @@ class QuantumBitvector(QuantumType):
257
268
  and self.element_type.is_evaluated
258
269
  )
259
270
 
271
+ @property
272
+ def is_constant(self) -> bool:
273
+ return (
274
+ self.length is not None
275
+ and self.length.is_evaluated()
276
+ and self.length.is_constant()
277
+ and self.element_type.is_constant
278
+ )
279
+
260
280
  @property
261
281
  def expressions(self) -> list[Expression]:
262
282
  exprs = self.element_type.expressions
@@ -311,6 +331,14 @@ class QuantumNumeric(QuantumScalar):
311
331
  def has_sign(self) -> bool:
312
332
  return self.is_signed is not None
313
333
 
334
+ @property
335
+ def has_constant_sign(self) -> bool:
336
+ return (
337
+ self.is_signed is not None
338
+ and self.is_signed.is_evaluated()
339
+ and self.is_signed.is_constant()
340
+ )
341
+
314
342
  @property
315
343
  def sign_value(self) -> bool:
316
344
  return False if self.is_signed is None else self.is_signed.to_bool_value()
@@ -319,6 +347,14 @@ class QuantumNumeric(QuantumScalar):
319
347
  def has_fraction_digits(self) -> bool:
320
348
  return self.fraction_digits is not None
321
349
 
350
+ @property
351
+ def has_constant_fraction_digits(self) -> bool:
352
+ return (
353
+ self.fraction_digits is not None
354
+ and self.fraction_digits.is_evaluated()
355
+ and self.fraction_digits.is_constant()
356
+ )
357
+
322
358
  @property
323
359
  def fraction_digits_value(self) -> int:
324
360
  return (
@@ -388,6 +424,26 @@ class QuantumNumeric(QuantumScalar):
388
424
  self.fraction_digits is not None and not self.fraction_digits.is_evaluated()
389
425
  )
390
426
 
427
+ @property
428
+ def is_constant(self) -> bool:
429
+ if (
430
+ self.size is None
431
+ or not self.size.is_evaluated()
432
+ or not self.size.is_constant()
433
+ ):
434
+ return False
435
+ if self.is_signed is not None and (
436
+ not self.is_signed.is_evaluated() or not self.is_signed.is_constant()
437
+ ):
438
+ return False
439
+ return not (
440
+ self.fraction_digits is not None
441
+ and (
442
+ not self.fraction_digits.is_evaluated()
443
+ or not self.fraction_digits.is_constant()
444
+ )
445
+ )
446
+
391
447
  @property
392
448
  def expressions(self) -> list[Expression]:
393
449
  exprs = []
@@ -141,24 +141,10 @@ class ASTToQMODCode:
141
141
  if len(node.args) != 2:
142
142
  raise PrettyPrinterError("Error parsing array access.")
143
143
  return f"{self.ast_to_code(node.args[0])}[{self.ast_to_code(node.args[1])}]"
144
- elif len(node.keywords) > 0:
145
- # struct instance
146
- keywords = node.keywords
147
- initializer_list = self.indent_items(
148
- lambda: [
149
- f"{keyword.arg}={self._cleaned_ast_to_code(keyword.value)}"
150
- for keyword in keywords
151
- if keyword.arg is not None
152
- ]
153
- )
154
- return f"{func} {{{initializer_list}}}"
155
144
  else:
156
- args = [self._cleaned_ast_to_code(arg) for arg in node.args]
157
- kwargs = [
158
- f"{kwarg.arg}={self._cleaned_ast_to_code(kwarg.value)}"
159
- for kwarg in node.keywords
160
- ]
161
- return "{}({})".format(func, ", ".join(args + kwargs))
145
+ return "{}({})".format(
146
+ func, ", ".join(self._cleaned_ast_to_code(arg) for arg in node.args)
147
+ )
162
148
  elif isinstance(node, ast.Expr):
163
149
  return self._cleaned_ast_to_code(node.value)
164
150
  else:
@@ -78,7 +78,7 @@ class AllocateEmitter(Emitter[Allocate]):
78
78
  target: QuantumSymbol,
79
79
  op_update_dict: dict[str, Expression],
80
80
  ) -> None:
81
- if target.quantum_type.is_evaluated:
81
+ if target.quantum_type.has_size_in_bits:
82
82
  expr = str(target.quantum_type.size_in_bits)
83
83
  elif self._allow_symbolic_attrs:
84
84
  expr = f"{target.handle}.size"
@@ -19,11 +19,5 @@ class HandleEvaluator(Emitter[QuantumOperation]):
19
19
  if not isinstance(handle, HandleBinding):
20
20
  return False
21
21
  evaluated_handle = self._interpreter.evaluate(handle).value.handle.collapse()
22
- if handle == evaluated_handle:
23
- return False
24
- op = op.model_copy(
25
- update={self._handle_name: evaluated_handle, "back_ref": op.uuid}
26
- )
27
- self._interpreter.add_to_debug_info(op)
28
- self._interpreter.emit(op)
29
- return True
22
+ setattr(op, self._handle_name, evaluated_handle)
23
+ return False
@@ -116,6 +116,7 @@ __all__ = [
116
116
  "prepare_exponential_state",
117
117
  "prepare_ghz_state",
118
118
  "prepare_int",
119
+ "prepare_linear_amplitudes",
119
120
  "prepare_uniform_interval_state",
120
121
  "prepare_uniform_trimmed_state",
121
122
  "projector_controlled_double_phase",
@@ -3,7 +3,7 @@ from typing import Literal
3
3
  import numpy as np
4
4
 
5
5
  from classiq.open_library.functions.state_preparation import (
6
- _load_phases,
6
+ apply_phase_table,
7
7
  )
8
8
  from classiq.open_library.functions.utility_functions import switch
9
9
  from classiq.qmod.builtins.functions import IDENTITY, X, Y, Z, inplace_prepare_state
@@ -73,7 +73,7 @@ def lcu(
73
73
  iteration=lambda i: control(block == i, lambda: unitaries[i]()),
74
74
  ),
75
75
  # TODO: replace to sparse constant phase
76
- _load_phases(phases, block),
76
+ apply_phase_table(phases, block),
77
77
  ],
78
78
  )
79
79
 
@@ -13,8 +13,8 @@ from classiq.open_library.functions.utility_functions import (
13
13
  from classiq.qmod.builtins.functions import (
14
14
  CX,
15
15
  IDENTITY,
16
+ PHASE,
16
17
  RY,
17
- RZ,
18
18
  H,
19
19
  X,
20
20
  inplace_prepare_amplitudes,
@@ -324,7 +324,7 @@ def _classical_hadamard_transform(arr: list[float]) -> np.ndarray:
324
324
 
325
325
 
326
326
  @qfunc
327
- def _load_phases(
327
+ def apply_phase_table(
328
328
  phases: list[float],
329
329
  target: QArray[QBit, Literal["log(get_field(phases, 'len'), 2)"]],
330
330
  ) -> None:
@@ -333,10 +333,10 @@ def _load_phases(
333
333
  for i in range(1, len(alphas) - 1):
334
334
  gray = _graycode(i)
335
335
  next_gray = _graycode(i + 1)
336
- RZ(alphas[gray], target[_msb(gray)])
336
+ PHASE(alphas[gray], target[_msb(gray)])
337
337
  CX(target[_control_qubit(i)], target[_msb(next_gray)])
338
338
 
339
- RZ(alphas[_graycode(len(phases) - 1)], target[target.len - 1])
339
+ PHASE(alphas[_graycode(len(phases) - 1)], target[target.len - 1])
340
340
 
341
341
 
342
342
  @qfunc
@@ -358,7 +358,7 @@ def inplace_prepare_complex_amplitudes(
358
358
  target: The quantum variable to act upon.
359
359
  """
360
360
  inplace_prepare_amplitudes(magnitudes, 0, target)
361
- _load_phases(phases, target)
361
+ apply_phase_table(phases, target)
362
362
 
363
363
 
364
364
  @qfunc
@@ -469,3 +469,45 @@ def prepare_basis_state(state: list[bool], arr: Output[QArray]) -> None:
469
469
  for idx, value in enumerate(state):
470
470
  if value:
471
471
  X(arr[idx])
472
+
473
+
474
+ def linear_hadamard_walsh_coefficients(n: int) -> np.ndarray:
475
+ coeffs = np.zeros(n + 1)
476
+ coeffs[0] = 2 ** (n / 2) * ((2**n - 1) / 2)
477
+ for k in range(1, n + 1):
478
+ coeffs[k] = -(2 ** (k - 1 + n / 2) / 2)
479
+ return coeffs / np.linalg.norm(coeffs)
480
+
481
+
482
+ @qfunc
483
+ def _zero_ctrl_rot(ctrl: QNum, target: QBit, theta: CReal) -> None:
484
+ control(ctrl == 0, lambda: RY(theta, target))
485
+
486
+
487
+ @qfunc
488
+ def prepare_linear_amplitudes(x: QArray) -> None:
489
+ """ "
490
+ [Qmod Classiq-library function]
491
+
492
+ Initializes a quantum variable in a state with linear amplitudes:
493
+ $$|\\psi\rangle = \frac{1}{Z}\\sum_{x=0}^{2^n-1}{x|x\rangle}$$
494
+ Where $Z$ is a normalization constant.
495
+
496
+ Based on the paper https://quantum-journal.org/papers/q-2024-03-21-1297/pdf/
497
+
498
+ Args:
499
+ x: The quantum register to prepare.
500
+ """
501
+ coeffs = linear_hadamard_walsh_coefficients(x.size) # type: ignore[arg-type]
502
+ thetas = np.zeros(x.size + 1) # type: ignore[arg-type]
503
+ for i in range(x.size): # type: ignore[arg-type]
504
+ thetas[i] = 2 * np.arcsin(
505
+ coeffs[i + 1] / np.sqrt(1 - np.linalg.norm(coeffs[1 : i + 1]) ** 2)
506
+ )
507
+ for k in range(x.len):
508
+ if k == 0:
509
+ RY(thetas[k], x[k])
510
+ else:
511
+ _zero_ctrl_rot(x[0:k], x[k], thetas[k])
512
+
513
+ hadamard_transform(x)
@@ -1,5 +1,3 @@
1
- from classiq.interface.finance.function_input import FinanceFunctionInput
2
-
3
1
  from .classical_execution_primitives import * # noqa: F403
4
2
  from .classical_execution_primitives import (
5
3
  __all__ as _builtin_classical_execution_primitives,
@@ -17,7 +15,6 @@ from .operations import __all__ as _builtin_operations
17
15
  from .structs import * # noqa: F403
18
16
  from .structs import __all__ as _builtin_structs
19
17
 
20
- FinanceFunctionInput.model_rebuild()
21
18
  BUILTIN_CONSTANTS = [
22
19
  constant._get_constant_node()
23
20
  for constant in [
@@ -54,38 +54,10 @@ def hypercube_entangler_graph(
54
54
  )
55
55
 
56
56
 
57
- def gaussian_finance_post_process(
58
- finance_model: GaussianModel,
59
- estimation_method: FinanceFunction,
60
- probability: CReal,
61
- ) -> CReal:
62
- return symbolic_function(
63
- finance_model,
64
- estimation_method,
65
- probability,
66
- return_type=CReal, # type:ignore[type-abstract]
67
- )
68
-
69
-
70
- def log_normal_finance_post_process(
71
- finance_model: LogNormalModel,
72
- estimation_method: FinanceFunction,
73
- probability: CReal,
74
- ) -> CReal:
75
- return symbolic_function(
76
- finance_model,
77
- estimation_method,
78
- probability,
79
- return_type=CReal, # type:ignore[type-abstract]
80
- )
81
-
82
-
83
57
  __all__ = [
84
58
  "qft_const_adder_phase",
85
59
  "fock_hamiltonian_problem_to_hamiltonian",
86
60
  "molecule_problem_to_hamiltonian",
87
61
  "grid_entangler_graph",
88
62
  "hypercube_entangler_graph",
89
- "gaussian_finance_post_process",
90
- "log_normal_finance_post_process",
91
63
  ]