classiq 0.39.0__py3-none-any.whl → 0.41.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 (100) hide show
  1. classiq/__init__.py +5 -2
  2. classiq/_internals/api_wrapper.py +3 -21
  3. classiq/applications/chemistry/chemistry_model_constructor.py +87 -101
  4. classiq/applications/combinatorial_helpers/combinatorial_problem_utils.py +7 -26
  5. classiq/applications/combinatorial_helpers/optimization_model.py +7 -6
  6. classiq/applications/combinatorial_helpers/pauli_helpers/pauli_utils.py +33 -55
  7. classiq/applications/combinatorial_optimization/__init__.py +4 -0
  8. classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py +29 -26
  9. classiq/applications/finance/finance_model_constructor.py +23 -26
  10. classiq/applications/grover/grover_model_constructor.py +37 -38
  11. classiq/applications/qsvm/qsvm.py +1 -2
  12. classiq/applications/qsvm/qsvm_model_constructor.py +15 -16
  13. classiq/execution/__init__.py +4 -0
  14. classiq/execution/execution_session.py +151 -0
  15. classiq/execution/qnn.py +80 -0
  16. classiq/executor.py +2 -109
  17. classiq/interface/_version.py +1 -1
  18. classiq/interface/analyzer/analysis_params.py +11 -0
  19. classiq/interface/applications/qsvm.py +0 -8
  20. classiq/interface/ast_node.py +12 -2
  21. classiq/interface/backend/backend_preferences.py +30 -6
  22. classiq/interface/backend/quantum_backend_providers.py +11 -11
  23. classiq/interface/executor/execution_preferences.py +7 -67
  24. classiq/interface/executor/execution_result.py +22 -1
  25. classiq/interface/generator/application_apis/chemistry_declarations.py +2 -4
  26. classiq/interface/generator/application_apis/finance_declarations.py +1 -1
  27. classiq/interface/generator/arith/binary_ops.py +88 -25
  28. classiq/interface/generator/arith/unary_ops.py +28 -19
  29. classiq/interface/generator/expressions/atomic_expression_functions.py +6 -2
  30. classiq/interface/generator/expressions/enums/__init__.py +10 -0
  31. classiq/interface/generator/expressions/enums/classical_enum.py +5 -1
  32. classiq/interface/generator/expressions/expression.py +9 -2
  33. classiq/interface/generator/expressions/qmod_qarray_proxy.py +89 -0
  34. classiq/interface/generator/expressions/qmod_qscalar_proxy.py +20 -0
  35. classiq/interface/generator/expressions/qmod_sized_proxy.py +22 -0
  36. classiq/interface/generator/expressions/sympy_supported_expressions.py +10 -1
  37. classiq/interface/generator/functions/builtins/core_library/atomic_quantum_functions.py +8 -6
  38. classiq/interface/generator/functions/builtins/core_library/exponentiation_functions.py +10 -4
  39. classiq/interface/generator/functions/builtins/internal_operators.py +7 -62
  40. classiq/interface/generator/functions/builtins/open_lib_functions.py +1627 -271
  41. classiq/interface/generator/functions/classical_type.py +27 -17
  42. classiq/interface/generator/model/preferences/preferences.py +4 -2
  43. classiq/interface/generator/synthesis_metadata/synthesis_duration.py +0 -4
  44. classiq/interface/model/bind_operation.py +3 -1
  45. classiq/interface/model/call_synthesis_data.py +2 -13
  46. classiq/interface/model/classical_if.py +3 -1
  47. classiq/interface/model/classical_parameter_declaration.py +13 -0
  48. classiq/interface/model/control.py +6 -8
  49. classiq/interface/model/inplace_binary_operation.py +3 -1
  50. classiq/interface/model/invert.py +3 -1
  51. classiq/interface/model/port_declaration.py +8 -1
  52. classiq/interface/model/power.py +3 -1
  53. classiq/interface/model/quantum_expressions/amplitude_loading_operation.py +4 -2
  54. classiq/interface/model/quantum_expressions/arithmetic_operation.py +3 -1
  55. classiq/interface/model/quantum_expressions/quantum_expression.py +11 -1
  56. classiq/interface/model/quantum_function_call.py +4 -10
  57. classiq/interface/model/quantum_function_declaration.py +26 -4
  58. classiq/interface/model/quantum_lambda_function.py +1 -20
  59. classiq/interface/model/quantum_statement.py +9 -2
  60. classiq/interface/model/quantum_type.py +6 -5
  61. classiq/interface/model/repeat.py +3 -1
  62. classiq/interface/model/resolvers/function_call_resolver.py +0 -5
  63. classiq/interface/model/statement_block.py +19 -16
  64. classiq/interface/model/validations/handles_validator.py +8 -2
  65. classiq/interface/model/variable_declaration_statement.py +3 -1
  66. classiq/interface/model/within_apply_operation.py +3 -1
  67. classiq/interface/server/routes.py +0 -5
  68. classiq/qmod/__init__.py +5 -2
  69. classiq/qmod/builtins/classical_execution_primitives.py +22 -2
  70. classiq/qmod/builtins/classical_functions.py +30 -35
  71. classiq/qmod/builtins/functions.py +263 -153
  72. classiq/qmod/builtins/operations.py +50 -26
  73. classiq/qmod/builtins/structs.py +50 -48
  74. classiq/qmod/declaration_inferrer.py +32 -27
  75. classiq/qmod/native/__init__.py +9 -0
  76. classiq/qmod/native/expression_to_qmod.py +8 -4
  77. classiq/qmod/native/pretty_printer.py +11 -18
  78. classiq/qmod/pretty_print/__init__.py +9 -0
  79. classiq/qmod/pretty_print/expression_to_python.py +221 -0
  80. classiq/qmod/pretty_print/pretty_printer.py +421 -0
  81. classiq/qmod/qmod_constant.py +7 -7
  82. classiq/qmod/qmod_parameter.py +57 -33
  83. classiq/qmod/qmod_struct.py +2 -2
  84. classiq/qmod/qmod_variable.py +40 -29
  85. classiq/qmod/quantum_callable.py +8 -4
  86. classiq/qmod/quantum_expandable.py +22 -15
  87. classiq/qmod/quantum_function.py +15 -4
  88. classiq/qmod/symbolic.py +73 -68
  89. classiq/qmod/symbolic_expr.py +1 -1
  90. classiq/qmod/symbolic_type.py +1 -4
  91. classiq/qmod/utilities.py +29 -0
  92. classiq/synthesis.py +15 -16
  93. {classiq-0.39.0.dist-info → classiq-0.41.0.dist-info}/METADATA +5 -4
  94. {classiq-0.39.0.dist-info → classiq-0.41.0.dist-info}/RECORD +95 -94
  95. classiq/interface/executor/error_mitigation.py +0 -6
  96. classiq/interface/generator/functions/builtins/core_library/chemistry_functions.py +0 -0
  97. classiq/interface/model/common_model_types.py +0 -23
  98. classiq/interface/model/quantum_expressions/control_state.py +0 -38
  99. classiq/interface/model/quantum_if_operation.py +0 -94
  100. {classiq-0.39.0.dist-info → classiq-0.41.0.dist-info}/WHEEL +0 -0
classiq/__init__.py CHANGED
@@ -9,7 +9,8 @@ from classiq.interface.generator.arith.register_user_input import (
9
9
  RegisterUserInput,
10
10
  )
11
11
  from classiq.interface.generator.control_state import ControlState
12
- from classiq.interface.generator.expressions.enums.pauli import Pauli
12
+ from classiq.interface.generator.expressions.enums import * # noqa: F403
13
+ from classiq.interface.generator.expressions.enums import __all__ as _enums_all
13
14
  from classiq.interface.generator.functions import * # noqa: F403
14
15
  from classiq.interface.generator.functions import __all__ as _ifunc_all
15
16
  from classiq.interface.generator.model import * # noqa: F403
@@ -33,7 +34,9 @@ from classiq.applications.chemistry import (
33
34
  molecule_problem_to_qmod,
34
35
  )
35
36
  from classiq.applications.combinatorial_optimization import (
37
+ compute_qaoa_initial_point,
36
38
  construct_combinatorial_optimization_model,
39
+ pyo_model_to_hamiltonian,
37
40
  )
38
41
  from classiq.applications.finance import construct_finance_model
39
42
  from classiq.applications.grover import construct_grover_model
@@ -94,13 +97,13 @@ __all__ = (
94
97
  "set_execution_preferences",
95
98
  "set_quantum_program_execution_preferences",
96
99
  "show",
97
- "Pauli",
98
100
  ]
99
101
  + _md_all
100
102
  + _ifunc_all
101
103
  + _sub_modules
102
104
  + _application_constructors_all
103
105
  + _qmod_all
106
+ + _enums_all
104
107
  )
105
108
 
106
109
 
@@ -12,7 +12,7 @@ from classiq.interface.execution.jobs import (
12
12
  ExecutionJobDetailsV1,
13
13
  ExecutionJobsQueryResultsV1,
14
14
  )
15
- from classiq.interface.executor import execution_request, result as execute_result
15
+ from classiq.interface.executor import execution_request
16
16
  from classiq.interface.generator import quantum_program as generator_result
17
17
  from classiq.interface.hardware import HardwareInformation
18
18
  from classiq.interface.jobs import (
@@ -22,7 +22,7 @@ from classiq.interface.jobs import (
22
22
  JobID,
23
23
  JSONObject,
24
24
  )
25
- from classiq.interface.model.common_model_types import ModelInput
25
+ from classiq.interface.model.model import Model
26
26
  from classiq.interface.server import routes
27
27
 
28
28
  from classiq._internals.client import client
@@ -101,7 +101,7 @@ class ApiWrapper:
101
101
 
102
102
  @classmethod
103
103
  async def call_generation_task(
104
- cls, model: ModelInput
104
+ cls, model: Model
105
105
  ) -> generator_result.QuantumProgram:
106
106
  poller = JobPoller(base_url=routes.TASKS_GENERATE_FULL_PATH)
107
107
  result = await poller.run_pydantic(model, timeout_sec=None)
@@ -192,24 +192,6 @@ class ApiWrapper:
192
192
  )
193
193
  return ExecutionJobsQueryResultsV1.parse_obj(data)
194
194
 
195
- @classmethod
196
- async def call_execute_estimate(
197
- cls, request: execution_request.ExecutionRequest
198
- ) -> execute_result.EstimationResults:
199
- poller = JobPoller(base_url=routes.EXECUTE_ESTIMATE_FULL_PATH)
200
- result = await poller.run_pydantic(request, timeout_sec=None)
201
- return _parse_job_response(result, execute_result.EstimationResults)
202
-
203
- @classmethod
204
- async def call_execute_quantum_program(
205
- cls, request: execution_request.ExecutionRequest
206
- ) -> execute_result.MultipleExecutionDetails:
207
- poller = JobPoller(
208
- base_url=routes.EXECUTE_QUANTUM_PROGRAM_FULL_PATH,
209
- )
210
- result = await poller.run_pydantic(request, timeout_sec=None)
211
- return _parse_job_response(result, execute_result.MultipleExecutionDetails)
212
-
213
195
  @classmethod
214
196
  async def call_analysis_task(
215
197
  cls, params: analysis_params.AnalysisParams
@@ -20,12 +20,14 @@ from classiq.interface.generator.expressions.expression import Expression
20
20
  from classiq.interface.generator.function_params import IOName
21
21
  from classiq.interface.generator.functions.classical_type import (
22
22
  ClassicalArray,
23
- ClassicalType,
24
23
  Real,
25
24
  )
26
25
  from classiq.interface.generator.functions.port_declaration import (
27
26
  PortDeclarationDirection,
28
27
  )
28
+ from classiq.interface.model.classical_parameter_declaration import (
29
+ ClassicalParameterDeclaration,
30
+ )
29
31
  from classiq.interface.model.handle_binding import HandleBinding
30
32
  from classiq.interface.model.model import Model, SerializedModel
31
33
  from classiq.interface.model.native_function_definition import NativeFunctionDefinition
@@ -65,137 +67,120 @@ _MOLECULE_PROBLEM_RESULT = "molecule_result"
65
67
  _HAE_GATE_MAPPING: Dict[str, QuantumFunctionCall] = {
66
68
  "h": QuantumFunctionCall(
67
69
  function="H",
68
- inouts={"target": HandleBinding(name="q")},
70
+ positional_args=[HandleBinding(name="q")],
69
71
  ),
70
72
  "x": QuantumFunctionCall(
71
73
  function="X",
72
- inouts={"target": HandleBinding(name="q")},
74
+ positional_args=[HandleBinding(name="q")],
73
75
  ),
74
76
  "y": QuantumFunctionCall(
75
77
  function="Y",
76
- inouts={"target": HandleBinding(name="q")},
78
+ positional_args=[HandleBinding(name="q")],
77
79
  ),
78
80
  "z": QuantumFunctionCall(
79
81
  function="Z",
80
- inouts={"target": HandleBinding(name="q")},
82
+ positional_args=[HandleBinding(name="q")],
81
83
  ),
82
84
  "i": QuantumFunctionCall(
83
85
  function="I",
84
- inouts={"target": HandleBinding(name="q")},
86
+ positional_args=[HandleBinding(name="q")],
85
87
  ),
86
88
  "s": QuantumFunctionCall(
87
89
  function="S",
88
- inouts={"target": HandleBinding(name="q")},
90
+ positional_args=[HandleBinding(name="q")],
89
91
  ),
90
92
  "t": QuantumFunctionCall(
91
93
  function="T",
92
- inouts={"target": HandleBinding(name="q")},
94
+ positional_args=[HandleBinding(name="q")],
93
95
  ),
94
96
  "sdg": QuantumFunctionCall(
95
97
  function="SDG",
96
- inouts={"target": HandleBinding(name="q")},
98
+ positional_args=[HandleBinding(name="q")],
97
99
  ),
98
100
  "tdg": QuantumFunctionCall(
99
101
  function="TDG",
100
- inouts={"target": HandleBinding(name="q")},
102
+ positional_args=[HandleBinding(name="q")],
101
103
  ),
102
104
  "p": QuantumFunctionCall(
103
105
  function="PHASE",
104
- inouts={"target": HandleBinding(name="q")},
106
+ positional_args=[HandleBinding(name="q")],
105
107
  ),
106
108
  "rx": QuantumFunctionCall(
107
109
  function="RX",
108
- params={"theta": Expression(expr="angle")},
109
- inouts={"target": HandleBinding(name="q")},
110
+ positional_args=[Expression(expr="angle"), HandleBinding(name="q")],
110
111
  ),
111
112
  "ry": QuantumFunctionCall(
112
113
  function="RY",
113
- params={"theta": Expression(expr="angle")},
114
- inouts={"target": HandleBinding(name="q")},
114
+ positional_args=[Expression(expr="angle"), HandleBinding(name="q")],
115
115
  ),
116
116
  "rz": QuantumFunctionCall(
117
117
  function="RZ",
118
- params={"theta": Expression(expr="angle")},
119
- inouts={"target": HandleBinding(name="q")},
118
+ positional_args=[Expression(expr="angle"), HandleBinding(name="q")],
120
119
  ),
121
120
  "rxx": QuantumFunctionCall(
122
121
  function="RXX",
123
- params={"theta": Expression(expr="angle")},
124
- inouts={"target": HandleBinding(name="q")},
122
+ positional_args=[Expression(expr="angle"), HandleBinding(name="q")],
125
123
  ),
126
124
  "ryy": QuantumFunctionCall(
127
125
  function="RYY",
128
- params={"theta": Expression(expr="angle")},
129
- inouts={"target": HandleBinding(name="q")},
126
+ positional_args=[Expression(expr="angle"), HandleBinding(name="q")],
130
127
  ),
131
128
  "rzz": QuantumFunctionCall(
132
129
  function="RZZ",
133
- params={"theta": Expression(expr="angle")},
134
- inouts={"target": HandleBinding(name="q")},
130
+ positional_args=[Expression(expr="angle"), HandleBinding(name="q")],
135
131
  ),
136
132
  "ch": QuantumFunctionCall(
137
133
  function="CH",
138
- inouts={
139
- "target": HandleBinding(name="q1"),
140
- "control": HandleBinding(name="q2"),
141
- },
134
+ positional_args=[HandleBinding(name="q1"), HandleBinding(name="q2")],
142
135
  ),
143
136
  "cx": QuantumFunctionCall(
144
137
  function="CX",
145
- inouts={
146
- "target": HandleBinding(name="q1"),
147
- "control": HandleBinding(name="q2"),
148
- },
138
+ positional_args=[HandleBinding(name="q1"), HandleBinding(name="q2")],
149
139
  ),
150
140
  "cy": QuantumFunctionCall(
151
141
  function="CY",
152
- inouts={
153
- "target": HandleBinding(name="q1"),
154
- "control": HandleBinding(name="q2"),
155
- },
142
+ positional_args=[HandleBinding(name="q1"), HandleBinding(name="q2")],
156
143
  ),
157
144
  "cz": QuantumFunctionCall(
158
145
  function="CZ",
159
- inouts={
160
- "target": HandleBinding(name="q1"),
161
- "control": HandleBinding(name="q2"),
162
- },
146
+ positional_args=[HandleBinding(name="q1"), HandleBinding(name="q2")],
163
147
  ),
164
148
  "crx": QuantumFunctionCall(
165
149
  function="CRX",
166
150
  params={"theta": Expression(expr="angle")},
167
- inouts={
168
- "target": HandleBinding(name="q1"),
169
- "control": HandleBinding(name="q2"),
170
- },
151
+ positional_args=[
152
+ Expression(expr="angle"),
153
+ HandleBinding(name="q1"),
154
+ HandleBinding(name="q2"),
155
+ ],
171
156
  ),
172
157
  "cry": QuantumFunctionCall(
173
158
  function="CRY",
174
- params={"theta": Expression(expr="angle")},
175
- inouts={
176
- "target": HandleBinding(name="q1"),
177
- "control": HandleBinding(name="q2"),
178
- },
159
+ positional_args=[
160
+ Expression(expr="angle"),
161
+ HandleBinding(name="q1"),
162
+ HandleBinding(name="q2"),
163
+ ],
179
164
  ),
180
165
  "crz": QuantumFunctionCall(
181
166
  function="CRZ",
182
- params={"theta": Expression(expr="angle")},
183
- inouts={
184
- "target": HandleBinding(name="q1"),
185
- "control": HandleBinding(name="q2"),
186
- },
167
+ positional_args=[
168
+ Expression(expr="angle"),
169
+ HandleBinding(name="q1"),
170
+ HandleBinding(name="q2"),
171
+ ],
187
172
  ),
188
173
  "cp": QuantumFunctionCall(
189
174
  function="CPHASE",
190
- params={"theta": Expression(expr="angle")},
191
- inouts={
192
- "target": HandleBinding(name="q1"),
193
- "control": HandleBinding(name="q2"),
194
- },
175
+ positional_args=[
176
+ Expression(expr="angle"),
177
+ HandleBinding(name="q1"),
178
+ HandleBinding(name="q2"),
179
+ ],
195
180
  ),
196
181
  "swap": QuantumFunctionCall(
197
182
  function="SWAP",
198
- inouts={"qbit0": HandleBinding(name="q1"), "qbit1": HandleBinding(name="q2")},
183
+ positional_args=[HandleBinding(name="q1"), HandleBinding(name="q2")],
199
184
  ),
200
185
  }
201
186
 
@@ -297,18 +282,18 @@ def _get_chemistry_function(
297
282
  chemistry_problem: CHEMISTRY_PROBLEMS_TYPE,
298
283
  chemistry_function_name: str,
299
284
  inouts: Mapping[IOName, HandleBinding],
300
- ansatz_parameters_expressions: Optional[Dict[str, Expression]] = None,
285
+ ansatz_parameters_expressions: Optional[List[Expression]] = None,
301
286
  ) -> QuantumFunctionCall:
302
287
  problem_prefix = _CHEMISTRY_PROBLEM_PREFIX_MAPPING[type(chemistry_problem)]
303
288
  return QuantumFunctionCall(
304
289
  function=f"{problem_prefix}_{chemistry_function_name}",
305
- params={
306
- f"{problem_prefix}_problem": Expression(
290
+ positional_args=[
291
+ Expression(
307
292
  expr=_convert_library_problem_to_qmod_problem(chemistry_problem)
308
293
  ),
309
- **(ansatz_parameters_expressions or dict()),
310
- },
311
- inouts=inouts,
294
+ *(ansatz_parameters_expressions or []),
295
+ *inouts.values(),
296
+ ],
312
297
  )
313
298
 
314
299
 
@@ -325,28 +310,26 @@ def _get_hartree_fock(
325
310
  def _get_hea_function(hea_parameters: HEAParameters) -> QuantumFunctionCall:
326
311
  return QuantumFunctionCall(
327
312
  function="full_hea",
328
- params={
329
- "num_qubits": Expression(expr=f"{hea_parameters.num_qubits}"),
330
- "is_parametrized": Expression(
313
+ positional_args=[
314
+ Expression(expr=f"{hea_parameters.num_qubits}"),
315
+ Expression(
331
316
  expr=f"{[int(_is_parametric_gate(_HAE_GATE_MAPPING[gate])) for gate in hea_parameters.one_qubit_gates+hea_parameters.two_qubit_gates]}"
332
317
  ),
333
- "angle_params": Expression(expr="t"),
334
- "connectivity_map": Expression(
318
+ Expression(expr="t"),
319
+ Expression(
335
320
  expr=f"{[list(connectivity_pair) for connectivity_pair in hea_parameters.connectivity_map]}"
336
321
  ),
337
- "reps": Expression(expr=f"{hea_parameters.reps}"),
338
- },
339
- operands={
340
- "operands_1qubit": [
322
+ Expression(expr=f"{hea_parameters.reps}"),
323
+ [
341
324
  QuantumLambdaFunction(body=[_HAE_GATE_MAPPING[gate]])
342
325
  for gate in hea_parameters.one_qubit_gates
343
326
  ],
344
- "operands_2qubit": [
327
+ [
345
328
  QuantumLambdaFunction(body=[_HAE_GATE_MAPPING[gate]])
346
329
  for gate in hea_parameters.two_qubit_gates
347
330
  ],
348
- },
349
- inouts={"x": HandleBinding(name="qbv")},
331
+ HandleBinding(name="qbv"),
332
+ ],
350
333
  )
351
334
 
352
335
 
@@ -360,10 +343,10 @@ def _get_ansatz(
360
343
  chemistry_problem,
361
344
  _ANSATZ_PARAMETERS_FUNCTION_NAME_MAPPING[type(ansatz_parameters)],
362
345
  {"qbv": HandleBinding(name="qbv")},
363
- {
364
- param_name: Expression(expr=str(param_value))
346
+ [
347
+ Expression(expr=str(param_value))
365
348
  for param_name, param_value in ansatz_parameters.__dict__.items()
366
- },
349
+ ],
367
350
  )
368
351
 
369
352
 
@@ -391,7 +374,9 @@ save({{{_MOLECULE_PROBLEM_RESULT!r}: {_MOLECULE_PROBLEM_RESULT}}})
391
374
 
392
375
 
393
376
  def _is_parametric_gate(call: QuantumFunctionCall) -> bool:
394
- return len(call.params) > 0
377
+ return len(call.params) > 0 or any(
378
+ isinstance(arg, Expression) for arg in call.positional_args
379
+ )
395
380
 
396
381
 
397
382
  def _get_execution_result_post_processing_statements(
@@ -420,14 +405,18 @@ def _get_hea_port_size(hea_parameters: HEAParameters) -> int:
420
405
 
421
406
  def _get_chemistry_quantum_main_params(
422
407
  ansatz_parameters: AnsatzParameters,
423
- ) -> Dict[str, ClassicalType]:
408
+ ) -> List[ClassicalParameterDeclaration]:
424
409
  if not isinstance(ansatz_parameters, HEAParameters):
425
- return dict()
426
- return {
427
- "t": ClassicalArray(
428
- element_type=Real(), size=_get_hea_port_size(ansatz_parameters)
429
- )
430
- }
410
+ return []
411
+ return [
412
+ ClassicalParameterDeclaration(
413
+ name="t",
414
+ classical_type=ClassicalArray(
415
+ element_type=Real(),
416
+ size=_get_hea_port_size(ansatz_parameters),
417
+ ),
418
+ ),
419
+ ]
431
420
 
432
421
 
433
422
  def _get_problem_to_hamiltonian_name(chemistry_problem: CHEMISTRY_PROBLEMS_TYPE) -> str:
@@ -446,7 +435,7 @@ def _get_chemistry_quantum_main(
446
435
  function="allocate",
447
436
  positional_args=[
448
437
  Expression(
449
- expr=f"len(get_field({_get_problem_to_hamiltonian_name(chemistry_problem)}({_convert_library_problem_to_qmod_problem(chemistry_problem)})[0], 'pauli'))"
438
+ expr=f"get_field(get_field({_get_problem_to_hamiltonian_name(chemistry_problem)}({_convert_library_problem_to_qmod_problem(chemistry_problem)})[0], 'pauli'), 'len')"
450
439
  ),
451
440
  HandleBinding(name="qbv"),
452
441
  ],
@@ -459,14 +448,10 @@ def _get_chemistry_quantum_main(
459
448
 
460
449
  return NativeFunctionDefinition(
461
450
  name="main",
462
- param_decls=_get_chemistry_quantum_main_params(ansatz_parameters),
463
- port_declarations=(
464
- {
465
- "qbv": PortDeclaration(
466
- name="qbv", direction=PortDeclarationDirection.Output
467
- )
468
- }
469
- ),
451
+ positional_arg_declarations=_get_chemistry_quantum_main_params(
452
+ ansatz_parameters
453
+ )
454
+ + [PortDeclaration(name="qbv", direction=PortDeclarationDirection.Output)],
470
455
  body=body,
471
456
  )
472
457
 
@@ -476,14 +461,15 @@ def _get_chemistry_classical_code(
476
461
  execution_parameters: ChemistryExecutionParameters,
477
462
  ) -> str:
478
463
  qmod_problem = _convert_library_problem_to_qmod_problem(chemistry_problem)
479
- return f"""
464
+ return (
465
+ f"""
480
466
  {_EXECUTION_RESULT} = vqe(
481
467
  hamiltonian={_get_problem_to_hamiltonian_name(chemistry_problem)}({qmod_problem}), {_get_chemistry_vqe_additional_params(execution_parameters)}
482
468
  )
483
469
  save({{{_EXECUTION_RESULT!r}: {_EXECUTION_RESULT}}})
484
- """ + _get_execution_result_post_processing_statements(
485
- chemistry_problem
486
- )
470
+ """
471
+ + _get_execution_result_post_processing_statements(chemistry_problem)
472
+ ).strip()
487
473
 
488
474
 
489
475
  def construct_chemistry_model(
@@ -1,5 +1,5 @@
1
1
  import itertools
2
- from typing import List, Union, cast
2
+ from typing import List, Union
3
3
 
4
4
  import numpy as np
5
5
  import pyomo.environ as pyo
@@ -16,23 +16,21 @@ from classiq.applications.combinatorial_helpers.pauli_helpers.pauli_sparsing imp
16
16
  SparsePauliOp,
17
17
  )
18
18
  from classiq.applications.combinatorial_helpers.pauli_helpers.pauli_utils import (
19
- PauliTerm,
20
- get_pauli_operator,
21
19
  pauli_operator_to_hamiltonian,
22
- pauli_string_to_int,
23
20
  )
24
21
  from classiq.applications.combinatorial_helpers.pyomo_utils import (
25
22
  convert_pyomo_to_global_presentation,
26
23
  )
24
+ from classiq.qmod.builtins import PauliTerm
27
25
 
28
26
 
29
27
  def compute_qaoa_initial_point(
30
- hamiltonian: List[QmodPyStruct],
28
+ hamiltonian: List[PauliTerm],
31
29
  repetitions: int,
32
30
  ) -> List[float]:
33
- coeffs_ising = [pauli_term["coefficient"] for pauli_term in hamiltonian[1:]]
31
+ coeffs_ising = [pauli_term.coefficient for pauli_term in hamiltonian[1:]]
34
32
  # the first coeff is the II...I term
35
- coeffs_abs = np.abs(coeffs_ising)
33
+ coeffs_abs = np.abs(coeffs_ising) # type: ignore[arg-type]
36
34
  coeffs_largest = np.sort(coeffs_abs)[len(coeffs_ising) // 2 :]
37
35
  operator_norm = np.mean(coeffs_largest)
38
36
  time_step = 1 / (2 * operator_norm) # adapted such that for MAXCUT time_step = 1
@@ -42,32 +40,15 @@ def compute_qaoa_initial_point(
42
40
  return list(itertools.chain(*zip(gamma_params, beta_params)))
43
41
 
44
42
 
45
- def _internal_pyo_model_to_hamiltonian(
43
+ def pyo_model_to_hamiltonian(
46
44
  pyo_model: pyo.ConcreteModel, penalty_energy: float
47
- ) -> List[QmodPyStruct]:
45
+ ) -> List[PauliTerm]:
48
46
  pauli_list = OptimizationModel(
49
47
  pyo_model, penalty_energy=penalty_energy, qsolver=QSolver.QAOAPenalty
50
48
  ).ising.pauli_list
51
49
  return pauli_operator_to_hamiltonian(pauli_list)
52
50
 
53
51
 
54
- def pyo_model_to_hamiltonian(
55
- pyo_model: pyo.ConcreteModel, penalty_energy: float
56
- ) -> List[PauliTerm]:
57
- hamiltonian = _internal_pyo_model_to_hamiltonian(pyo_model, penalty_energy)
58
- pauli_operator = get_pauli_operator(hamiltonian).pauli_list
59
- pauli_terms = []
60
- for item in pauli_operator:
61
- term = PauliTerm()
62
- term.pauli, term.coefficient = (
63
- pauli_string_to_int(item[0]),
64
- cast(complex, item[1]).real,
65
- )
66
- pauli_terms.append(term)
67
-
68
- return pauli_terms
69
-
70
-
71
52
  def _str_to_list_int(str_ints: str) -> List[int]:
72
53
  return list(map(int, list(str_ints)))
73
54
 
@@ -45,22 +45,23 @@ class OptimizationModel:
45
45
  encoding_type: Optional[EncodingType] = None,
46
46
  ) -> None:
47
47
  assert model.nobjectives() == 1, "model must have a single objective"
48
- self._model_original = copy.deepcopy(model)
49
- self._assigned_model = remove_fixed_variables(model)
48
+ model_copy = copy.deepcopy(model)
49
+ self._model_original = model
50
+ self._assigned_model = remove_fixed_variables(model_copy)
50
51
  self.qsolver = qsolver
51
52
  self._encoding_type = encoding_type
52
53
 
53
- self.is_encoded = encoding_utils.is_model_encodable(model)
54
+ self.is_encoded = encoding_utils.is_model_encodable(model_copy)
54
55
  if self.is_encoded:
55
56
  if self._encoding_type is None:
56
57
  self._encoding_type = EncodingType.BINARY
57
58
  self._model_encoder = encoding.ModelEncoder(
58
- model, qsolver, self._encoding_type
59
+ model_copy, qsolver, self._encoding_type
59
60
  )
60
61
  self._model = self._model_encoder.encoded_model
61
62
  self._vars_encoding_mapping = self._model_encoder.vars_encoding_mapping
62
63
  else:
63
- self._model = model
64
+ self._model = model_copy
64
65
  # TODO How to handle encoding_type == None
65
66
  self._vars_encoding_mapping = EncodingMapping(self._encoding_type) # type: ignore[arg-type]
66
67
 
@@ -70,7 +71,7 @@ class OptimizationModel:
70
71
  self.vars_not_encoded, self._vars_encoding_mapping
71
72
  )
72
73
 
73
- self.is_maximization = sense.is_maximization(model)
74
+ self.is_maximization = sense.is_maximization(model_copy)
74
75
  self.objective = next(self._model.component_objects(pyo.Objective))
75
76
 
76
77
  self.penalty_energy = penalty_energy
@@ -1,75 +1,53 @@
1
- from typing import List, cast
1
+ from typing import List
2
2
 
3
- from classiq.interface.chemistry.operator import PauliOperator
4
3
  from classiq.interface.generator.expressions.enums.pauli import Pauli
5
4
  from classiq.interface.generator.functions.qmod_python_interface import QmodPyStruct
6
5
  from classiq.interface.helpers.custom_pydantic_types import PydanticPauliList
7
6
 
8
- from classiq.exceptions import (
9
- ClassiqExecutorInvalidHamiltonianError,
10
- ClassiqNonNumericCoefficientInPauliError,
11
- ClassiqValueError,
12
- )
7
+ from classiq.exceptions import ClassiqNonNumericCoefficientInPauliError
8
+ from classiq.qmod.builtins import PauliTerm
13
9
 
14
10
 
15
- class PauliTerm:
16
- pauli: List[int]
17
- coefficient: float
18
-
19
-
20
- def pauli_string_to_int(pauli_str: str) -> List[int]:
21
- pauli_map = {"I": 0, "X": 1, "Y": 2, "Z": 3}
22
- return [pauli_map[char] for char in pauli_str]
23
-
24
-
25
- def _pauli_str_to_enums(pauli_str: str) -> str:
26
- return ", ".join(f"Pauli.{pauli_term}" for pauli_term in pauli_str)
27
-
28
-
29
- def pauli_integers_to_str(paulis: List[Pauli]) -> str:
30
- return "".join([Pauli(pauli).name for pauli in paulis])
31
-
32
-
33
- def pauli_operator_to_hamiltonian(pauli_list: PydanticPauliList) -> List[QmodPyStruct]:
34
- pauli_struct_list: List[QmodPyStruct] = []
11
+ def pauli_operator_to_hamiltonian(pauli_list: PydanticPauliList) -> List[PauliTerm]:
12
+ pauli_terms: List[PauliTerm] = []
35
13
  for pauli_term in pauli_list:
36
14
  if not isinstance(pauli_term[1], complex) or pauli_term[1].imag != 0:
37
15
  raise ClassiqNonNumericCoefficientInPauliError(
38
16
  "Coefficient is not a number."
39
17
  )
40
-
41
- pauli_struct_list.append(
42
- {
43
- "pauli": [Pauli[p] for p in pauli_term[0]],
44
- "coefficient": pauli_term[1].real,
45
- }
18
+ term = PauliTerm(
19
+ [Pauli[p] for p in pauli_term[0]], # type: ignore[arg-type]
20
+ pauli_term[1].real, # type: ignore[arg-type]
46
21
  )
47
- return pauli_struct_list
22
+ pauli_terms.append(term)
23
+
24
+ return pauli_terms
48
25
 
49
26
 
50
- def get_pauli_operator(pauli_operator: List[QmodPyStruct]) -> PauliOperator:
51
- pauli_list = [
52
- (
53
- pauli_integers_to_str(elem["pauli"]),
54
- elem["coefficient"],
27
+ def pauli_enum_to_str(pauli: Pauli) -> str:
28
+ return {
29
+ Pauli.I: "Pauli.I",
30
+ Pauli.X: "Pauli.X",
31
+ Pauli.Y: "Pauli.Y",
32
+ Pauli.Z: "Pauli.Z",
33
+ }.get(pauli, "")
34
+
35
+
36
+ def _pauli_terms_to_qmod(hamiltonian: List[PauliTerm]) -> str:
37
+ qmod_strings = []
38
+ for term in hamiltonian:
39
+ pauli_str = ", ".join([pauli_enum_to_str(p) for p in term.pauli]) # type: ignore[attr-defined]
40
+ qmod_strings.append(
41
+ f"struct_literal(PauliTerm, pauli=[{pauli_str}], coefficient={term.coefficient})"
55
42
  )
56
- for elem in pauli_operator
57
- ]
58
43
 
59
- try:
60
- pauli = PauliOperator(pauli_list=pauli_list)
61
- except ValueError:
62
- raise ClassiqExecutorInvalidHamiltonianError() from None
44
+ return ", ".join(qmod_strings)
63
45
 
64
- return pauli
65
46
 
47
+ def _pauli_dict_to_str(hamiltonian: List[QmodPyStruct]) -> str:
48
+ res = []
49
+ for struct in hamiltonian:
50
+ pauli_str = ", ".join([pauli_enum_to_str(p) for p in struct["pauli"]])
51
+ res.append(f'"pauli": [{pauli_str}], "coefficient": {struct["coefficient"]}')
66
52
 
67
- def _pauli_operator_to_qmod(hamiltonian: PauliOperator) -> str:
68
- if not all(isinstance(summand[1], complex) for summand in hamiltonian.pauli_list):
69
- raise ClassiqValueError(
70
- "Supporting only Hamiltonian with numeric coefficients."
71
- )
72
- return ", ".join(
73
- f"struct_literal(PauliTerm, pauli=[{_pauli_str_to_enums(pauli)}], coefficient={cast(complex, coeff).real})"
74
- for pauli, coeff in hamiltonian.pauli_list
75
- )
53
+ return f"{{{', '.join(res)}}}"