classiq 0.67.0__py3-none-any.whl → 0.69.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 (87) hide show
  1. classiq/_internals/api_wrapper.py +9 -9
  2. classiq/_internals/async_utils.py +1 -1
  3. classiq/_internals/authentication/password_manager.py +1 -1
  4. classiq/_internals/client.py +1 -1
  5. classiq/applications/combinatorial_optimization/combinatorial_problem.py +8 -11
  6. classiq/applications/qnn/gradients/quantum_gradient.py +1 -1
  7. classiq/applications/qnn/gradients/simple_quantum_gradient.py +1 -1
  8. classiq/applications/qnn/torch_utils.py +1 -1
  9. classiq/execution/execution_session.py +7 -3
  10. classiq/execution/jobs.py +2 -5
  11. classiq/executor.py +7 -2
  12. classiq/interface/_version.py +1 -1
  13. classiq/interface/ast_node.py +1 -1
  14. classiq/interface/backend/quantum_backend_providers.py +2 -3
  15. classiq/interface/chemistry/operator.py +12 -8
  16. classiq/interface/debug_info/back_ref_util.py +22 -0
  17. classiq/interface/debug_info/debug_info.py +26 -21
  18. classiq/interface/executor/optimizer_preferences.py +1 -0
  19. classiq/interface/generator/arith/arithmetic.py +96 -1
  20. classiq/interface/generator/arith/arithmetic_expression_parser.py +1 -1
  21. classiq/interface/generator/arith/arithmetic_param_getters.py +3 -3
  22. classiq/interface/generator/functions/classical_type.py +12 -1
  23. classiq/interface/generator/generated_circuit_data.py +64 -23
  24. classiq/interface/generator/quantum_program.py +18 -1
  25. classiq/interface/generator/types/builtin_enum_declarations.py +1 -0
  26. classiq/interface/generator/types/enum_declaration.py +45 -3
  27. classiq/interface/ide/visual_model.py +0 -2
  28. classiq/interface/model/classical_if.py +2 -2
  29. classiq/interface/model/control.py +2 -2
  30. classiq/interface/model/invert.py +2 -2
  31. classiq/interface/model/power.py +2 -2
  32. classiq/interface/model/quantum_function_call.py +4 -0
  33. classiq/interface/model/quantum_statement.py +1 -1
  34. classiq/interface/model/repeat.py +2 -2
  35. classiq/interface/model/statement_block.py +1 -1
  36. classiq/interface/model/within_apply_operation.py +2 -2
  37. classiq/interface/server/routes.py +0 -6
  38. classiq/model_expansions/generative_functions.py +4 -3
  39. classiq/model_expansions/interpreters/generative_interpreter.py +78 -18
  40. classiq/model_expansions/quantum_operations/allocate.py +3 -1
  41. classiq/model_expansions/quantum_operations/assignment_result_processor.py +52 -0
  42. classiq/model_expansions/quantum_operations/bind.py +2 -1
  43. classiq/model_expansions/quantum_operations/block_evaluator.py +76 -0
  44. classiq/model_expansions/quantum_operations/call_emitter.py +0 -13
  45. classiq/model_expansions/quantum_operations/classicalif.py +5 -4
  46. classiq/model_expansions/quantum_operations/composite_emitter.py +27 -0
  47. classiq/model_expansions/quantum_operations/emitter.py +16 -2
  48. classiq/model_expansions/quantum_operations/expression_evaluator.py +33 -0
  49. classiq/model_expansions/quantum_operations/handle_evaluator.py +28 -0
  50. classiq/model_expansions/quantum_operations/quantum_function_call.py +3 -2
  51. classiq/model_expansions/quantum_operations/repeat.py +2 -1
  52. classiq/model_expansions/quantum_operations/variable_decleration.py +2 -1
  53. classiq/model_expansions/scope_initialization.py +5 -19
  54. classiq/model_expansions/sympy_conversion/expression_to_sympy.py +1 -1
  55. classiq/open_library/functions/__init__.py +1 -2
  56. classiq/open_library/functions/amplitude_amplification.py +11 -12
  57. classiq/open_library/functions/discrete_sine_cosine_transform.py +17 -14
  58. classiq/open_library/functions/grover.py +7 -11
  59. classiq/open_library/functions/hea.py +3 -3
  60. classiq/open_library/functions/modular_exponentiation.py +17 -33
  61. classiq/open_library/functions/qft_functions.py +2 -2
  62. classiq/open_library/functions/qsvt.py +8 -8
  63. classiq/open_library/functions/state_preparation.py +16 -17
  64. classiq/open_library/functions/swap_test.py +1 -1
  65. classiq/open_library/functions/utility_functions.py +12 -4
  66. classiq/qmod/builtins/classical_functions.py +24 -7
  67. classiq/qmod/builtins/enums.py +1 -0
  68. classiq/qmod/builtins/functions/__init__.py +2 -0
  69. classiq/qmod/builtins/functions/chemistry.py +6 -38
  70. classiq/qmod/builtins/functions/exponentiation.py +24 -0
  71. classiq/qmod/builtins/operations.py +26 -11
  72. classiq/qmod/cparam.py +32 -5
  73. classiq/qmod/python_classical_type.py +10 -4
  74. classiq/qmod/quantum_callable.py +2 -1
  75. classiq/qmod/quantum_expandable.py +30 -6
  76. classiq/qmod/quantum_function.py +3 -2
  77. classiq/qmod/semantics/error_manager.py +1 -1
  78. classiq/qmod/semantics/validation/types_validation.py +1 -1
  79. classiq/qmod/symbolic.py +2 -1
  80. classiq/qmod/utilities.py +31 -2
  81. classiq/qmod/write_qmod.py +10 -7
  82. classiq/synthesis.py +25 -9
  83. {classiq-0.67.0.dist-info → classiq-0.69.0.dist-info}/METADATA +1 -1
  84. {classiq-0.67.0.dist-info → classiq-0.69.0.dist-info}/RECORD +85 -81
  85. classiq/interface/execution/jobs.py +0 -31
  86. classiq/model_expansions/quantum_operations/shallow_emitter.py +0 -166
  87. {classiq-0.67.0.dist-info → classiq-0.69.0.dist-info}/WHEEL +0 -0
@@ -16,7 +16,7 @@ from classiq.model_expansions.scope import Evaluated, QuantumSymbol
16
16
 
17
17
 
18
18
  class BindEmitter(Emitter[BindOperation]):
19
- def emit(self, bind: BindOperation, /) -> None:
19
+ def emit(self, bind: BindOperation, /) -> bool:
20
20
  inputs, outputs = self._get_inputs_outputs(bind)
21
21
  validate_bind_targets(bind, self._current_scope)
22
22
  unsized_outputs = [
@@ -56,6 +56,7 @@ class BindEmitter(Emitter[BindOperation]):
56
56
  back_ref=bind.uuid,
57
57
  )
58
58
  )
59
+ return True
59
60
 
60
61
  def _get_inputs_outputs(
61
62
  self, bind: BindOperation
@@ -0,0 +1,76 @@
1
+ from collections.abc import Sequence
2
+ from typing import TYPE_CHECKING
3
+
4
+ from classiq.interface.model.quantum_statement import QuantumOperation, QuantumStatement
5
+
6
+ from classiq.model_expansions.closure import Closure
7
+ from classiq.model_expansions.quantum_operations.emitter import Emitter
8
+ from classiq.model_expansions.scope import Scope
9
+
10
+ if TYPE_CHECKING:
11
+ from classiq.model_expansions.interpreters.base_interpreter import BaseInterpreter
12
+
13
+
14
+ _BLOCK_RENAMES = {
15
+ "compute": "within",
16
+ "action": "apply",
17
+ }
18
+ _REVERSE_BLOCK_RENAMES = {rename: name for name, rename in _BLOCK_RENAMES.items()}
19
+
20
+
21
+ class BlockEvaluator(Emitter[QuantumOperation]):
22
+ def __init__(
23
+ self, interpreter: "BaseInterpreter", operation_name: str, *block_names: str
24
+ ) -> None:
25
+ super().__init__(interpreter)
26
+ self._operation_name = operation_name
27
+ self._block_names: Sequence[str] = block_names
28
+
29
+ def emit(self, op: QuantumOperation, /) -> bool:
30
+ expanded_blocks: dict[str, list[QuantumStatement]] = {}
31
+ blocks = [
32
+ block
33
+ for block in self._block_names
34
+ if hasattr(op, block) and getattr(op, block) is not None
35
+ ]
36
+
37
+ if len(blocks) > 0:
38
+ if op.is_generative():
39
+ expanded_blocks = self.expand_generative_blocks(op)
40
+ else:
41
+ expanded_blocks = self.expand_blocks(op, blocks)
42
+ expanded_blocks.update(expanded_blocks)
43
+
44
+ op = op.model_copy(update={**expanded_blocks, "back_ref": op.uuid})
45
+ self._builder.emit_statement(op)
46
+ return True
47
+
48
+ def expand_blocks(
49
+ self, op: QuantumOperation, block_names: list[str]
50
+ ) -> dict[str, list[QuantumStatement]]:
51
+ blocks = {
52
+ _BLOCK_RENAMES.get(block, block): getattr(op, block)
53
+ for block in block_names
54
+ }
55
+ block_closure = Closure(
56
+ name=self._operation_name,
57
+ scope=Scope(parent=self._current_scope),
58
+ blocks=blocks,
59
+ )
60
+ context = self._expand_operation(block_closure)
61
+ return {
62
+ block: context.statements(_BLOCK_RENAMES.get(block, block))
63
+ for block in block_names
64
+ }
65
+
66
+ def expand_generative_blocks(
67
+ self, op: QuantumOperation
68
+ ) -> dict[str, list[QuantumStatement]]:
69
+ blocks = [
70
+ block for block in self._block_names if op.has_generative_block(block)
71
+ ]
72
+ context = self._expand_generative_context(op, self._operation_name, blocks)
73
+ return {
74
+ _REVERSE_BLOCK_RENAMES.get(block, block): context.statements(block)
75
+ for block in blocks
76
+ }
@@ -13,9 +13,6 @@ from classiq.interface.generator.functions.port_declaration import (
13
13
  PortDeclarationDirection,
14
14
  )
15
15
  from classiq.interface.generator.generated_circuit_data import OperationLevel
16
- from classiq.interface.model.classical_parameter_declaration import (
17
- ClassicalParameterDeclaration,
18
- )
19
16
  from classiq.interface.model.handle_binding import HandleBinding
20
17
  from classiq.interface.model.native_function_definition import NativeFunctionDefinition
21
18
  from classiq.interface.model.port_declaration import PortDeclaration
@@ -162,11 +159,6 @@ class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], VarSpl
162
159
  back_ref=self._get_back_ref(propagated_debug_info),
163
160
  )
164
161
  is_allocate_or_free = new_call.func_name == free.func_decl.name
165
- parameters = {
166
- arg_decl.name: FunctionDebugInfo.param_controller(value=evaluated_arg.value)
167
- for arg_decl, evaluated_arg in zip(new_positional_arg_decls, evaluated_args)
168
- if isinstance(arg_decl, ClassicalParameterDeclaration)
169
- }
170
162
 
171
163
  port_to_passed_variable_map = {
172
164
  arg_decl.name: str(evaluated_arg.value.handle)
@@ -176,11 +168,6 @@ class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], VarSpl
176
168
  self._debug_info[new_call.uuid] = FunctionDebugInfo(
177
169
  name=new_call.func_name,
178
170
  level=OperationLevel.QMOD_FUNCTION_CALL,
179
- parameters=(
180
- parameters
181
- if propagated_debug_info is None or propagated_debug_info.name == ""
182
- else propagated_debug_info.parameters
183
- ),
184
171
  is_allocate_or_free=is_allocate_or_free,
185
172
  port_to_passed_variable_map=port_to_passed_variable_map,
186
173
  node=new_call._as_back_ref(),
@@ -18,7 +18,7 @@ def _is_all_identity_calls(body: Sequence[QuantumStatement]) -> bool:
18
18
 
19
19
 
20
20
  class ClassicalIfEmitter(CallEmitter[ClassicalIf]):
21
- def emit(self, classical_if: ClassicalIf, /) -> None:
21
+ def emit(self, classical_if: ClassicalIf, /) -> bool:
22
22
  condition = self._interpreter.evaluate(classical_if.condition).as_type(bool)
23
23
  op_name = "then" if condition else "else"
24
24
  is_generative = classical_if.is_generative()
@@ -26,7 +26,7 @@ class ClassicalIfEmitter(CallEmitter[ClassicalIf]):
26
26
  body: Sequence[QuantumStatement]
27
27
  if is_generative:
28
28
  if not classical_if.has_generative_block(op_name):
29
- return
29
+ return True
30
30
  context = self._expand_generative_context(classical_if, op_name, op_name)
31
31
  context.blocks["body"] = context.blocks[op_name]
32
32
  context.blocks.pop(op_name)
@@ -35,7 +35,7 @@ class ClassicalIfEmitter(CallEmitter[ClassicalIf]):
35
35
  body = classical_if.then if condition else classical_if.else_
36
36
 
37
37
  if _is_all_identity_calls(body):
38
- return
38
+ return True
39
39
 
40
40
  if is_generative or not self._should_wrap(body):
41
41
  for stmt in body:
@@ -43,7 +43,7 @@ class ClassicalIfEmitter(CallEmitter[ClassicalIf]):
43
43
  self._interpreter._builder.emit_statement(stmt)
44
44
  else:
45
45
  self._interpreter.emit_statement(stmt)
46
- return
46
+ return True
47
47
 
48
48
  then_else_func = FunctionClosure.create(
49
49
  name=self._counted_name_allocator.allocate("then" if condition else "else"),
@@ -54,3 +54,4 @@ class ClassicalIfEmitter(CallEmitter[ClassicalIf]):
54
54
  self._emit_quantum_function_call(
55
55
  then_else_func, list(), new_function_debug_info_by_node(classical_if)
56
56
  )
57
+ return True
@@ -0,0 +1,27 @@
1
+ from collections.abc import Sequence
2
+ from typing import TYPE_CHECKING, Generic
3
+
4
+ from classiq.model_expansions.quantum_operations.emitter import (
5
+ Emitter,
6
+ QuantumStatementT,
7
+ )
8
+
9
+ if TYPE_CHECKING:
10
+ from classiq.model_expansions.interpreters.base_interpreter import BaseInterpreter
11
+
12
+
13
+ class CompositeEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT]):
14
+ def __init__(
15
+ self,
16
+ interpreter: "BaseInterpreter",
17
+ emitters: Sequence[Emitter[QuantumStatementT]],
18
+ ) -> None:
19
+ super().__init__(interpreter)
20
+ self._emitters = emitters
21
+
22
+ def emit(self, statement: QuantumStatementT, /) -> bool:
23
+ for emitter in self._emitters:
24
+ if emitter.emit(statement):
25
+ return True
26
+ self._builder.emit_statement(statement)
27
+ return True
@@ -1,3 +1,4 @@
1
+ import ast
1
2
  from abc import ABC, abstractmethod
2
3
  from typing import (
3
4
  TYPE_CHECKING,
@@ -39,12 +40,15 @@ from classiq.model_expansions.sympy_conversion.sympy_to_python import (
39
40
  translate_sympy_quantum_expression,
40
41
  )
41
42
  from classiq.model_expansions.utils.counted_name_allocator import CountedNameAllocator
43
+ from classiq.model_expansions.visitors.variable_references import VarRefCollector
42
44
  from classiq.qmod.quantum_function import GenerativeQFunc
43
45
 
44
46
  if TYPE_CHECKING:
45
47
  from classiq.model_expansions.interpreters.base_interpreter import BaseInterpreter
46
48
 
47
- QuantumStatementT = TypeVar("QuantumStatementT", bound=QuantumStatement)
49
+ QuantumStatementT = TypeVar(
50
+ "QuantumStatementT", bound=QuantumStatement, contravariant=True
51
+ )
48
52
 
49
53
 
50
54
  class Emitter(Generic[QuantumStatementT], ABC):
@@ -60,7 +64,7 @@ class Emitter(Generic[QuantumStatementT], ABC):
60
64
  )
61
65
 
62
66
  @abstractmethod
63
- def emit(self, statement: QuantumStatementT, /) -> None:
67
+ def emit(self, statement: QuantumStatementT, /) -> bool:
64
68
  pass
65
69
 
66
70
  def _expand_operation(self, closure: Closure) -> OperationContext:
@@ -173,3 +177,13 @@ class Emitter(Generic[QuantumStatementT], ABC):
173
177
  defining_function=defining_function,
174
178
  direction=direction,
175
179
  )
180
+
181
+ def _get_symbols_in_expression(self, expr: Expression) -> list[QuantumSymbol]:
182
+ vrc = VarRefCollector(ignore_duplicated_handles=True)
183
+ vrc.visit(ast.parse(expr.expr))
184
+ handles = dict.fromkeys(
185
+ handle
186
+ for handle in vrc.var_handles
187
+ if isinstance(self._current_scope[handle.name].value, QuantumSymbol)
188
+ )
189
+ return [self._interpreter.evaluate(handle).value for handle in handles]
@@ -0,0 +1,33 @@
1
+ from typing import TYPE_CHECKING
2
+
3
+ from classiq.interface.generator.expressions.expression import Expression
4
+ from classiq.interface.generator.functions.port_declaration import (
5
+ PortDeclarationDirection,
6
+ )
7
+ from classiq.interface.model.quantum_statement import QuantumOperation
8
+
9
+ from classiq.model_expansions.quantum_operations.emitter import Emitter
10
+
11
+ if TYPE_CHECKING:
12
+ from classiq.model_expansions.interpreters.base_interpreter import BaseInterpreter
13
+
14
+
15
+ class ExpressionEvaluator(Emitter[QuantumOperation]):
16
+ def __init__(self, interpreter: "BaseInterpreter", expression_name: str) -> None:
17
+ super().__init__(interpreter)
18
+ self._expression_name = expression_name
19
+
20
+ def emit(self, op: QuantumOperation, /) -> bool:
21
+ expression = getattr(op, self._expression_name)
22
+ if not isinstance(expression, Expression) or expression.is_evaluated():
23
+ return False
24
+ evaluated_expression = self._evaluate_expression(
25
+ expression, preserve_bool_ops=True
26
+ )
27
+ for symbol in self._get_symbols_in_expression(evaluated_expression):
28
+ self._capture_handle(symbol.handle, PortDeclarationDirection.Inout)
29
+ op = op.model_copy(
30
+ update={self._expression_name: evaluated_expression, "back_ref": op.uuid}
31
+ )
32
+ self._interpreter.emit(op)
33
+ return True
@@ -0,0 +1,28 @@
1
+ from typing import TYPE_CHECKING
2
+
3
+ from classiq.interface.model.handle_binding import HandleBinding
4
+ from classiq.interface.model.quantum_statement import QuantumOperation
5
+
6
+ from classiq.model_expansions.quantum_operations.emitter import Emitter
7
+
8
+ if TYPE_CHECKING:
9
+ from classiq.model_expansions.interpreters.base_interpreter import BaseInterpreter
10
+
11
+
12
+ class HandleEvaluator(Emitter[QuantumOperation]):
13
+ def __init__(self, interpreter: "BaseInterpreter", handle_name: str) -> None:
14
+ super().__init__(interpreter)
15
+ self._handle_name = handle_name
16
+
17
+ def emit(self, op: QuantumOperation, /) -> bool:
18
+ handle = getattr(op, self._handle_name)
19
+ if not isinstance(handle, HandleBinding):
20
+ return False
21
+ evaluated_handle = self._interpreter.evaluate(handle).value.handle
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.emit(op)
28
+ return True
@@ -28,16 +28,17 @@ class QuantumFunctionCallEmitter(CallEmitter[QuantumFunctionCall]):
28
28
  super().__init__(interpreter)
29
29
  self._model = self._interpreter._model
30
30
 
31
- def emit(self, call: QuantumFunctionCall, /) -> None:
31
+ def emit(self, call: QuantumFunctionCall, /) -> bool:
32
32
  if call.function == "allocate": # FIXME: Remove compatibility (CAD-25935)
33
33
  self._allocate_compatibility(call)
34
- return
34
+ return True
35
35
  function = self._interpreter.evaluate(call.function).as_type(FunctionClosure)
36
36
  args = call.positional_args
37
37
  with ErrorManager().call(function.name):
38
38
  self._emit_quantum_function_call(
39
39
  function, args, self._debug_info.get(call.uuid)
40
40
  )
41
+ return True
41
42
 
42
43
  def _allocate_compatibility(self, call: QuantumFunctionCall) -> None:
43
44
  if len(call.positional_args) != 2:
@@ -17,7 +17,7 @@ from classiq.qmod.quantum_function import GenerativeQFunc
17
17
 
18
18
 
19
19
  class RepeatEmitter(CallEmitter[Repeat]):
20
- def emit(self, repeat: Repeat, /) -> None:
20
+ def emit(self, repeat: Repeat, /) -> bool:
21
21
  count = self._interpreter.evaluate(repeat.count).as_type(int)
22
22
  if count < 0:
23
23
  raise ClassiqExpansionError(
@@ -26,6 +26,7 @@ class RepeatEmitter(CallEmitter[Repeat]):
26
26
  op_name = self._counted_name_allocator.allocate(REPEAT_OPERATOR_NAME)
27
27
  for i in range(count):
28
28
  self._emit_iteration(repeat, i, op_name)
29
+ return True
29
30
 
30
31
  def _emit_iteration(self, repeat: Repeat, i: int, op_name: str) -> None:
31
32
  closure_constructor: type[FunctionClosure]
@@ -12,7 +12,7 @@ from classiq.model_expansions.scope import Evaluated, QuantumSymbol
12
12
 
13
13
 
14
14
  class VariableDeclarationStatementEmitter(Emitter[VariableDeclarationStatement]):
15
- def emit(self, variable_declaration: VariableDeclarationStatement, /) -> None:
15
+ def emit(self, variable_declaration: VariableDeclarationStatement, /) -> bool:
16
16
  var_decl = variable_declaration.model_copy(
17
17
  update=dict(back_ref=variable_declaration.uuid)
18
18
  )
@@ -36,3 +36,4 @@ class VariableDeclarationStatementEmitter(Emitter[VariableDeclarationStatement])
36
36
  var_decl.name, self._builder.current_function
37
37
  )
38
38
  self.emit_statement(var_decl)
39
+ return True
@@ -3,10 +3,6 @@ from typing import Any
3
3
 
4
4
  from classiq.interface.exceptions import ClassiqError
5
5
  from classiq.interface.generator.constant import Constant
6
- from classiq.interface.generator.expressions.expression_constants import (
7
- CPARAM_EXECUTION_SUFFIX,
8
- RESERVED_EXPRESSIONS,
9
- )
10
6
  from classiq.interface.generator.functions.concrete_types import ConcreteClassicalType
11
7
  from classiq.interface.model.handle_binding import HandleBinding
12
8
  from classiq.interface.model.model import MAIN_FUNCTION_NAME, Model
@@ -129,12 +125,6 @@ def init_builtin_types() -> None:
129
125
  QMODULE.type_decls |= BUILTIN_STRUCT_DECLARATIONS
130
126
 
131
127
 
132
- def _rename_exec_param(param_name: str) -> str:
133
- if param_name in RESERVED_EXPRESSIONS:
134
- return param_name
135
- return param_name + CPARAM_EXECUTION_SUFFIX
136
-
137
-
138
128
  def _add_exec_param_parts_to_scope(param_val: Any, scope: Scope) -> None:
139
129
  if not isinstance(param_val, list):
140
130
  scope[str(param_val)] = Evaluated(value=param_val)
@@ -145,21 +135,17 @@ def _add_exec_param_parts_to_scope(param_val: Any, scope: Scope) -> None:
145
135
 
146
136
  def init_exec_params(model: Model, scope: Scope) -> dict[str, ConcreteClassicalType]:
147
137
  if model.execution_parameters is not None:
148
- exec_params = {
149
- param_name: (param_name, param_type)
150
- for param_name, param_type in model.execution_parameters.items()
151
- }
138
+ exec_params = model.execution_parameters
152
139
  else:
153
140
  exec_params = {
154
- param.name: (_rename_exec_param(param.name), param.classical_type)
141
+ param.name: param.classical_type
155
142
  for param in model.function_dict.get(
156
143
  "_dec_main", model.main_func
157
144
  ).param_decls
158
145
  }
159
- for param_name, (param_rename, param_type) in exec_params.items():
160
- param_val = param_type.as_symbolic(param_rename)
146
+ for param_name, param_type in exec_params.items():
147
+ param_val = param_type.as_symbolic(param_name)
161
148
  scope[param_name] = Evaluated(value=param_val)
162
- scope[param_rename] = Evaluated(value=param_val)
163
149
  if isinstance(param_val, list):
164
150
  _add_exec_param_parts_to_scope(param_val, scope)
165
- return dict(exec_params.values())
151
+ return exec_params
@@ -174,6 +174,6 @@ class ExpressionSympyTranslator(ast.NodeTransformer):
174
174
  def visit_Attribute(self, node: ast.Attribute) -> ast.Call:
175
175
  return ast.Call(
176
176
  func=ast.Name("get_field"),
177
- args=[node.value, ast.Constant(value=node.attr)],
177
+ args=[self.visit(node.value), ast.Constant(value=node.attr)],
178
178
  keywords=[],
179
179
  )
@@ -10,7 +10,7 @@ from .hea import *
10
10
  from .linear_pauli_rotation import *
11
11
  from .linear_pauli_rotation import _single_pauli
12
12
  from .modular_exponentiation import *
13
- from .modular_exponentiation import _check_msb, _ctrl_x
13
+ from .modular_exponentiation import _check_msb
14
14
  from .qaoa_penalty import *
15
15
  from .qft_functions import *
16
16
  from .qpe import *
@@ -72,7 +72,6 @@ OPEN_LIBRARY_FUNCTIONS = [
72
72
  qst_type2,
73
73
  modular_increment,
74
74
  qft,
75
- _ctrl_x,
76
75
  _prepare_uniform_trimmed_state_step,
77
76
  _qct_d_operator,
78
77
  _qct_pi_operator,
@@ -4,7 +4,7 @@ from classiq.qmod.builtins.operations import (
4
4
  allocate,
5
5
  bind,
6
6
  control,
7
- repeat,
7
+ power,
8
8
  within_apply,
9
9
  )
10
10
  from classiq.qmod.cparam import CInt, CReal
@@ -24,7 +24,7 @@ def amplitude_amplification(
24
24
  """
25
25
  [Qmod Classiq-library function]
26
26
 
27
- Applies the Amplitude Amplification algorithm (QAE); Prepares a state using the given `space_transform` function, and applies `reps` repetititions
27
+ Applies the Amplitude Amplification algorithm; Prepares a state using the given `space_transform` function, and applies `reps` repetititions
28
28
  of the grover operator, using the given `oracle` functions which marks the "good" states.
29
29
 
30
30
  Args:
@@ -34,7 +34,10 @@ def amplitude_amplification(
34
34
  packed_vars: The variable that holds the state to be amplified. Assumed to be in the zero state at the beginning of the algorithm.
35
35
  """
36
36
  space_transform(packed_qvars)
37
- repeat(reps, lambda index: grover_operator(oracle, space_transform, packed_qvars))
37
+ power(
38
+ reps,
39
+ lambda: grover_operator(oracle, space_transform, packed_qvars),
40
+ )
38
41
 
39
42
 
40
43
  @qfunc
@@ -47,7 +50,7 @@ def exact_amplitude_amplification(
47
50
  """
48
51
  [Qmod Classiq-library function]
49
52
 
50
- Applies an exact version of the Amplitude Amplification algorithm (QAE), assuming knowledge of the amplitude of the marked state.
53
+ Applies an exact version of the Amplitude Amplification algorithm, assuming knowledge of the amplitude of the marked state.
51
54
  The function should be applied on the zero state, and it takes care for preparing the initial state before amplification using the `space_transform`.
52
55
 
53
56
  Based on the algorithm in [Quantum state preparation without coherent arithmetic](https://arxiv.org/abs/2210.14892).
@@ -68,13 +71,11 @@ def exact_amplitude_amplification(
68
71
  theta = pi / (4 * k + 2)
69
72
  rot_phase = 2 * acos(sin(theta) / amplitude)
70
73
 
71
- extended_qvars: QArray = QArray("extended_qvars")
74
+ extended_qvars: QArray = QArray()
72
75
  within_apply(
73
- lambda: [ # type:ignore[arg-type]
76
+ lambda: [
74
77
  allocate(aux),
75
- bind(
76
- [aux, packed_qvars], extended_qvars
77
- ), # type:ignore[func-returns-value]
78
+ bind([aux, packed_qvars], extended_qvars),
78
79
  ],
79
80
  lambda: amplitude_amplification(
80
81
  k,
@@ -82,9 +83,7 @@ def exact_amplitude_amplification(
82
83
  qvars_[0] == 0, lambda: oracle(qvars_[1 : qvars_.size])
83
84
  ),
84
85
  lambda qvars_: [
85
- space_transform( # type:ignore[func-returns-value]
86
- qvars_[1 : qvars_.size]
87
- ),
86
+ space_transform(qvars_[1 : qvars_.size]),
88
87
  RY(rot_phase, qvars_[0]),
89
88
  ],
90
89
  extended_qvars,
@@ -1,13 +1,11 @@
1
1
  from classiq.open_library.functions.qft_functions import qft
2
- from classiq.open_library.functions.utility_functions import (
3
- apply_to_all,
4
- modular_increment,
5
- )
2
+ from classiq.open_library.functions.utility_functions import apply_to_all
6
3
  from classiq.qmod.builtins.functions.standard_gates import PHASE, H, S, X, Z
7
4
  from classiq.qmod.builtins.operations import (
8
5
  allocate,
9
6
  bind,
10
7
  control,
8
+ inplace_add,
11
9
  invert,
12
10
  repeat,
13
11
  within_apply,
@@ -30,8 +28,13 @@ def _qct_d_operator(x: QNum, q: QBit) -> None:
30
28
 
31
29
  @qfunc
32
30
  def _qct_pi_operator(x: QArray[QBit], q: QBit) -> None:
33
- control(q == 1, lambda: apply_to_all(X, x))
34
- control(q == 1, lambda: modular_increment(1, x))
31
+ control(
32
+ q == 1,
33
+ lambda: [
34
+ apply_to_all(X, x),
35
+ inplace_add(1, x), # type:ignore[arg-type]
36
+ ],
37
+ )
35
38
 
36
39
 
37
40
  def _t_operator(x: QArray) -> None:
@@ -63,11 +66,11 @@ def _d1_operator(x: QArray[QBit], q: QBit) -> None:
63
66
 
64
67
 
65
68
  def _pi2_operator(x: QArray[QBit], q: QBit) -> None:
66
- control(q == 1, lambda: modular_increment(1, x))
69
+ control(q == 1, lambda: inplace_add(1, x)) # type:ignore[arg-type]
67
70
 
68
71
 
69
72
  def _j_operator(q: QBit) -> None:
70
- within_apply(lambda: Z(q), lambda: (S(q), H(q), S(q))) # type:ignore[arg-type]
73
+ within_apply(lambda: Z(q), lambda: (S(q), H(q), S(q)))
71
74
 
72
75
 
73
76
  def _b_t_operator(q: QBit) -> None:
@@ -76,7 +79,7 @@ def _b_t_operator(q: QBit) -> None:
76
79
 
77
80
 
78
81
  def _d0dt_operator(x: QArray, q: QBit) -> None:
79
- x_num: QNum = QNum("x_num", x.len, False, 0)
82
+ x_num: QNum = QNum(size=x.len)
80
83
  bind(x, x_num)
81
84
  _b_t_operator(q)
82
85
  control(x_num == 0, lambda: _j_operator(q))
@@ -140,7 +143,7 @@ def qct_qst_type2(x: QArray[QBit], q: QBit) -> None:
140
143
  x: The LSB part of the qubit array to apply the transform to.
141
144
  q: The MSB of the qubit array to apply the transform to.
142
145
  """
143
- extended_state: QArray = QArray("extended_state")
146
+ extended_state: QArray = QArray()
144
147
  _vn_operator(x, q)
145
148
  bind([x, q], extended_state)
146
149
  qft(extended_state)
@@ -159,8 +162,8 @@ def qct_type2(x: QArray[QBit]) -> None:
159
162
  Args:
160
163
  x: The qubit array to apply the transform to.
161
164
  """
162
- q = QBit("q")
163
- within_apply(lambda: allocate(1, q), lambda: qct_qst_type2(x, q))
165
+ q = QBit()
166
+ within_apply(lambda: allocate(q), lambda: qct_qst_type2(x, q))
164
167
 
165
168
 
166
169
  @qfunc
@@ -174,8 +177,8 @@ def qst_type2(x: QArray[QBit]) -> None:
174
177
  Args:
175
178
  x: The qubit array to apply the transform to.
176
179
  """
177
- q = QBit("q")
180
+ q = QBit()
178
181
  within_apply(
179
- lambda: (allocate(1, q), X(q)), # type:ignore[arg-type]
182
+ lambda: (allocate(q), X(q)),
180
183
  lambda: qct_qst_type2(x, q),
181
184
  )
@@ -40,9 +40,9 @@ def phase_oracle(
40
40
  predicate: A predicate function that takes a QArray of QBits and sets a single QBit |1> if the predicate is true, and |0> otherwise.
41
41
  target: The target QArray of QBits to apply the phase oracle to.
42
42
  """
43
- aux = QBit("aux")
43
+ aux = QBit()
44
44
  within_apply(
45
- within=lambda: (allocate(1, aux), X(aux), H(aux)), # type:ignore[arg-type]
45
+ within=lambda: (allocate(aux), X(aux), H(aux)),
46
46
  apply=lambda: predicate(target, aux),
47
47
  )
48
48
 
@@ -64,11 +64,11 @@ def reflect_about_zero(packed_vars: QArray[QBit]) -> None:
64
64
  Args:
65
65
  packed_vars: The quantum state to reflect.
66
66
  """
67
- msbs: QNum = QNum("msbs", packed_vars.len - 1, False, 0)
68
- lsb = QBit("lsb")
67
+ msbs: QNum = QNum(size=packed_vars.len - 1)
68
+ lsb = QBit()
69
69
  bind(packed_vars, [msbs, lsb])
70
70
  within_apply(
71
- lambda: (X(lsb), H(lsb)), # type:ignore[arg-type]
71
+ lambda: (X(lsb), H(lsb)),
72
72
  lambda: control(msbs == 0, lambda: X(lsb)),
73
73
  )
74
74
  bind([msbs, lsb], packed_vars)
@@ -126,7 +126,7 @@ def grover_operator(
126
126
  packed_vars: The state to which to apply the grover operator.
127
127
  """
128
128
  oracle(packed_vars)
129
- grover_diffuser(lambda qba: space_transform(qba), packed_vars)
129
+ grover_diffuser(space_transform, packed_vars)
130
130
  U(0, 0, 0, pi, packed_vars[0])
131
131
 
132
132
 
@@ -149,9 +149,5 @@ def grover_search(
149
149
  hadamard_transform(packed_vars)
150
150
  power(
151
151
  reps,
152
- lambda: grover_operator(
153
- lambda qba: oracle(qba),
154
- lambda qba: hadamard_transform(qba),
155
- packed_vars,
156
- ),
152
+ lambda: grover_operator(oracle, hadamard_transform, packed_vars),
157
153
  )
@@ -58,8 +58,8 @@ def full_hea(
58
58
  """
59
59
  repeat(
60
60
  reps,
61
- lambda r: [ # type:ignore[arg-type]
62
- repeat( # type:ignore[func-returns-value]
61
+ lambda r: [
62
+ repeat(
63
63
  operands_1qubit.len,
64
64
  lambda i1: repeat(
65
65
  num_qubits,
@@ -77,7 +77,7 @@ def full_hea(
77
77
  ),
78
78
  ),
79
79
  ),
80
- repeat( # type:ignore[func-returns-value]
80
+ repeat(
81
81
  operands_2qubit.len,
82
82
  lambda i2: repeat(
83
83
  connectivity_map.len,