classiq 0.36.0__py3-none-any.whl → 0.37.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 (91) hide show
  1. classiq/__init__.py +1 -0
  2. classiq/_internals/api_wrapper.py +24 -6
  3. classiq/_internals/authentication/device.py +6 -3
  4. classiq/_internals/authentication/token_manager.py +21 -5
  5. classiq/_internals/client.py +7 -2
  6. classiq/_internals/config.py +12 -0
  7. classiq/_internals/host_checker.py +1 -1
  8. classiq/_internals/jobs.py +3 -1
  9. classiq/_internals/type_validation.py +3 -6
  10. classiq/analyzer/analyzer.py +1 -0
  11. classiq/analyzer/rb.py +3 -5
  12. classiq/applications_model_constructors/chemistry_model_constructor.py +42 -67
  13. classiq/applications_model_constructors/grover_model_constructor.py +27 -18
  14. classiq/exceptions.py +5 -0
  15. classiq/execution/jobs.py +13 -4
  16. classiq/executor.py +3 -2
  17. classiq/interface/_version.py +1 -1
  18. classiq/interface/analyzer/analysis_params.py +0 -6
  19. classiq/interface/analyzer/result.py +0 -4
  20. classiq/interface/backend/backend_preferences.py +2 -2
  21. classiq/interface/backend/quantum_backend_providers.py +1 -1
  22. classiq/interface/execution/resource_estimator.py +7 -0
  23. classiq/interface/execution/result.py +5 -0
  24. classiq/interface/executor/register_initialization.py +3 -1
  25. classiq/interface/executor/vqe_result.py +1 -0
  26. classiq/interface/generator/ansatz_library.py +3 -3
  27. classiq/interface/generator/arith/argument_utils.py +4 -4
  28. classiq/interface/generator/arith/arithmetic.py +4 -2
  29. classiq/interface/generator/arith/arithmetic_arg_type_validator.py +11 -5
  30. classiq/interface/generator/arith/arithmetic_expression_parser.py +8 -7
  31. classiq/interface/generator/arith/arithmetic_operations.py +7 -0
  32. classiq/interface/generator/arith/arithmetic_param_getters.py +97 -16
  33. classiq/interface/generator/arith/arithmetic_result_builder.py +13 -3
  34. classiq/interface/generator/arith/binary_ops.py +8 -10
  35. classiq/interface/generator/arith/extremum_operations.py +2 -2
  36. classiq/interface/generator/arith/number_utils.py +20 -23
  37. classiq/interface/generator/arith/register_user_input.py +3 -1
  38. classiq/interface/generator/arith/unary_ops.py +9 -13
  39. classiq/interface/generator/expressions/atomic_expression_functions.py +2 -0
  40. classiq/interface/generator/expressions/expression.py +7 -2
  41. classiq/interface/generator/expressions/qmod_qnum_proxy.py +22 -0
  42. classiq/interface/generator/expressions/qmod_sized_proxy.py +2 -12
  43. classiq/interface/generator/functions/core_lib_declarations/quantum_functions/atomic_quantum_functions.py +63 -3
  44. classiq/interface/generator/functions/core_lib_declarations/quantum_functions/std_lib_functions.py +143 -17
  45. classiq/interface/generator/functions/core_lib_declarations/quantum_operators.py +41 -16
  46. classiq/interface/generator/functions/native_function_definition.py +3 -3
  47. classiq/interface/generator/model/constraints.py +3 -3
  48. classiq/interface/generator/model/preferences/preferences.py +13 -9
  49. classiq/interface/generator/noise_properties.py +5 -5
  50. classiq/interface/generator/qpe.py +5 -5
  51. classiq/interface/generator/quantum_function_call.py +5 -3
  52. classiq/interface/generator/randomized_benchmarking.py +5 -3
  53. classiq/interface/generator/visitor.py +1 -2
  54. classiq/interface/hardware.py +1 -1
  55. classiq/interface/helpers/custom_pydantic_types.py +6 -0
  56. classiq/interface/model/{modular_addition_operation.py → inplace_binary_operation.py} +16 -2
  57. classiq/interface/model/native_function_definition.py +2 -24
  58. classiq/interface/model/operator_synthesis_data.py +6 -0
  59. classiq/interface/model/quantum_expressions/amplitude_loading_operation.py +8 -4
  60. classiq/interface/model/quantum_expressions/arithmetic_operation.py +9 -5
  61. classiq/interface/model/quantum_expressions/control_state.py +38 -0
  62. classiq/interface/model/quantum_expressions/quantum_expression.py +21 -11
  63. classiq/interface/model/quantum_function_call.py +81 -6
  64. classiq/interface/model/quantum_function_declaration.py +3 -3
  65. classiq/interface/model/quantum_if_operation.py +95 -0
  66. classiq/interface/model/resolvers/function_call_resolver.py +1 -1
  67. classiq/interface/model/validations/handles_validator.py +42 -15
  68. classiq/interface/server/routes.py +10 -6
  69. classiq/model/function_handler.pyi +86 -86
  70. classiq/model/model.py +1 -0
  71. classiq/qmod/__init__.py +6 -1
  72. classiq/qmod/builtins/__init__.py +13 -1
  73. classiq/qmod/builtins/classical_execution_primitives.py +109 -0
  74. classiq/qmod/builtins/classical_functions.py +68 -0
  75. classiq/qmod/builtins/functions.py +88 -18
  76. classiq/qmod/builtins/operations.py +60 -35
  77. classiq/qmod/classical_function.py +40 -0
  78. classiq/qmod/declaration_inferrer.py +5 -2
  79. classiq/qmod/qmod_variable.py +17 -10
  80. classiq/qmod/quantum_callable.py +24 -3
  81. classiq/qmod/quantum_expandable.py +131 -21
  82. classiq/qmod/quantum_function.py +12 -2
  83. classiq/qmod/symbolic.py +182 -107
  84. classiq/qmod/symbolic_expr.py +11 -10
  85. classiq/qmod/symbolic_type.py +8 -0
  86. classiq/quantum_functions/decorators.py +2 -4
  87. classiq/quantum_functions/function_library.py +1 -0
  88. {classiq-0.36.0.dist-info → classiq-0.37.0.dist-info}/METADATA +1 -1
  89. {classiq-0.36.0.dist-info → classiq-0.37.0.dist-info}/RECORD +90 -82
  90. classiq/interface/model/local_variable_declaration.py +0 -7
  91. {classiq-0.36.0.dist-info → classiq-0.37.0.dist-info}/WHEEL +0 -0
@@ -57,6 +57,7 @@ def get_params(
57
57
  *,
58
58
  node_id: str,
59
59
  args: List[RegisterOrFloat],
60
+ machine_precision: int,
60
61
  output_size: Optional[int] = None,
61
62
  inplace_arg: Optional[str] = None,
62
63
  target: Optional[RegisterArithmeticInfo] = None
@@ -64,35 +65,52 @@ def get_params(
64
65
  operation = id2op(node_id)
65
66
  if target and not operation_allows_target(operation):
66
67
  raise ClassiqArithmeticError(_TARGET_ERROR_MESSAGE)
67
- validate_operation_arg_types(operation, args)
68
+ validate_operation_arg_types(operation, args, machine_precision)
68
69
  return params_getter_map[operation](
69
- *args, output_size=output_size, inplace_arg=inplace_arg, target=target
70
+ *args,
71
+ machine_precision=machine_precision,
72
+ output_size=output_size,
73
+ inplace_arg=inplace_arg,
74
+ target=target,
70
75
  )
71
76
 
72
77
 
73
78
  def or_params_getter(
74
79
  left_arg: RegisterOrInt,
75
80
  right_arg: RegisterOrInt,
81
+ machine_precision: int,
76
82
  output_size: Optional[int] = None,
77
83
  inplace_arg: Optional[str] = None,
78
84
  target: Optional[RegisterArithmeticInfo] = None,
79
85
  ) -> ArithmeticOperationParams:
80
- return BitwiseOr(left_arg=left_arg, right_arg=right_arg, output_size=output_size)
86
+ return BitwiseOr(
87
+ left_arg=left_arg,
88
+ right_arg=right_arg,
89
+ output_size=output_size,
90
+ machine_precision=machine_precision,
91
+ )
81
92
 
82
93
 
83
94
  def and_params_getter(
84
95
  left_arg: RegisterOrInt,
85
96
  right_arg: RegisterOrInt,
97
+ machine_precision: int,
86
98
  output_size: Optional[int] = None,
87
99
  inplace_arg: Optional[str] = None,
88
100
  target: Optional[RegisterArithmeticInfo] = None,
89
101
  ) -> ArithmeticOperationParams:
90
- return BitwiseAnd(left_arg=left_arg, right_arg=right_arg, output_size=output_size)
102
+ return BitwiseAnd(
103
+ left_arg=left_arg,
104
+ right_arg=right_arg,
105
+ output_size=output_size,
106
+ machine_precision=machine_precision,
107
+ )
91
108
 
92
109
 
93
110
  def xor_params_getter(
94
111
  left_arg: RegisterOrInt,
95
112
  right_arg: RegisterOrInt,
113
+ machine_precision: int,
96
114
  output_size: Optional[int] = None,
97
115
  inplace_arg: Optional[str] = None,
98
116
  target: Optional[RegisterArithmeticInfo] = None,
@@ -100,6 +118,7 @@ def xor_params_getter(
100
118
  return BitwiseXor(
101
119
  left_arg=left_arg,
102
120
  right_arg=right_arg,
121
+ machine_precision=machine_precision,
103
122
  output_size=output_size,
104
123
  inplace_arg=inplace_arg,
105
124
  )
@@ -107,12 +126,14 @@ def xor_params_getter(
107
126
 
108
127
  def invert_params_getter(
109
128
  arg: RegisterOrInt,
129
+ machine_precision: int,
110
130
  output_size: Optional[int] = None,
111
131
  inplace_arg: Optional[str] = None,
112
132
  target: Optional[RegisterArithmeticInfo] = None,
113
133
  ) -> ArithmeticOperationParams:
114
134
  return BitwiseInvert(
115
135
  arg=arg,
136
+ machine_precision=machine_precision,
116
137
  output_size=output_size,
117
138
  inplace=inplace_arg is not None,
118
139
  )
@@ -120,12 +141,14 @@ def invert_params_getter(
120
141
 
121
142
  def usub_params_getter(
122
143
  arg: RegisterOrInt,
144
+ machine_precision: int,
123
145
  output_size: Optional[int] = None,
124
146
  inplace_arg: Optional[str] = None,
125
147
  target: Optional[RegisterArithmeticInfo] = None,
126
148
  ) -> ArithmeticOperationParams:
127
149
  return Negation(
128
150
  arg=arg,
151
+ machine_precision=machine_precision,
129
152
  output_size=output_size,
130
153
  inplace=inplace_arg is not None,
131
154
  )
@@ -134,6 +157,7 @@ def usub_params_getter(
134
157
  def adder_params_getter(
135
158
  left_arg: RegisterOrFloat,
136
159
  right_arg: RegisterOrFloat,
160
+ machine_precision: int,
137
161
  output_size: Optional[int] = None,
138
162
  inplace_arg: Optional[str] = None,
139
163
  target: Optional[RegisterArithmeticInfo] = None,
@@ -141,6 +165,7 @@ def adder_params_getter(
141
165
  return Adder(
142
166
  left_arg=left_arg,
143
167
  right_arg=right_arg,
168
+ machine_precision=machine_precision,
144
169
  inplace_arg=inplace_arg,
145
170
  output_size=output_size,
146
171
  )
@@ -149,46 +174,71 @@ def adder_params_getter(
149
174
  def multiplier_params_getter(
150
175
  left_arg: RegisterOrFloat,
151
176
  right_arg: RegisterOrFloat,
177
+ machine_precision: int,
152
178
  output_size: Optional[int] = None,
153
179
  inplace_arg: Optional[str] = None,
154
180
  target: Optional[RegisterArithmeticInfo] = None,
155
181
  ) -> ArithmeticOperationParams:
156
- return Multiplier(left_arg=left_arg, right_arg=right_arg, output_size=output_size)
182
+ return Multiplier(
183
+ left_arg=left_arg,
184
+ right_arg=right_arg,
185
+ machine_precision=machine_precision,
186
+ output_size=output_size,
187
+ )
157
188
 
158
189
 
159
190
  def power_params_getter(
160
191
  left_arg: RegisterArithmeticInfo,
161
192
  right_arg: int,
193
+ machine_precision: int,
162
194
  output_size: Optional[int] = None,
163
195
  inplace_arg: Optional[str] = None,
164
196
  target: Optional[RegisterArithmeticInfo] = None,
165
197
  ) -> ArithmeticOperationParams:
166
- return Power(left_arg=left_arg, right_arg=right_arg, output_size=output_size)
198
+ return Power(
199
+ left_arg=left_arg,
200
+ right_arg=right_arg,
201
+ machine_precision=machine_precision,
202
+ output_size=output_size,
203
+ )
167
204
 
168
205
 
169
206
  def min_params_getter(
170
207
  left_arg: RegisterOrFloat,
171
208
  right_arg: RegisterOrFloat,
209
+ machine_precision: int,
172
210
  output_size: Optional[int] = None,
173
211
  inplace_arg: Optional[str] = None,
174
212
  target: Optional[RegisterArithmeticInfo] = None,
175
213
  ) -> ArithmeticOperationParams:
176
- return Min(left_arg=left_arg, right_arg=right_arg, output_size=output_size)
214
+ return Min(
215
+ left_arg=left_arg,
216
+ right_arg=right_arg,
217
+ machine_precision=machine_precision,
218
+ output_size=output_size,
219
+ )
177
220
 
178
221
 
179
222
  def max_params_getter(
180
223
  left_arg: RegisterOrFloat,
181
224
  right_arg: RegisterOrFloat,
225
+ machine_precision: int,
182
226
  output_size: Optional[int] = None,
183
227
  inplace_arg: Optional[str] = None,
184
228
  target: Optional[RegisterArithmeticInfo] = None,
185
229
  ) -> ArithmeticOperationParams:
186
- return Max(left_arg=left_arg, right_arg=right_arg, output_size=output_size)
230
+ return Max(
231
+ left_arg=left_arg,
232
+ right_arg=right_arg,
233
+ machine_precision=machine_precision,
234
+ output_size=output_size,
235
+ )
187
236
 
188
237
 
189
238
  def sub_params_getter(
190
239
  left_arg: RegisterOrFloat,
191
240
  right_arg: RegisterOrFloat,
241
+ machine_precision: int,
192
242
  output_size: Optional[int] = None,
193
243
  inplace_arg: Optional[str] = None,
194
244
  target: Optional[RegisterArithmeticInfo] = None,
@@ -196,6 +246,7 @@ def sub_params_getter(
196
246
  return Subtractor(
197
247
  left_arg=left_arg,
198
248
  right_arg=right_arg,
249
+ machine_precision=machine_precision,
199
250
  inplace_arg=inplace_arg,
200
251
  output_size=output_size,
201
252
  )
@@ -204,84 +255,105 @@ def sub_params_getter(
204
255
  def equal_params_getter(
205
256
  left_arg: RegisterOrFloat,
206
257
  right_arg: RegisterOrFloat,
258
+ machine_precision: int,
207
259
  output_size: Optional[int] = None,
208
260
  inplace_arg: Optional[str] = None,
209
261
  target: Optional[RegisterArithmeticInfo] = None,
210
262
  ) -> ArithmeticOperationParams:
211
- return Equal(left_arg=left_arg, right_arg=right_arg)
263
+ return Equal(
264
+ left_arg=left_arg, right_arg=right_arg, machine_precision=machine_precision
265
+ )
212
266
 
213
267
 
214
268
  def not_equal_params_getter(
215
269
  left_arg: RegisterOrFloat,
216
270
  right_arg: RegisterOrFloat,
271
+ machine_precision: int,
217
272
  output_size: Optional[int] = None,
218
273
  inplace_arg: Optional[str] = None,
219
274
  target: Optional[RegisterArithmeticInfo] = None,
220
275
  ) -> ArithmeticOperationParams:
221
- return NotEqual(left_arg=left_arg, right_arg=right_arg)
276
+ return NotEqual(
277
+ left_arg=left_arg, right_arg=right_arg, machine_precision=machine_precision
278
+ )
222
279
 
223
280
 
224
281
  def greater_than_params_getter(
225
282
  left_arg: RegisterOrFloat,
226
283
  right_arg: RegisterOrFloat,
284
+ machine_precision: int,
227
285
  output_size: Optional[int] = None,
228
286
  inplace_arg: Optional[str] = None,
229
287
  target: Optional[RegisterArithmeticInfo] = None,
230
288
  ) -> ArithmeticOperationParams:
231
- return GreaterThan(left_arg=left_arg, right_arg=right_arg)
289
+ return GreaterThan(
290
+ left_arg=left_arg, right_arg=right_arg, machine_precision=machine_precision
291
+ )
232
292
 
233
293
 
234
294
  def greater_equal_params_getter(
235
295
  left_arg: RegisterOrFloat,
236
296
  right_arg: RegisterOrFloat,
297
+ machine_precision: int,
237
298
  output_size: Optional[int] = None,
238
299
  inplace_arg: Optional[str] = None,
239
300
  target: Optional[RegisterArithmeticInfo] = None,
240
301
  ) -> ArithmeticOperationParams:
241
- return GreaterEqual(left_arg=left_arg, right_arg=right_arg)
302
+ return GreaterEqual(
303
+ left_arg=left_arg, right_arg=right_arg, machine_precision=machine_precision
304
+ )
242
305
 
243
306
 
244
307
  def less_than_params_getter(
245
308
  left_arg: RegisterOrFloat,
246
309
  right_arg: RegisterOrFloat,
310
+ machine_precision: int,
247
311
  output_size: Optional[int] = None,
248
312
  inplace_arg: Optional[str] = None,
249
313
  target: Optional[RegisterArithmeticInfo] = None,
250
314
  ) -> ArithmeticOperationParams:
251
- return LessThan(left_arg=left_arg, right_arg=right_arg)
315
+ return LessThan(
316
+ left_arg=left_arg, right_arg=right_arg, machine_precision=machine_precision
317
+ )
252
318
 
253
319
 
254
320
  def less_equal_params_getter(
255
321
  left_arg: RegisterOrFloat,
256
322
  right_arg: RegisterOrFloat,
323
+ machine_precision: int,
257
324
  output_size: Optional[int] = None,
258
325
  inplace_arg: Optional[str] = None,
259
326
  target: Optional[RegisterArithmeticInfo] = None,
260
327
  ) -> ArithmeticOperationParams:
261
- return LessEqual(left_arg=left_arg, right_arg=right_arg)
328
+ return LessEqual(
329
+ left_arg=left_arg, right_arg=right_arg, machine_precision=machine_precision
330
+ )
262
331
 
263
332
 
264
333
  def logical_and_params_getter(
265
334
  *arg: List[RegisterOrFloat],
335
+ machine_precision: int,
266
336
  output_size: Optional[int] = None,
267
337
  inplace_arg: Optional[str] = None,
268
338
  target: Optional[RegisterArithmeticInfo] = None
269
339
  ) -> ArithmeticOperationParams:
270
- return LogicalAnd(args=arg, target=target)
340
+ return LogicalAnd(args=arg, target=target, machine_precision=machine_precision)
271
341
 
272
342
 
273
343
  def logical_or_params_getter(
274
344
  *arg: List[RegisterOrFloat],
345
+ machine_precision: int,
275
346
  output_size: Optional[int] = None,
276
347
  inplace_arg: Optional[str] = None,
277
348
  target: Optional[RegisterArithmeticInfo] = None
278
349
  ) -> ArithmeticOperationParams:
279
- return LogicalOr(args=arg, target=target)
350
+ return LogicalOr(args=arg, target=target, machine_precision=machine_precision)
280
351
 
281
352
 
282
353
  def lshift_params_getter(
283
354
  left_arg: RegisterArithmeticInfo,
284
355
  right_arg: int,
356
+ machine_precision: int,
285
357
  output_size: Optional[int] = None,
286
358
  inplace_arg: Optional[str] = None,
287
359
  target: Optional[RegisterArithmeticInfo] = None,
@@ -289,6 +361,7 @@ def lshift_params_getter(
289
361
  return LShift(
290
362
  left_arg=left_arg,
291
363
  right_arg=right_arg,
364
+ machine_precision=machine_precision,
292
365
  inplace_arg=inplace_arg,
293
366
  output_size=output_size,
294
367
  )
@@ -297,6 +370,7 @@ def lshift_params_getter(
297
370
  def rshift_params_getter(
298
371
  left_arg: RegisterArithmeticInfo,
299
372
  right_arg: int,
373
+ machine_precision: int,
300
374
  output_size: Optional[int] = None,
301
375
  inplace_arg: Optional[str] = None,
302
376
  target: Optional[RegisterArithmeticInfo] = None,
@@ -304,6 +378,7 @@ def rshift_params_getter(
304
378
  return RShift(
305
379
  left_arg=left_arg,
306
380
  right_arg=right_arg,
381
+ machine_precision=machine_precision,
307
382
  inplace_arg=inplace_arg,
308
383
  output_size=output_size,
309
384
  )
@@ -312,6 +387,7 @@ def rshift_params_getter(
312
387
  def clshift_params_getter(
313
388
  left_arg: RegisterArithmeticInfo,
314
389
  right_arg: int,
390
+ machine_precision: int,
315
391
  output_size: Optional[int] = None,
316
392
  inplace_arg: Optional[str] = None,
317
393
  target: Optional[RegisterArithmeticInfo] = None,
@@ -319,6 +395,7 @@ def clshift_params_getter(
319
395
  return CyclicShift(
320
396
  left_arg=left_arg,
321
397
  right_arg=-right_arg,
398
+ machine_precision=machine_precision,
322
399
  inplace_arg=inplace_arg,
323
400
  output_size=output_size,
324
401
  )
@@ -327,6 +404,7 @@ def clshift_params_getter(
327
404
  def crshift_params_getter(
328
405
  left_arg: RegisterArithmeticInfo,
329
406
  right_arg: int,
407
+ machine_precision: int,
330
408
  output_size: Optional[int] = None,
331
409
  inplace_arg: Optional[str] = None,
332
410
  target: Optional[RegisterArithmeticInfo] = None,
@@ -334,6 +412,7 @@ def crshift_params_getter(
334
412
  return CyclicShift(
335
413
  left_arg=left_arg,
336
414
  right_arg=right_arg,
415
+ machine_precision=machine_precision,
337
416
  inplace_arg=inplace_arg,
338
417
  output_size=output_size,
339
418
  )
@@ -342,6 +421,7 @@ def crshift_params_getter(
342
421
  def modulo_params_getter(
343
422
  left_arg: RegisterArithmeticInfo,
344
423
  right_arg: int,
424
+ machine_precision: int,
345
425
  output_size: Optional[int] = None,
346
426
  inplace_arg: Optional[str] = None,
347
427
  target: Optional[RegisterArithmeticInfo] = None,
@@ -349,6 +429,7 @@ def modulo_params_getter(
349
429
  return Modulo(
350
430
  left_arg=left_arg,
351
431
  right_arg=right_arg,
432
+ machine_precision=machine_precision,
352
433
  output_size=output_size,
353
434
  inplace_arg=inplace_arg,
354
435
  )
@@ -80,18 +80,28 @@ class ArithmeticResultBuilder:
80
80
  for predecessor_node in graph.predecessors(node)
81
81
  ]
82
82
  if graph.out_degree(node) == 0:
83
- return cls._get_node_result(graph, args, node)
84
- node_results[node] = cls._get_node_result(graph, args, node)
83
+ return cls._get_node_result(
84
+ graph, args, node, machine_precision=machine_precision
85
+ )
86
+ node_results[node] = cls._get_node_result(
87
+ graph, args, node, machine_precision=machine_precision
88
+ )
85
89
  raise ClassiqArithmeticError("Expression has no result")
86
90
 
87
91
  @classmethod
88
92
  def _get_node_result(
89
- cls, graph: nx.DiGraph, args: List[RegisterOrConst], node: str
93
+ cls,
94
+ graph: nx.DiGraph,
95
+ args: List[RegisterOrConst],
96
+ node: str,
97
+ *,
98
+ machine_precision: int,
90
99
  ) -> RegisterArithmeticInfo:
91
100
  return arithmetic_param_getters.get_params(
92
101
  node_id=node,
93
102
  args=args,
94
103
  output_size=graph.nodes[node].get(OUTPUT_SIZE, None),
104
+ machine_precision=machine_precision,
95
105
  ).result_register
96
106
 
97
107
  @staticmethod
@@ -253,8 +253,8 @@ class Adder(InplacableBinaryOpParams[RegisterOrConst, RegisterOrConst]):
253
253
  )
254
254
  integer_part_size = number_utils.bounds_to_integer_part_size(lb, ub)
255
255
  fraction_places = max(
256
- argument_utils.fraction_places(self.left_arg),
257
- argument_utils.fraction_places(self.right_arg),
256
+ self._compute_fraction_places(self.left_arg),
257
+ self._compute_fraction_places(self.right_arg),
258
258
  )
259
259
  size_needed = integer_part_size + fraction_places
260
260
  return RegisterArithmeticInfo(
@@ -277,8 +277,8 @@ class Subtractor(InplacableBinaryOpParams[RegisterOrConst, RegisterOrConst]):
277
277
  )
278
278
  integer_part_size = number_utils.bounds_to_integer_part_size(*bounds)
279
279
  fraction_places = max(
280
- argument_utils.fraction_places(self.left_arg),
281
- argument_utils.fraction_places(self.right_arg),
280
+ self._compute_fraction_places(self.left_arg),
281
+ self._compute_fraction_places(self.right_arg),
282
282
  )
283
283
  size_needed = integer_part_size + fraction_places
284
284
  return RegisterArithmeticInfo(
@@ -327,7 +327,7 @@ class Subtractor(InplacableBinaryOpParams[RegisterOrConst, RegisterOrConst]):
327
327
  return self.inplace_arg == ArgToInplace.LEFT
328
328
 
329
329
  def _expected_negation_output_size(self) -> int:
330
- return argument_utils.fraction_places(self.right_arg) + min(
330
+ return self._compute_fraction_places(self.right_arg) + min(
331
331
  self.result_register.integer_part_size,
332
332
  number_utils.bounds_to_integer_part_size(
333
333
  *(-bound for bound in argument_utils.bounds(self.right_arg))
@@ -357,9 +357,9 @@ class Multiplier(BinaryOpWithFloatInputs):
357
357
  output_name = "product"
358
358
 
359
359
  def _get_result_register(self) -> RegisterArithmeticInfo:
360
- fraction_places = argument_utils.fraction_places(
360
+ fraction_places = self._compute_fraction_places(
361
361
  self.left_arg
362
- ) + argument_utils.fraction_places(self.right_arg)
362
+ ) + self._compute_fraction_places(self.right_arg)
363
363
  extremal_values = [
364
364
  left * right
365
365
  for left in argument_utils.bounds(self.left_arg)
@@ -583,9 +583,7 @@ class Modulo(EffectiveUnaryOpParams[int]):
583
583
  ) -> int:
584
584
  repr_qubits_float = math.log2(right_arg)
585
585
  repr_qubits = round(repr_qubits_float)
586
- assert (
587
- abs(repr_qubits - repr_qubits_float) < 10**-8
588
- ), NOT_POWER_OF_TWO_ERROR_MSG
586
+ assert abs(repr_qubits - repr_qubits_float) < 10**-8, NOT_POWER_OF_TWO_ERROR_MSG
589
587
  output_size = values.get("output_size")
590
588
  if output_size is not None:
591
589
  repr_qubits = min(repr_qubits, output_size)
@@ -61,8 +61,8 @@ class Extremum(ArithmeticOperationParams):
61
61
  argument_utils.integer_part_size(self.right_arg),
62
62
  )
63
63
  fraction_places = max(
64
- argument_utils.fraction_places(self.left_arg),
65
- argument_utils.fraction_places(self.right_arg),
64
+ self._compute_fraction_places(self.left_arg),
65
+ self._compute_fraction_places(self.right_arg),
66
66
  )
67
67
  required_size = integer_part_size + fraction_places
68
68
  bounds = (
@@ -1,6 +1,6 @@
1
1
  from typing import Tuple, Union
2
2
 
3
- _MAXIMAL_MACHINE_PRECISION: int = 20
3
+ MAXIMAL_MACHINE_PRECISION: int = 20
4
4
  MAX_FRACTION_PLACES: int = 8
5
5
 
6
6
 
@@ -42,7 +42,7 @@ def _get_fraction_places(*, binary_value: str, machine_precision: int) -> int:
42
42
 
43
43
 
44
44
  def get_int_representation_and_fraction_places(
45
- float_value: float, *, machine_precision: int = MAX_FRACTION_PLACES
45
+ float_value: float, *, machine_precision: int
46
46
  ) -> Tuple[int, int]:
47
47
  int_val = signed_int_to_unsigned(int(float_value * 2**machine_precision))
48
48
  if int_val == 0:
@@ -54,9 +54,7 @@ def get_int_representation_and_fraction_places(
54
54
  return int_val, fraction_places
55
55
 
56
56
 
57
- def fraction_places(
58
- float_value: float, *, machine_precision: int = MAX_FRACTION_PLACES
59
- ) -> int:
57
+ def fraction_places(float_value: float, *, machine_precision: int) -> int:
60
58
  int_val = signed_int_to_unsigned(int(float_value * 2**machine_precision))
61
59
  if int_val == 0:
62
60
  return 0
@@ -70,7 +68,7 @@ def _bit_length(integer_representation: int) -> int:
70
68
 
71
69
 
72
70
  def binary_string(
73
- float_value: float, *, machine_precision: int = _MAXIMAL_MACHINE_PRECISION
71
+ float_value: float, *, machine_precision: int = MAXIMAL_MACHINE_PRECISION
74
72
  ) -> str:
75
73
  int_val, _ = get_int_representation_and_fraction_places(
76
74
  float_value=float_value, machine_precision=machine_precision
@@ -83,32 +81,24 @@ def binary_string(
83
81
  return bin_rep[::-1] + extension_bit * size_diff
84
82
 
85
83
 
86
- def integer_part_size(
87
- float_value: float, *, machine_precision: int = MAX_FRACTION_PLACES
88
- ) -> int:
84
+ def integer_part_size(float_value: float) -> int:
89
85
  int_val, fraction_places = get_int_representation_and_fraction_places(
90
- float_value=float_value, machine_precision=machine_precision
86
+ float_value=float_value, machine_precision=MAXIMAL_MACHINE_PRECISION
91
87
  )
92
88
  return max(_bit_length(int_val) - fraction_places, 0)
93
89
 
94
90
 
95
- def size(float_value: float, *, machine_precision: int = MAX_FRACTION_PLACES) -> int:
91
+ def size(float_value: float, *, machine_precision: int) -> int:
96
92
  int_val, fraction_places = get_int_representation_and_fraction_places(
97
93
  float_value=float_value, machine_precision=machine_precision
98
94
  )
99
95
  return max(_bit_length(int_val), fraction_places)
100
96
 
101
97
 
102
- def bounds_to_integer_part_size(
103
- lb: float, ub: float, *, machine_precision: int = MAX_FRACTION_PLACES
104
- ) -> int:
98
+ def bounds_to_integer_part_size(lb: float, ub: float) -> int:
105
99
  lb, ub = min(lb, ub), max(lb, ub)
106
- ub_integer_part_size: int = integer_part_size(
107
- float_value=ub, machine_precision=machine_precision
108
- )
109
- lb_integer_part_size: int = integer_part_size(
110
- float_value=lb, machine_precision=machine_precision
111
- )
100
+ ub_integer_part_size: int = integer_part_size(float_value=ub)
101
+ lb_integer_part_size: int = integer_part_size(float_value=lb)
112
102
  if lb == 0:
113
103
  return ub_integer_part_size
114
104
  if ub == 0:
@@ -118,8 +108,15 @@ def bounds_to_integer_part_size(
118
108
 
119
109
 
120
110
  def limit_fraction_places(number: float, *, machine_precision: int) -> float:
121
- bin_rep = binary_string(number, machine_precision=machine_precision)[::-1]
122
- frac_places = fraction_places(number, machine_precision=machine_precision)
111
+ orig_bin_rep = binary_string(number, machine_precision=MAXIMAL_MACHINE_PRECISION)[
112
+ ::-1
113
+ ]
114
+ orig_fractions = fraction_places(
115
+ number, machine_precision=MAXIMAL_MACHINE_PRECISION
116
+ )
117
+ removed_fractions = max(orig_fractions - machine_precision, 0)
123
118
  return binary_to_float(
124
- bin_rep=bin_rep, fraction_part_size=frac_places, is_signed=number < 0
119
+ bin_rep=orig_bin_rep[: len(orig_bin_rep) - removed_fractions],
120
+ fraction_part_size=orig_fractions - removed_fractions,
121
+ is_signed=number < 0,
125
122
  )
@@ -7,6 +7,8 @@ from classiq.interface.helpers.hashable_pydantic_base_model import (
7
7
  HashablePydanticBaseModel,
8
8
  )
9
9
 
10
+ from classiq.exceptions import ClassiqValueError
11
+
10
12
 
11
13
  class RegisterArithmeticInfo(HashablePydanticBaseModel):
12
14
  size: pydantic.PositiveInt
@@ -30,7 +32,7 @@ class RegisterArithmeticInfo(HashablePydanticBaseModel):
30
32
  return tuple(bounds) # type: ignore[return-value]
31
33
  size = values.get("size")
32
34
  if not isinstance(size, int):
33
- raise ValueError("RegisterUserInput must have an integer size")
35
+ raise ClassiqValueError("RegisterUserInput must have an integer size")
34
36
  is_signed: bool = values.get("is_signed", False)
35
37
  lb = 0 if not is_signed else -(2 ** (size - 1))
36
38
  ub = 2**size - 1 if not is_signed else 2 ** (size - 1) - 1
@@ -19,13 +19,12 @@ class UnaryOpParams(ArithmeticOperationParams):
19
19
  arg: RegisterArithmeticInfo
20
20
  inplace: bool = False
21
21
 
22
- @classmethod
23
22
  @abc.abstractmethod
24
- def _expected_result_size(cls, arg: RegisterArithmeticInfo) -> pydantic.PositiveInt:
23
+ def _expected_result_size(self) -> pydantic.PositiveInt:
25
24
  pass
26
25
 
27
26
  def actual_result_size(self) -> int:
28
- return self.output_size or self._expected_result_size(self.arg)
27
+ return self.output_size or self._expected_result_size()
29
28
 
30
29
  def garbage_output_size(self) -> pydantic.NonNegativeInt:
31
30
  return int(self.is_inplaced()) * max(
@@ -73,9 +72,8 @@ class UnaryOpParams(ArithmeticOperationParams):
73
72
  class BitwiseInvert(UnaryOpParams):
74
73
  output_name = "inverted"
75
74
 
76
- @classmethod
77
- def _expected_result_size(cls, arg: RegisterArithmeticInfo) -> pydantic.PositiveInt:
78
- return arg.size
75
+ def _expected_result_size(self) -> pydantic.PositiveInt:
76
+ return self.arg.size
79
77
 
80
78
  def _get_result_register(self) -> RegisterArithmeticInfo:
81
79
  return RegisterArithmeticInfo(
@@ -88,12 +86,11 @@ class BitwiseInvert(UnaryOpParams):
88
86
  class Negation(UnaryOpParams):
89
87
  output_name = "negated"
90
88
 
91
- @classmethod
92
- def _expected_result_size(cls, arg: RegisterArithmeticInfo) -> pydantic.PositiveInt:
93
- if arg.size == 1:
89
+ def _expected_result_size(self) -> pydantic.PositiveInt:
90
+ if self.arg.size == 1:
94
91
  return 1
95
- return arg.fraction_places + number_utils.bounds_to_integer_part_size(
96
- *(-bound for bound in arg.bounds)
92
+ return self.arg.fraction_places + number_utils.bounds_to_integer_part_size(
93
+ *(-bound for bound in self.arg.bounds)
97
94
  )
98
95
 
99
96
  def _get_result_register(self) -> RegisterArithmeticInfo:
@@ -118,8 +115,7 @@ class Sign(UnaryOpParams):
118
115
  raise ValueError("Sign output size must be 1")
119
116
  return 1
120
117
 
121
- @classmethod
122
- def _expected_result_size(cls, arg: RegisterArithmeticInfo) -> pydantic.PositiveInt:
118
+ def _expected_result_size(self) -> pydantic.PositiveInt:
123
119
  return 1
124
120
 
125
121
  def _get_result_register(self) -> RegisterArithmeticInfo:
@@ -11,6 +11,8 @@ SUPPORTED_ATOMIC_EXPRESSION_FUNCTIONS = {
11
11
  "get_type",
12
12
  "struct_literal",
13
13
  "get_field",
14
+ "fraction_digits",
15
+ "is_signed",
14
16
  "molecule_problem_to_hamiltonian",
15
17
  "fock_hamiltonian_problem_to_hamiltonian",
16
18
  "molecule_ground_state_solution_post_process",
@@ -4,6 +4,9 @@ from typing import Any, Mapping, Optional, Type
4
4
  import pydantic
5
5
  from pydantic import PrivateAttr
6
6
 
7
+ from classiq.interface.generator.arith.arithmetic_expression_validator import (
8
+ DEFAULT_SUPPORTED_FUNC_NAMES,
9
+ )
7
10
  from classiq.interface.generator.expressions.atomic_expression_functions import (
8
11
  SUPPORTED_ATOMIC_EXPRESSION_FUNCTIONS,
9
12
  )
@@ -32,8 +35,10 @@ class Expression(HashablePydanticBaseModel):
32
35
 
33
36
  @pydantic.validator("expr")
34
37
  def validate_expression(cls, expr: str) -> str:
35
- supported_functions = SUPPORTED_ATOMIC_EXPRESSION_FUNCTIONS | set(
36
- SYMPY_SUPPORTED_EXPRESSIONS
38
+ supported_functions = (
39
+ SUPPORTED_ATOMIC_EXPRESSION_FUNCTIONS
40
+ | set(SYMPY_SUPPORTED_EXPRESSIONS)
41
+ | set(DEFAULT_SUPPORTED_FUNC_NAMES)
37
42
  )
38
43
  validate_expression_str(expr, supported_functions=supported_functions)
39
44
  return expr