classiq 0.32.1__py3-none-any.whl → 0.34.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 (74) hide show
  1. classiq/__init__.py +2 -1
  2. classiq/_analyzer_extras/_ipywidgets_async_extension.py +1 -1
  3. classiq/_internals/api_wrapper.py +34 -23
  4. classiq/_internals/jobs.py +41 -14
  5. classiq/analyzer/__init__.py +3 -1
  6. classiq/applications/__init__.py +3 -1
  7. classiq/applications/benchmarking/__init__.py +3 -1
  8. classiq/applications/chemistry/__init__.py +3 -1
  9. classiq/applications/combinatorial_optimization/__init__.py +3 -1
  10. classiq/applications/combinatorial_optimization/examples/__init__.py +3 -1
  11. classiq/applications/finance/__init__.py +3 -1
  12. classiq/applications/qnn/__init__.py +3 -1
  13. classiq/applications/qnn/datasets/__init__.py +3 -1
  14. classiq/applications/qsvm/qsvm.py +1 -1
  15. classiq/applications_model_constructors/grover_model_constructor.py +25 -8
  16. classiq/builtin_functions/__init__.py +3 -1
  17. classiq/execution/__init__.py +3 -1
  18. classiq/execution/jobs.py +57 -20
  19. classiq/executor.py +4 -11
  20. classiq/interface/_version.py +1 -1
  21. classiq/interface/analyzer/analysis_params.py +1 -1
  22. classiq/interface/backend/backend_preferences.py +17 -0
  23. classiq/interface/backend/pydantic_backend.py +8 -0
  24. classiq/interface/backend/quantum_backend_providers.py +15 -1
  25. classiq/interface/chemistry/ground_state_problem.py +1 -1
  26. classiq/interface/chemistry/operator.py +198 -0
  27. classiq/interface/executor/execution_request.py +5 -12
  28. classiq/interface/generator/circuit_code/types_and_constants.py +1 -1
  29. classiq/interface/generator/complex_type.py +4 -1
  30. classiq/interface/generator/functions/__init__.py +3 -1
  31. classiq/interface/generator/functions/core_lib_declarations/quantum_functions/__init__.py +0 -1
  32. classiq/interface/generator/functions/core_lib_declarations/quantum_functions/atomic_quantum_functions.py +39 -39
  33. classiq/interface/generator/functions/core_lib_declarations/quantum_functions/std_lib_functions.py +251 -87
  34. classiq/interface/generator/functions/core_lib_declarations/quantum_operators.py +5 -54
  35. classiq/interface/generator/generated_circuit.py +14 -43
  36. classiq/interface/generator/generated_circuit_data.py +26 -34
  37. classiq/interface/generator/model/preferences/preferences.py +3 -3
  38. classiq/interface/generator/partitioned_register.py +1 -1
  39. classiq/interface/generator/quantum_function_call.py +1 -1
  40. classiq/interface/generator/validations/validator_functions.py +4 -2
  41. classiq/interface/hardware.py +3 -2
  42. classiq/interface/ide/show.py +1 -14
  43. classiq/interface/model/bind_operation.py +20 -0
  44. classiq/interface/model/handle_binding.py +8 -0
  45. classiq/interface/model/native_function_definition.py +15 -5
  46. classiq/interface/model/quantum_expressions/amplitude_loading_operation.py +8 -3
  47. classiq/interface/model/quantum_expressions/arithmetic_operation.py +9 -4
  48. classiq/interface/model/quantum_expressions/quantum_expression.py +10 -5
  49. classiq/interface/model/quantum_function_call.py +24 -347
  50. classiq/interface/model/quantum_function_declaration.py +7 -11
  51. classiq/interface/model/quantum_statement.py +13 -7
  52. classiq/interface/model/validations/handle_validation_base.py +1 -2
  53. classiq/interface/model/validations/handles_validator.py +34 -8
  54. classiq/interface/model/variable_declaration_statement.py +8 -0
  55. classiq/interface/server/routes.py +11 -16
  56. classiq/model/__init__.py +3 -1
  57. classiq/model/function_handler.py +1 -1
  58. classiq/model/function_handler.pyi +88 -88
  59. classiq/qmod/declaration_inferrer.py +37 -18
  60. classiq/qmod/model_state_container.py +6 -3
  61. classiq/qmod/qmod_builtins.py +892 -4
  62. classiq/qmod/qmod_parameter.py +24 -8
  63. classiq/qmod/qmod_variable.py +2 -1
  64. classiq/qmod/quantum_expandable.py +6 -2
  65. classiq/qmod/quantum_function.py +11 -10
  66. classiq/quantum_functions/quantum_function.py +4 -1
  67. {classiq-0.32.1.dist-info → classiq-0.34.0.dist-info}/METADATA +1 -1
  68. {classiq-0.32.1.dist-info → classiq-0.34.0.dist-info}/RECORD +69 -72
  69. classiq/interface/generator/functions/core_lib_declarations/quantum_functions/apps_lib_functions.py +0 -262
  70. classiq/interface/model/clients/__init__.py +0 -0
  71. classiq/interface/model/clients/qmod/__init__.py +0 -0
  72. classiq/interface/model/clients/qmod/qmod_builtins.py +0 -908
  73. classiq/interface/model/semantics.py +0 -15
  74. {classiq-0.32.1.dist-info → classiq-0.34.0.dist-info}/WHEEL +0 -0
@@ -1,62 +1,29 @@
1
- import functools
2
1
  import itertools
3
2
  import re
4
- from collections import defaultdict
5
- from typing import (
6
- TYPE_CHECKING,
7
- Any,
8
- Collection,
9
- Dict,
10
- Iterable,
11
- List,
12
- Mapping,
13
- Match,
14
- Optional,
15
- Sequence,
16
- Set,
17
- Tuple,
18
- Union,
19
- )
3
+ from typing import Any, Dict, List, Mapping, Optional, Sequence, Set, Union
20
4
 
21
5
  import pydantic
22
- from pydantic import BaseModel, Extra
6
+ from pydantic import BaseModel
23
7
 
24
- from classiq.interface.generator import function_param_list, function_params as f_params
25
8
  from classiq.interface.generator.arith.arithmetic import Arithmetic
26
9
  from classiq.interface.generator.control_state import ControlState
27
10
  from classiq.interface.generator.expressions.expression import Expression
28
- from classiq.interface.generator.function_params import (
29
- NAME_REGEX,
30
- FunctionParams,
31
- IOName,
32
- PortDirection,
33
- )
11
+ from classiq.interface.generator.function_params import NAME_REGEX
34
12
  from classiq.interface.generator.functions import FunctionDeclaration
35
13
  from classiq.interface.generator.functions.port_declaration import (
36
14
  PortDeclarationDirection,
37
15
  )
38
16
  from classiq.interface.generator.quantum_function_call import (
39
17
  BAD_CALL_NAME_ERROR_MSG,
40
- BAD_INPUT_ERROR_MSG,
41
- BAD_INPUT_EXPRESSION_MSG,
42
- BAD_INPUT_SLICING_MSG,
43
- BAD_OUTPUT_ERROR_MSG,
44
- BAD_OUTPUT_EXPRESSION_MSG,
45
- BAD_OUTPUT_SLICING_MSG,
46
- CUSTOM_FUNCTION_SINGLE_IO_ERROR,
47
- LEGAL_SLICING,
48
18
  SUFFIX_MARKER,
49
19
  randomize_suffix,
50
20
  )
51
- from classiq.interface.generator.slice_parsing_utils import (
52
- IO_REGEX,
53
- NAME,
54
- SLICING,
55
- parse_io_slicing,
56
- )
57
- from classiq.interface.generator.user_defined_function_params import CustomFunction
58
21
  from classiq.interface.helpers.custom_pydantic_types import PydanticNonEmptyString
59
- from classiq.interface.model.handle_binding import HandleBinding, SlicedHandleBinding
22
+ from classiq.interface.model.handle_binding import (
23
+ HandleBinding,
24
+ SlicedHandleBinding,
25
+ SubscriptHandleBinding,
26
+ )
60
27
  from classiq.interface.model.quantum_function_declaration import (
61
28
  QuantumFunctionDeclaration,
62
29
  QuantumOperandDeclaration,
@@ -64,7 +31,7 @@ from classiq.interface.model.quantum_function_declaration import (
64
31
  from classiq.interface.model.quantum_statement import QuantumOperation
65
32
  from classiq.interface.model.validation_handle import get_unique_handle_names
66
33
 
67
- from classiq.exceptions import ClassiqControlError, ClassiqValueError
34
+ from classiq.exceptions import ClassiqError, ClassiqValueError
68
35
 
69
36
 
70
37
  def _validate_no_duplicated_ports(
@@ -140,10 +107,6 @@ class QuantumFunctionCall(QuantumOperation):
140
107
  description="The function that is called"
141
108
  )
142
109
  params: Dict[str, Expression] = pydantic.Field(default_factory=dict)
143
- function_params: f_params.FunctionParams = pydantic.Field(
144
- description="The parameters necessary for defining the function",
145
- default_factory=CustomFunction,
146
- )
147
110
  strict_zero_ios: bool = pydantic.Field(
148
111
  default=True,
149
112
  description="Enables automated qubit allocation for pre-determined zero inputs "
@@ -163,15 +126,17 @@ class QuantumFunctionCall(QuantumOperation):
163
126
  default=True,
164
127
  description="False value indicates this call shouldn't be controlled even if the flow is controlled.",
165
128
  )
166
- inputs: Dict[IOName, HandleBinding] = pydantic.Field(
129
+ inputs: Dict[str, HandleBinding] = pydantic.Field(
167
130
  default_factory=dict,
168
131
  description="A mapping from the input name to the wire it connects to",
169
132
  )
170
- inouts: Dict[IOName, Union[SlicedHandleBinding, HandleBinding]] = pydantic.Field(
133
+ inouts: Dict[
134
+ str, Union[SlicedHandleBinding, SubscriptHandleBinding, HandleBinding]
135
+ ] = pydantic.Field(
171
136
  default_factory=dict,
172
137
  description="A mapping from in/out name to the wires that connect to it",
173
138
  )
174
- outputs: Dict[IOName, HandleBinding] = pydantic.Field(
139
+ outputs: Dict[str, HandleBinding] = pydantic.Field(
175
140
  default_factory=dict,
176
141
  description="A mapping from the output name to the wire it connects to",
177
142
  )
@@ -191,7 +156,10 @@ class QuantumFunctionCall(QuantumOperation):
191
156
  )
192
157
 
193
158
  @property
194
- def func_decl(self) -> Optional[QuantumFunctionDeclaration]:
159
+ def func_decl(self) -> QuantumFunctionDeclaration:
160
+ if self._func_decl is None:
161
+ raise ClassiqError("Accessing an unresolved quantum function call")
162
+
195
163
  return self._func_decl
196
164
 
197
165
  def set_func_decl(self, fd: Optional[FunctionDeclaration]) -> None:
@@ -208,17 +176,19 @@ class QuantumFunctionCall(QuantumOperation):
208
176
  return self.function
209
177
 
210
178
  @property
211
- def wiring_inputs(self) -> Mapping[IOName, HandleBinding]:
179
+ def wiring_inputs(self) -> Mapping[str, HandleBinding]:
212
180
  return self.inputs
213
181
 
214
182
  @property
215
183
  def wiring_inouts(
216
184
  self,
217
- ) -> Mapping[IOName, Union[SlicedHandleBinding, HandleBinding]]:
185
+ ) -> Mapping[
186
+ str, Union[SlicedHandleBinding, SubscriptHandleBinding, HandleBinding]
187
+ ]:
218
188
  return self.inouts
219
189
 
220
190
  @property
221
- def wiring_outputs(self) -> Mapping[IOName, HandleBinding]:
191
+ def wiring_outputs(self) -> Mapping[str, HandleBinding]:
222
192
  return self.outputs
223
193
 
224
194
  def get_positional_args(self) -> List[ArgValue]:
@@ -253,41 +223,13 @@ class QuantumFunctionCall(QuantumOperation):
253
223
  if isinstance(function, OperandIdentifier):
254
224
  function = function.name
255
225
 
256
- params = values.get("function_params")
257
- if isinstance(params, CustomFunction):
258
- if function == CustomFunction.discriminator() and params.name != "":
259
- function = params.name
260
-
261
226
  suffix = f"{SUFFIX_MARKER}_{randomize_suffix()}"
262
- if not function or params is None:
227
+ if not function:
263
228
  return name if name else suffix
264
229
  return f"{function}_{suffix}"
265
230
 
266
- @pydantic.root_validator(pre=True)
267
- def validate_composite_name(cls, values: Dict[str, Any]) -> Dict[str, Any]:
268
- if isinstance(values.get("unitary_params"), CustomFunction) and not values.get(
269
- "unitary"
270
- ):
271
- raise ClassiqValueError(
272
- "`PhaseEstimation` of a user define function (`CustomFunction`) must receive the function name from the `unitary` field"
273
- )
274
- return values
275
-
276
- @pydantic.root_validator(pre=True)
277
- def _parse_function_params(cls, values: Dict[str, Any]) -> Dict[str, Any]:
278
- f_params.parse_function_params_values(
279
- values=values,
280
- params_key="function_params",
281
- discriminator_key="function",
282
- param_classes=function_param_list.function_param_library.param_list,
283
- default_parser_class=CustomFunction,
284
- )
285
- return values
286
-
287
231
  @property
288
232
  def pos_param_args(self) -> Dict[str, Expression]:
289
- if TYPE_CHECKING:
290
- assert self.func_decl is not None
291
233
  return dict(
292
234
  zip(
293
235
  self.func_decl.param_decls.keys(),
@@ -301,8 +243,6 @@ class QuantumFunctionCall(QuantumOperation):
301
243
 
302
244
  @property
303
245
  def pos_operand_args(self) -> Dict[str, "QuantumOperand"]:
304
- if TYPE_CHECKING:
305
- assert self.func_decl is not None
306
246
  return dict(
307
247
  zip(
308
248
  self.func_decl.operand_declarations.keys(),
@@ -316,8 +256,6 @@ class QuantumFunctionCall(QuantumOperation):
316
256
 
317
257
  @property
318
258
  def pos_port_args(self) -> Dict[str, HandleBinding]:
319
- if TYPE_CHECKING:
320
- assert self.func_decl is not None
321
259
  return dict(
322
260
  zip(
323
261
  self.func_decl.port_declarations.keys(),
@@ -330,8 +268,6 @@ class QuantumFunctionCall(QuantumOperation):
330
268
  )
331
269
 
332
270
  def _update_pos_port_params(self) -> None:
333
- if TYPE_CHECKING:
334
- assert self.func_decl is not None
335
271
  for name, port_decl in self.func_decl.port_declarations.items():
336
272
  if port_decl.direction == PortDeclarationDirection.Input:
337
273
  self.inputs[name] = self.pos_port_args[name]
@@ -345,45 +281,10 @@ class QuantumFunctionCall(QuantumOperation):
345
281
  self.operands.update(self.pos_operand_args)
346
282
  self._update_pos_port_params()
347
283
 
348
- # TODO: note that this checks QuantumFunctionCall input register names
349
- # are PARTIAL to FunctionParams input register names, not EQUAL.
350
- # We might want to change that.
351
- @staticmethod
352
- def _validate_input_names(
353
- *,
354
- params: f_params.FunctionParams,
355
- input_names: Collection[IOName],
356
- control_states: List[ControlState],
357
- strict_zero_ios: bool,
358
- ) -> None:
359
- (
360
- invalid_expressions,
361
- invalid_slicings,
362
- invalid_names,
363
- ) = QuantumFunctionCall._get_invalid_ios(
364
- expressions=input_names,
365
- params=params,
366
- io=PortDirection.Input,
367
- control_states=control_states,
368
- strict_zero_ios=strict_zero_ios,
369
- )
370
- error_msg = []
371
- if invalid_expressions:
372
- error_msg.append(f"{BAD_INPUT_EXPRESSION_MSG}: {invalid_expressions}")
373
- if invalid_names:
374
- error_msg.append(f"{BAD_INPUT_ERROR_MSG}: {invalid_names}")
375
- if invalid_slicings:
376
- error_msg.append(f"{BAD_INPUT_SLICING_MSG}: {invalid_slicings}")
377
- if error_msg:
378
- raise ValueError("\n".join(error_msg))
379
-
380
284
  def resolve_function_decl(
381
285
  self,
382
286
  function_dict: Mapping[str, FunctionDeclaration],
383
287
  ) -> None:
384
- if not isinstance(self.function_params, CustomFunction):
385
- return
386
-
387
288
  if self._func_decl is None:
388
289
  func_decl = function_dict.get(self.func_name)
389
290
  if func_decl is None:
@@ -392,9 +293,6 @@ class QuantumFunctionCall(QuantumOperation):
392
293
  )
393
294
  self.set_func_decl(func_decl)
394
295
 
395
- if TYPE_CHECKING:
396
- assert self.func_decl is not None
397
-
398
296
  if self.positional_args:
399
297
  self._reduce_positional_args_to_keywords()
400
298
 
@@ -425,228 +323,10 @@ class QuantumFunctionCall(QuantumOperation):
425
323
  ), "when using the Arithmetic function, assign to the expression result register via the target parameter instead of the strict_zero_ios flag"
426
324
  return strict_zero_ios
427
325
 
428
- @pydantic.validator("control_states")
429
- def _validate_control_states(
430
- cls, control_states: List[ControlState], values: Dict[str, Any]
431
- ) -> List[ControlState]:
432
- control_names = [ctrl_state.name for ctrl_state in control_states]
433
- function_params = values.get("function_params")
434
- strict_zero_ios = values.get("strict_zero_ios")
435
- if not (
436
- isinstance(function_params, FunctionParams)
437
- and isinstance(strict_zero_ios, bool)
438
- ):
439
- return control_states
440
- all_input_names = [
441
- *function_params.inputs_full(strict_zero_ios=strict_zero_ios),
442
- *control_names,
443
- ]
444
- all_output_names = [*function_params.outputs, *control_names]
445
- if any(
446
- cls._has_repetitions(name_list)
447
- for name_list in (control_names, all_input_names, all_output_names)
448
- ):
449
- raise ClassiqControlError()
450
- return control_states
451
-
452
326
  @staticmethod
453
327
  def _has_repetitions(name_list: Sequence[str]) -> bool:
454
328
  return len(set(name_list)) < len(name_list)
455
329
 
456
- @staticmethod
457
- def _validate_slices(
458
- io: PortDirection,
459
- input_names: Collection[IOName],
460
- fp: FunctionParams,
461
- strict_zero_ios: bool,
462
- control_states: List[ControlState],
463
- ) -> None:
464
- name_slice_pairs = [parse_io_slicing(input) for input in input_names]
465
- slices_dict: Dict[str, List[slice]] = defaultdict(list)
466
- for name, slice_obj in name_slice_pairs:
467
- slices_dict[name].append(slice_obj)
468
-
469
- fp_inputs = (
470
- fp.inputs_full(strict_zero_ios)
471
- if (io == PortDirection.Input)
472
- else fp.outputs
473
- )
474
- widths = {name: reg.size for name, reg in fp_inputs.items()}
475
- control_names = {state.name for state in control_states}
476
-
477
- for name in slices_dict:
478
- if name in control_names:
479
- continue
480
- assert name in widths, "Name not in widths"
481
- if not QuantumFunctionCall._register_validate_slices(
482
- slices_dict[name], widths[name]
483
- ):
484
- raise ValueError(BAD_INPUT_SLICING_MSG)
485
-
486
- @staticmethod
487
- def _register_validate_slices(slices: List[slice], reg_width: int) -> bool:
488
- widths_separated = [len(range(reg_width)[reg_slice]) for reg_slice in slices]
489
- # examples: slice(0), slice(5,None) when width <= 5, slice(5,3)
490
- empty_slices = 0 in widths_separated
491
-
492
- max_stop = max(reg_slice.stop or 0 for reg_slice in slices)
493
- out_of_range = max_stop > reg_width
494
-
495
- all_widths_separated = sum(widths_separated)
496
- all_indices = set(
497
- itertools.chain.from_iterable(
498
- range(reg_width)[reg_slice] for reg_slice in slices
499
- )
500
- )
501
- all_widths_combined = len(all_indices)
502
- overlapping_slices = all_widths_combined != all_widths_separated
503
-
504
- return not any((empty_slices, out_of_range, overlapping_slices))
505
-
506
- @pydantic.validator("inputs")
507
- def _validate_inputs(
508
- cls, inputs: Mapping[IOName, HandleBinding], values: Dict[str, Any]
509
- ) -> Mapping[IOName, HandleBinding]:
510
- params: Optional[FunctionParams] = values.get("function_params")
511
- strict_zero_ios: bool = values.get("strict_zero_ios", True)
512
- control_states: List[ControlState] = values.get("control_states", list())
513
- if params is None:
514
- return dict()
515
- if isinstance(params, CustomFunction):
516
- if not isinstance(inputs, dict):
517
- raise ValueError(CUSTOM_FUNCTION_SINGLE_IO_ERROR)
518
- return inputs
519
-
520
- cls._validate_input_names(
521
- params=params,
522
- input_names=inputs.keys(),
523
- control_states=control_states,
524
- strict_zero_ios=strict_zero_ios,
525
- )
526
-
527
- cls._validate_slices(
528
- PortDirection.Input,
529
- inputs.keys(),
530
- params,
531
- strict_zero_ios,
532
- control_states,
533
- )
534
-
535
- return inputs
536
-
537
- @staticmethod
538
- def _validate_output_names(
539
- *,
540
- params: f_params.FunctionParams,
541
- output_names: Collection[IOName],
542
- control_states: List[ControlState],
543
- strict_zero_ios: bool,
544
- ) -> None:
545
- (
546
- invalid_expressions,
547
- invalid_slicings,
548
- invalid_names,
549
- ) = QuantumFunctionCall._get_invalid_ios(
550
- expressions=output_names,
551
- params=params,
552
- io=PortDirection.Output,
553
- control_states=control_states,
554
- strict_zero_ios=strict_zero_ios,
555
- )
556
- error_msg = []
557
- if invalid_expressions:
558
- error_msg.append(f"{BAD_OUTPUT_EXPRESSION_MSG}: {invalid_expressions}")
559
- if invalid_names:
560
- error_msg.append(f"{BAD_OUTPUT_ERROR_MSG}: {invalid_names}")
561
- if invalid_slicings:
562
- error_msg.append(f"{BAD_OUTPUT_SLICING_MSG}: {invalid_slicings}")
563
- if error_msg:
564
- raise ValueError("\n".join(error_msg))
565
-
566
- @pydantic.validator("outputs")
567
- def _validate_outputs(
568
- cls, outputs: Mapping[IOName, HandleBinding], values: Dict[str, Any]
569
- ) -> Mapping[IOName, HandleBinding]:
570
- params = values.get("function_params")
571
- strict_zero_ios: bool = values.get("strict_zero_ios", True)
572
- control_states = values.get("control_states", list())
573
- if params is None:
574
- return outputs
575
- if isinstance(params, CustomFunction):
576
- if not isinstance(outputs, dict):
577
- raise ValueError(CUSTOM_FUNCTION_SINGLE_IO_ERROR)
578
- return outputs
579
-
580
- cls._validate_output_names(
581
- params=params,
582
- output_names=outputs.keys(),
583
- control_states=control_states,
584
- strict_zero_ios=strict_zero_ios,
585
- )
586
-
587
- cls._validate_slices(
588
- PortDirection.Output,
589
- outputs.keys(),
590
- params,
591
- strict_zero_ios,
592
- control_states,
593
- )
594
-
595
- return outputs
596
-
597
- @staticmethod
598
- def _get_invalid_ios(
599
- *,
600
- expressions: Iterable[str],
601
- params: f_params.FunctionParams,
602
- io: f_params.PortDirection,
603
- control_states: List[ControlState],
604
- strict_zero_ios: bool,
605
- ) -> Tuple[List[str], List[str], List[str]]:
606
- expression_matches: Iterable[Optional[Match]] = map(
607
- functools.partial(re.fullmatch, IO_REGEX), expressions
608
- )
609
-
610
- valid_matches: List[Match] = []
611
- invalid_expressions: List[str] = []
612
- for expression, expression_match in zip(expressions, expression_matches):
613
- invalid_expressions.append(
614
- expression
615
- ) if expression_match is None else valid_matches.append(expression_match)
616
-
617
- invalid_slicings: List[str] = []
618
- invalid_names: List[str] = []
619
- valid_names = frozenset(
620
- params.inputs_full(strict_zero_ios)
621
- if io == PortDirection.Input
622
- else params.outputs
623
- )
624
- for match in valid_matches:
625
- name = match.groupdict().get(NAME)
626
- if name is None:
627
- raise AssertionError("Input/output name validation error")
628
-
629
- slicing = match.groupdict().get(SLICING)
630
- if slicing is not None and re.fullmatch(LEGAL_SLICING, slicing) is None:
631
- invalid_slicings.append(match.string)
632
-
633
- if name in valid_names:
634
- continue
635
- elif all(state.name != name for state in control_states):
636
- invalid_names.append(name)
637
-
638
- return invalid_expressions, invalid_slicings, invalid_names
639
-
640
- def get_param_exprs(self) -> Dict[str, Expression]:
641
- if isinstance(self.function_params, CustomFunction):
642
- return self.params
643
- else:
644
- return {
645
- name: Expression(expr=raw_expr)
646
- for name, raw_expr in self.function_params
647
- if self.function_params.is_field_gen_param(name)
648
- }
649
-
650
330
  @pydantic.root_validator()
651
331
  def validate_handles(cls, values: Dict[str, Any]) -> Dict[str, Any]:
652
332
  inputs = values.get("inputs", dict())
@@ -659,9 +339,6 @@ class QuantumFunctionCall(QuantumOperation):
659
339
 
660
340
  return values
661
341
 
662
- class Config:
663
- extra = Extra.forbid
664
-
665
342
 
666
343
  class QuantumLambdaFunction(BaseModel):
667
344
  """
@@ -2,11 +2,7 @@ from typing import Any, ClassVar, Dict, List, Mapping, Sequence, Set, Type, Unio
2
2
 
3
3
  import pydantic
4
4
 
5
- from classiq.interface.generator.function_params import (
6
- ArithmeticIODict,
7
- IOName,
8
- PortDirection,
9
- )
5
+ from classiq.interface.generator.function_params import ArithmeticIODict, PortDirection
10
6
  from classiq.interface.generator.functions.function_declaration import (
11
7
  FunctionDeclaration,
12
8
  )
@@ -56,7 +52,7 @@ PositionalArg = Union[
56
52
 
57
53
 
58
54
  def _ports_to_registers(
59
- port_declarations: Dict[IOName, PortDeclaration], direction: PortDirection
55
+ port_declarations: Dict[str, PortDeclaration], direction: PortDirection
60
56
  ) -> ArithmeticIODict:
61
57
  return {
62
58
  name: quantum_var_to_register(name, port_decl.quantum_type)
@@ -70,7 +66,7 @@ class QuantumFunctionDeclaration(FunctionDeclaration):
70
66
  Facilitates the creation of a common quantum function interface object.
71
67
  """
72
68
 
73
- port_declarations: Dict[IOName, PortDeclaration] = pydantic.Field(
69
+ port_declarations: Dict[str, PortDeclaration] = pydantic.Field(
74
70
  description="The input and output ports of the function.",
75
71
  default_factory=dict,
76
72
  )
@@ -89,11 +85,11 @@ class QuantumFunctionDeclaration(FunctionDeclaration):
89
85
  ] = {}
90
86
 
91
87
  @property
92
- def input_set(self) -> Set[IOName]:
88
+ def input_set(self) -> Set[str]:
93
89
  return set(self.inputs.keys())
94
90
 
95
91
  @property
96
- def output_set(self) -> Set[IOName]:
92
+ def output_set(self) -> Set[str]:
97
93
  return set(self.outputs.keys())
98
94
 
99
95
  @property
@@ -138,8 +134,8 @@ class QuantumFunctionDeclaration(FunctionDeclaration):
138
134
 
139
135
  @pydantic.validator("port_declarations")
140
136
  def _validate_port_declarations_names(
141
- cls, port_declarations: Dict[IOName, PortDeclaration]
142
- ) -> Dict[IOName, PortDeclaration]:
137
+ cls, port_declarations: Dict[str, PortDeclaration]
138
+ ) -> Dict[str, PortDeclaration]:
143
139
  validate_nameables_mapping(port_declarations, "Port")
144
140
  return port_declarations
145
141
 
@@ -1,26 +1,32 @@
1
1
  from typing import Mapping, Union
2
2
 
3
- from pydantic import BaseModel
3
+ from pydantic import BaseModel, Extra
4
4
 
5
- from classiq.interface.generator.function_params import IOName
6
- from classiq.interface.model.handle_binding import HandleBinding, SlicedHandleBinding
5
+ from classiq.interface.model.handle_binding import (
6
+ HandleBinding,
7
+ SlicedHandleBinding,
8
+ SubscriptHandleBinding,
9
+ )
7
10
 
8
11
 
9
12
  class QuantumStatement(BaseModel):
10
- pass
13
+ class Config:
14
+ extra = Extra.forbid
11
15
 
12
16
 
13
17
  class QuantumOperation(QuantumStatement):
14
18
  @property
15
- def wiring_inputs(self) -> Mapping[IOName, HandleBinding]:
19
+ def wiring_inputs(self) -> Mapping[str, HandleBinding]:
16
20
  return dict()
17
21
 
18
22
  @property
19
23
  def wiring_inouts(
20
24
  self,
21
- ) -> Mapping[IOName, Union[SlicedHandleBinding, HandleBinding]]:
25
+ ) -> Mapping[
26
+ str, Union[SlicedHandleBinding, SubscriptHandleBinding, HandleBinding]
27
+ ]:
22
28
  return dict()
23
29
 
24
30
  @property
25
- def wiring_outputs(self) -> Mapping[IOName, HandleBinding]:
31
+ def wiring_outputs(self) -> Mapping[str, HandleBinding]:
26
32
  return dict()
@@ -1,7 +1,6 @@
1
1
  import abc
2
2
  from typing import Dict, Mapping, Type
3
3
 
4
- from classiq.interface.generator.function_params import IOName
5
4
  from classiq.interface.generator.functions.port_declaration import (
6
5
  PortDeclarationDirection,
7
6
  )
@@ -17,7 +16,7 @@ EXPECTED_TERMINAL_STATES: Dict[PortDeclarationDirection, HandleState] = {
17
16
  class HandleValidationBase(abc.ABC):
18
17
  def __init__(
19
18
  self,
20
- port_declarations: Mapping[IOName, PortDeclaration],
19
+ port_declarations: Mapping[str, PortDeclaration],
21
20
  ) -> None:
22
21
  self._port_declarations = port_declarations.values()
23
22