classiq 0.102.0__py3-none-any.whl → 1.0.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 (95) hide show
  1. classiq/__init__.py +2 -0
  2. classiq/_internals/authentication/auth0.py +29 -0
  3. classiq/_internals/authentication/auth_flow_factory.py +43 -0
  4. classiq/_internals/authentication/machine_credentials_flow.py +26 -0
  5. classiq/_internals/authentication/password_manager.py +84 -0
  6. classiq/_internals/authentication/token_manager.py +24 -8
  7. classiq/analyzer/show_interactive_hack.py +0 -8
  8. classiq/applications/chemistry/op_utils.py +32 -0
  9. classiq/applications/combinatorial_optimization/combinatorial_problem.py +1 -1
  10. classiq/evaluators/qmod_annotated_expression.py +1 -1
  11. classiq/evaluators/qmod_expression_visitors/qmod_expression_evaluator.py +1 -8
  12. classiq/evaluators/qmod_expression_visitors/qmod_expression_simplifier.py +1 -1
  13. classiq/evaluators/qmod_node_evaluators/attribute_evaluation.py +2 -2
  14. classiq/evaluators/qmod_node_evaluators/binary_op_evaluation.py +18 -29
  15. classiq/evaluators/qmod_node_evaluators/min_max_evaluation.py +1 -6
  16. classiq/evaluators/qmod_node_evaluators/numeric_attrs_utils.py +1 -7
  17. classiq/evaluators/qmod_type_inference/quantum_type_comparison.py +52 -0
  18. classiq/execution/all_hardware_devices.py +59 -1
  19. classiq/execution/execution_session.py +1 -1
  20. classiq/execution/functions/__init__.py +13 -0
  21. classiq/execution/functions/expectation_value.py +106 -0
  22. classiq/execution/functions/minimize.py +90 -0
  23. classiq/execution/functions/sample.py +76 -0
  24. classiq/execution/functions/state_vector.py +113 -0
  25. classiq/execution/functions/util/__init__.py +0 -0
  26. classiq/execution/functions/util/_logging.py +19 -0
  27. classiq/execution/functions/util/backend_preferences.py +188 -0
  28. classiq/execution/functions/util/constants.py +9 -0
  29. classiq/execution/functions/util/parse_provider_backend.py +90 -0
  30. classiq/interface/_version.py +1 -1
  31. classiq/interface/backend/backend_preferences.py +81 -0
  32. classiq/interface/backend/provider_config/providers/aqt.py +1 -1
  33. classiq/interface/backend/provider_config/providers/azure.py +1 -2
  34. classiq/interface/backend/provider_config/providers/ibm.py +1 -1
  35. classiq/interface/backend/quantum_backend_providers.py +14 -0
  36. classiq/interface/exceptions.py +0 -4
  37. classiq/interface/executor/result.py +9 -5
  38. classiq/interface/generator/arith/binary_ops.py +62 -2
  39. classiq/interface/generator/arith/number_utils.py +15 -6
  40. classiq/interface/generator/compiler_keywords.py +1 -0
  41. classiq/interface/generator/function_param_list.py +8 -2
  42. classiq/interface/generator/function_params.py +1 -1
  43. classiq/interface/generator/functions/builtins/internal_operators.py +5 -9
  44. classiq/interface/generator/functions/classical_type.py +60 -0
  45. classiq/interface/generator/functions/type_name.py +36 -0
  46. classiq/interface/generator/generated_circuit_data.py +0 -2
  47. classiq/interface/generator/transpiler_basis_gates.py +1 -0
  48. classiq/interface/generator/types/compilation_metadata.py +18 -0
  49. classiq/interface/hardware.py +2 -0
  50. classiq/interface/helpers/model_normalizer.py +42 -6
  51. classiq/interface/interface_version.py +1 -1
  52. classiq/interface/model/invert.py +8 -0
  53. classiq/interface/model/model.py +19 -0
  54. classiq/interface/model/model_visitor.py +4 -2
  55. classiq/interface/model/quantum_type.py +36 -0
  56. classiq/interface/model/statement_block.py +0 -4
  57. classiq/interface/qubits_mapping/__init__.py +4 -0
  58. classiq/interface/qubits_mapping/path_expr_range.py +69 -0
  59. classiq/interface/qubits_mapping/qubits_mapping.py +231 -0
  60. classiq/interface/qubits_mapping/slices.py +112 -0
  61. classiq/model_expansions/arithmetic.py +6 -0
  62. classiq/model_expansions/capturing/captured_vars.py +16 -12
  63. classiq/model_expansions/function_builder.py +9 -1
  64. classiq/model_expansions/interpreters/base_interpreter.py +9 -8
  65. classiq/model_expansions/interpreters/generative_interpreter.py +9 -24
  66. classiq/model_expansions/quantum_operations/arithmetic/explicit_boolean_expressions.py +1 -0
  67. classiq/model_expansions/quantum_operations/assignment_result_processor.py +132 -28
  68. classiq/model_expansions/quantum_operations/bind.py +4 -0
  69. classiq/model_expansions/quantum_operations/call_emitter.py +5 -35
  70. classiq/model_expansions/quantum_operations/emitter.py +1 -4
  71. classiq/model_expansions/quantum_operations/expression_evaluator.py +0 -3
  72. classiq/model_expansions/visitors/uncomputation_signature_inference.py +0 -9
  73. classiq/qmod/builtins/functions/__init__.py +21 -9
  74. classiq/qmod/builtins/functions/allocation.py +0 -36
  75. classiq/qmod/builtins/functions/arithmetic.py +183 -0
  76. classiq/qmod/builtins/functions/exponentiation.py +32 -2
  77. classiq/qmod/builtins/functions/gray_code.py +23 -0
  78. classiq/qmod/builtins/functions/mcx_func.py +10 -0
  79. classiq/qmod/builtins/operations.py +2 -38
  80. classiq/qmod/builtins/structs.py +22 -3
  81. classiq/qmod/native/pretty_printer.py +1 -12
  82. classiq/qmod/pretty_print/pretty_printer.py +1 -17
  83. classiq/qmod/qmod_parameter.py +4 -0
  84. classiq/qmod/qmod_variable.py +38 -63
  85. classiq/qmod/quantum_function.py +43 -7
  86. classiq/qmod/semantics/validation/function_name_collisions_validation.py +7 -4
  87. classiq/qmod/semantics/validation/model_validation.py +7 -2
  88. classiq/qmod/symbolic_type.py +4 -2
  89. classiq/qprog_to_cudaq.py +347 -0
  90. {classiq-0.102.0.dist-info → classiq-1.0.0.dist-info}/METADATA +4 -1
  91. {classiq-0.102.0.dist-info → classiq-1.0.0.dist-info}/RECORD +93 -76
  92. classiq/interface/generator/amplitude_loading.py +0 -103
  93. classiq/interface/model/quantum_expressions/amplitude_loading_operation.py +0 -77
  94. {classiq-0.102.0.dist-info → classiq-1.0.0.dist-info}/WHEEL +0 -0
  95. {classiq-0.102.0.dist-info → classiq-1.0.0.dist-info}/licenses/LICENSE.txt +0 -0
@@ -0,0 +1,52 @@
1
+ from classiq.interface.exceptions import (
2
+ ClassiqInternalExpansionError,
3
+ )
4
+ from classiq.interface.generator.expressions.expression import Expression
5
+ from classiq.interface.generator.functions.type_name import TypeName
6
+ from classiq.interface.model.quantum_type import (
7
+ QuantumBit,
8
+ QuantumBitvector,
9
+ QuantumNumeric,
10
+ QuantumType,
11
+ )
12
+
13
+
14
+ def _compare_expressions(expr1: Expression | None, expr2: Expression | None) -> bool:
15
+ if expr1 is None:
16
+ return expr2 is None
17
+ if expr2 is None:
18
+ return False
19
+ return expr1.expr == expr2.expr
20
+
21
+
22
+ def compare_quantum_types(type_1: QuantumType, type_2: QuantumType) -> bool:
23
+ for qmod_type in (type_1, type_2):
24
+ if isinstance(qmod_type, TypeName) and not qmod_type.has_fields:
25
+ raise ClassiqInternalExpansionError("Quantum struct expected")
26
+ if isinstance(type_1, QuantumBit):
27
+ return isinstance(type_2, QuantumBit)
28
+ if isinstance(type_1, QuantumNumeric):
29
+ return (
30
+ isinstance(type_2, QuantumNumeric)
31
+ and _compare_expressions(type_1.size, type_2.size)
32
+ and _compare_expressions(type_1.is_signed, type_2.is_signed)
33
+ and _compare_expressions(type_1.fraction_digits, type_2.fraction_digits)
34
+ )
35
+ if isinstance(type_1, QuantumBitvector):
36
+ return (
37
+ isinstance(type_2, QuantumBitvector)
38
+ and _compare_expressions(type_1.length, type_2.length)
39
+ and compare_quantum_types(type_1.element_type, type_2.element_type)
40
+ )
41
+ if isinstance(type_1, TypeName):
42
+ return (
43
+ isinstance(type_2, TypeName)
44
+ and type_1.name == type_2.name
45
+ and all(
46
+ compare_quantum_types(field_type_1, field_type_2)
47
+ for field_type_1, field_type_2 in zip(
48
+ type_1.fields.values(), type_2.fields.values(), strict=True
49
+ )
50
+ )
51
+ )
52
+ raise ClassiqInternalExpansionError(f"Unexpected type {type(type_1).__name__}")
@@ -1,7 +1,15 @@
1
- from classiq.interface.hardware import HardwareInformation
1
+ from typing import TYPE_CHECKING
2
+
3
+ from classiq.interface.hardware import HardwareInformation, Provider
2
4
 
3
5
  from classiq._internals import async_utils
4
6
  from classiq._internals.api_wrapper import ApiWrapper
7
+ from classiq.execution.functions.util.parse_provider_backend import (
8
+ _PROVIDER_TO_CANONICAL_NAME,
9
+ )
10
+
11
+ if TYPE_CHECKING:
12
+ from pandas import DataFrame
5
13
 
6
14
 
7
15
  def get_all_hardware_devices() -> list[HardwareInformation]:
@@ -9,3 +17,53 @@ def get_all_hardware_devices() -> list[HardwareInformation]:
9
17
  Returns a list of all hardware devices known to Classiq.
10
18
  """
11
19
  return async_utils.run(ApiWrapper.call_get_all_hardware_devices())
20
+
21
+
22
+ def _extract_relevant_hardware_fields_for_user(info: HardwareInformation) -> tuple:
23
+ return (
24
+ _PROVIDER_TO_CANONICAL_NAME[info.provider],
25
+ info.name,
26
+ info.number_of_qubits,
27
+ info.status.availability.is_available,
28
+ info.status.pending_jobs,
29
+ info.status.queue_time,
30
+ )
31
+
32
+
33
+ _NON_DISPLAYED_DEVICES = [
34
+ (Provider.CLASSIQ, "simulator_statevector"),
35
+ (Provider.CLASSIQ, "nvidia_simulator_statevector"),
36
+ (Provider.GOOGLE, "cuquantum_statevector"),
37
+ ]
38
+
39
+
40
+ def get_backend_details() -> "DataFrame":
41
+ """
42
+ Returns a pandas DataFrame containing hardware devices known to Classiq.
43
+ """
44
+ from pandas import DataFrame
45
+
46
+ devices = get_all_hardware_devices()
47
+ displayed_devices = [
48
+ device
49
+ for device in devices
50
+ if (device.provider, device.name) not in _NON_DISPLAYED_DEVICES
51
+ ]
52
+ # Remove "ibm_" prefix.
53
+ for device in displayed_devices:
54
+ if device.provider == Provider.IBM_QUANTUM and device.name.startswith("ibm_"):
55
+ device.name = device.name[len("ibm_") :]
56
+ tuples = [
57
+ _extract_relevant_hardware_fields_for_user(info) for info in displayed_devices
58
+ ]
59
+ return DataFrame(
60
+ tuples,
61
+ columns=[
62
+ "provider",
63
+ "name",
64
+ "number of qubits",
65
+ "available",
66
+ "pending jobs",
67
+ "queue time",
68
+ ],
69
+ )
@@ -365,7 +365,7 @@ class ExecutionSession:
365
365
  A list of tuples, each containing the estimated cost and the corresponding parameters for that iteration. `cost` is a float, and `parameters` is a dictionary matching the execution parameter format.
366
366
 
367
367
  See Also:
368
- The [Classiq Tutorial](https://docs.classiq.io/latest/getting-started/classiq_tutorial/execution_tutorial_part2/) has examples on using this method in variational quantum algorithms.
368
+ The [Execution Tutorial](https://docs.classiq.io/latest/getting-started/classiq_tutorial/execution_tutorial_part2/) has examples on using this method in variational quantum algorithms.
369
369
  More information about [Hamiltonians](https://docs.classiq.io/latest/qmod-reference/language-reference/classical-types/#hamiltonians).
370
370
  """
371
371
  _hamiltonian_deprecation_warning(cost_function)
@@ -0,0 +1,13 @@
1
+ from classiq.execution.functions.expectation_value import _get_expectation_value
2
+ from classiq.execution.functions.minimize import _minimize
3
+ from classiq.execution.functions.sample import _new_sample
4
+ from classiq.execution.functions.state_vector import _calculate_state_vector
5
+ from classiq.execution.functions.util.constants import Verbosity
6
+
7
+ __all__ = [
8
+ "Verbosity",
9
+ "_calculate_state_vector",
10
+ "_get_expectation_value",
11
+ "_minimize",
12
+ "_new_sample",
13
+ ]
@@ -0,0 +1,106 @@
1
+ from typing import Any
2
+
3
+ from classiq.interface.backend.backend_preferences import (
4
+ BackendPreferencesTypes,
5
+ ClassiqBackendPreferences,
6
+ )
7
+ from classiq.interface.backend.provider_config.provider_config import ProviderConfig
8
+ from classiq.interface.backend.quantum_backend_providers import (
9
+ ClassiqSimulatorBackendNames,
10
+ )
11
+ from classiq.interface.executor.execution_preferences import ExecutionPreferences
12
+ from classiq.interface.generator.model.preferences import create_random_seed
13
+ from classiq.interface.generator.model.preferences.preferences import (
14
+ TranspilationOption,
15
+ )
16
+ from classiq.interface.hardware import Provider
17
+
18
+ from classiq import (
19
+ ExecutionParams,
20
+ QuantumProgram,
21
+ )
22
+ from classiq.execution.execution_session import ExecutionSession
23
+ from classiq.execution.functions.util._logging import _logger
24
+ from classiq.execution.functions.util.backend_preferences import (
25
+ _get_backend_preferences_from_specifier,
26
+ )
27
+ from classiq.execution.functions.util.constants import Verbosity
28
+ from classiq.execution.functions.util.parse_provider_backend import (
29
+ _parse_provider_backend,
30
+ )
31
+ from classiq.qmod.builtins.structs import SparsePauliOp
32
+
33
+ _DEFAULT_BACKEND_NAME = "simulator"
34
+
35
+
36
+ def _get_backend_preferences(
37
+ backend: str, estimate: bool, config: dict[str, Any] | ProviderConfig | None
38
+ ) -> BackendPreferencesTypes:
39
+ provider, backend_name = _parse_provider_backend(backend)
40
+ backend_preferences: BackendPreferencesTypes
41
+ if not estimate:
42
+ if not (
43
+ provider == Provider.CLASSIQ and backend_name.lower().strip() == "simulator"
44
+ ):
45
+ raise ValueError(
46
+ "Calculating exact expectation value is supported only for the 'classiq/simulator' backend"
47
+ )
48
+ backend_preferences = ClassiqBackendPreferences(
49
+ # This backend name is for exact simulation
50
+ backend_name=ClassiqSimulatorBackendNames.SIMULATOR_STATEVECTOR
51
+ )
52
+ else:
53
+ backend_preferences = _get_backend_preferences_from_specifier(
54
+ backend, config or {}
55
+ )
56
+ return backend_preferences
57
+
58
+
59
+ def _get_expectation_value(
60
+ qprog: QuantumProgram,
61
+ observable: SparsePauliOp,
62
+ backend: str | None = None,
63
+ *,
64
+ estimate: bool = True,
65
+ parameters: ExecutionParams | None = None,
66
+ config: dict[str, Any] | ProviderConfig | None = None,
67
+ num_shots: int | None = None,
68
+ random_seed: int | None = None,
69
+ transpilation_option: TranspilationOption = TranspilationOption.DECOMPOSE,
70
+ verbosity: Verbosity = Verbosity.INFO,
71
+ ) -> complex:
72
+ """
73
+ Get the expectation value of the observable O with respect to the state |psi>
74
+
75
+ Args:
76
+ qprog: The quantum program which generates the state |psi> to be observed
77
+ observable: The observable O
78
+ backend: The device (hardware or simulator) on which to run the quantum program. Specified as "provider/device_id". Use the `get_backend_details` function to see supported devices.
79
+ estimate: Whether to estimate the expectation value by repeatedly measuring the circuit, or else calculate the expectation value using a simulator.
80
+ parameters: The classical parameters for the quantum program
81
+ config: Provider-specific configuration, such as api keys
82
+ num_shots:
83
+ random_seed: The random seed used for transpilation and simulation
84
+ transpilation_option: Advanced configuration for hardware-specific transpilation
85
+ verbosity: What level of information should be logged
86
+
87
+ Returns: The expectation value
88
+ """
89
+ if backend is None:
90
+ backend = _DEFAULT_BACKEND_NAME
91
+ backend_preferences = _get_backend_preferences(backend, estimate, config)
92
+ ep = ExecutionPreferences(
93
+ backend_preferences=backend_preferences,
94
+ num_shots=num_shots,
95
+ random_seed=create_random_seed() if random_seed is None else random_seed,
96
+ transpile_to_hardware=transpilation_option,
97
+ )
98
+
99
+ if verbosity != Verbosity.QUIET:
100
+ _logger.info(f"Submitting job to {backend}")
101
+ with ExecutionSession(qprog, execution_preferences=ep) as session:
102
+ job = session.submit_estimate(hamiltonian=observable, parameters=parameters)
103
+ if verbosity != Verbosity.QUIET:
104
+ _logger.info(f"Job id: {job.id}")
105
+ result = job.get_estimate_result()
106
+ return result.value
@@ -0,0 +1,90 @@
1
+ from typing import Any
2
+
3
+ from classiq.interface.backend.provider_config.provider_config import ProviderConfig
4
+ from classiq.interface.executor.execution_preferences import ExecutionPreferences
5
+ from classiq.interface.generator.model.preferences import create_random_seed
6
+ from classiq.interface.generator.model.preferences.preferences import (
7
+ TranspilationOption,
8
+ )
9
+
10
+ from classiq import (
11
+ ExecutionParams,
12
+ QuantumProgram,
13
+ )
14
+ from classiq.execution.execution_session import ExecutionSession
15
+ from classiq.execution.functions.util._logging import _logger
16
+ from classiq.execution.functions.util.backend_preferences import (
17
+ _get_backend_preferences_from_specifier,
18
+ )
19
+ from classiq.execution.functions.util.constants import Verbosity
20
+ from classiq.qmod.builtins.structs import SparsePauliOp
21
+ from classiq.qmod.qmod_variable import QmodExpressionCreator
22
+
23
+ _DEFAULT_BACKEND_NAME = "simulator"
24
+
25
+
26
+ def _minimize(
27
+ qprog: QuantumProgram,
28
+ cost_function: SparsePauliOp | QmodExpressionCreator,
29
+ initial_params: ExecutionParams,
30
+ max_iteration: int,
31
+ backend: str | None = None,
32
+ *,
33
+ quantile: float = 1.0,
34
+ tolerance: float | None = None,
35
+ config: dict[str, Any] | ProviderConfig | None = None,
36
+ random_seed: int | None = None,
37
+ transpilation_option: TranspilationOption = TranspilationOption.DECOMPOSE,
38
+ verbosity: Verbosity = Verbosity.INFO,
39
+ ) -> list[tuple[float, ExecutionParams]]:
40
+ """
41
+ Minimize the given cost function using the quantum program.
42
+
43
+ Args:
44
+ qprog: The parametric quantum program that generates the state (ansatz).
45
+ Only quantum programs with exactly one execution parameter are supported.
46
+ cost_function: The cost function to minimize. It can be one of the following:
47
+ - A quantum cost function defined by a Hamiltonian.
48
+ - A classical cost function represented as a callable that returns a Qmod expression.
49
+ The callable should accept `QVar`s as arguments and use names matching the Model outputs.
50
+ initial_params: The initial parameters for the minimization.
51
+ This parameter must be of type `CReal` or `CArray`. The dictionary must contain a single key-value pair, where:
52
+ - The key is the name of the parameter.
53
+ - The value is either a float or a list of floats.
54
+ max_iteration: The maximum number of iterations for the minimization.
55
+ backend: The device (hardware or simulator) on which to run the quantum programs. Specified as "provider/device_id". Use the `get_backend_details` function to see supported devices.
56
+ quantile: The quantile to use for cost estimation.
57
+ tolerance: The tolerance for the minimization.
58
+ config: Provider-specific configuration, such as api keys
59
+ random_seed: Set this to increase determinism
60
+ transpilation_option: Advanced configuration for hardware-specific transpilation
61
+ verbosity: What level of information should be logged
62
+ Returns:
63
+ A list of tuples, each containing the estimated cost and the corresponding parameters for that iteration. `cost` is a float, and `parameters` is a dictionary matching the execution parameter format.
64
+
65
+ See Also:
66
+ The [Execution Tutorial](https://docs.classiq.io/latest/getting-started/classiq_tutorial/execution_tutorial_part2/) has examples on using this method in variational quantum algorithms.
67
+ More information about [Hamiltonians](https://docs.classiq.io/latest/qmod-reference/language-reference/classical-types/#hamiltonians).
68
+ """
69
+ if backend is None:
70
+ backend = _DEFAULT_BACKEND_NAME
71
+ backend_preferences = _get_backend_preferences_from_specifier(backend, config or {})
72
+
73
+ ep = ExecutionPreferences(
74
+ backend_preferences=backend_preferences,
75
+ random_seed=create_random_seed() if random_seed is None else random_seed,
76
+ transpile_to_hardware=transpilation_option,
77
+ )
78
+
79
+ if verbosity != Verbosity.QUIET:
80
+ _logger.info(f"Submitting job to {backend}")
81
+ with ExecutionSession(qprog, execution_preferences=ep) as session:
82
+ job = session.submit_minimize(
83
+ cost_function, initial_params, max_iteration, quantile, tolerance
84
+ )
85
+ if verbosity != Verbosity.QUIET:
86
+ _logger.info(f"Job id: {job.id}")
87
+ result = job.get_minimization_result()
88
+ return session._minimize_result_to_result(
89
+ result=result, initial_params=initial_params
90
+ )
@@ -0,0 +1,76 @@
1
+ from typing import TYPE_CHECKING, Any
2
+
3
+ from classiq.execution.functions.util.backend_preferences import (
4
+ _get_backend_preferences_from_specifier,
5
+ )
6
+
7
+ if TYPE_CHECKING:
8
+ from pandas import DataFrame
9
+
10
+ from classiq.interface.backend.provider_config.provider_config import ProviderConfig
11
+ from classiq.interface.executor.execution_preferences import ExecutionPreferences
12
+ from classiq.interface.generator.model.preferences import create_random_seed
13
+ from classiq.interface.generator.model.preferences.preferences import (
14
+ TranspilationOption,
15
+ )
16
+
17
+ from classiq import (
18
+ ExecutionParams,
19
+ QuantumProgram,
20
+ )
21
+ from classiq.execution import ExecutionSession
22
+ from classiq.execution.functions.util._logging import _logger
23
+ from classiq.execution.functions.util.constants import Verbosity
24
+
25
+ _DEFAULT_BACKEND_NAME = "simulator"
26
+
27
+
28
+ def _new_sample(
29
+ qprog: QuantumProgram,
30
+ backend: str | None = None,
31
+ *,
32
+ parameters: ExecutionParams | None = None,
33
+ config: dict[str, Any] | ProviderConfig | None = None,
34
+ num_shots: int | None = None,
35
+ random_seed: int | None = None,
36
+ transpilation_option: TranspilationOption = TranspilationOption.DECOMPOSE,
37
+ verbosity: Verbosity = Verbosity.INFO,
38
+ ) -> "DataFrame":
39
+ """
40
+ Sample a quantum program.
41
+
42
+ Args:
43
+ qprog: The quantum program
44
+ backend: The device (hardware or simulator) on which to run the quantum program. Specified as "provider/device_id". Use the `get_backend_details` function to see supported devices.
45
+ parameters: The classical parameters for the quantum program
46
+ config: Provider-specific configuration, such as api keys
47
+ num_shots: The number of times to sample
48
+ random_seed: The random seed used for transpilation and simulation
49
+ transpilation_option: Advanced configuration for hardware-specific transpilation
50
+ verbosity: What level of information should be logged
51
+
52
+ Returns: A dataframe containing the histogram
53
+ """
54
+ if num_shots is not None and num_shots < 1:
55
+ raise ValueError(f"Argument num_shots must be greater than 0, got {num_shots}")
56
+ if config is None:
57
+ config = {}
58
+ if backend is None:
59
+ backend = _DEFAULT_BACKEND_NAME
60
+ backend_preferences = _get_backend_preferences_from_specifier(backend, config)
61
+ ep = ExecutionPreferences(
62
+ backend_preferences=backend_preferences,
63
+ num_shots=num_shots,
64
+ random_seed=create_random_seed() if random_seed is None else random_seed,
65
+ transpile_to_hardware=transpilation_option,
66
+ )
67
+ if verbosity != Verbosity.QUIET:
68
+ _logger.info(f"Submitting job to {backend}")
69
+ with ExecutionSession(qprog, execution_preferences=ep) as session:
70
+ job = session.submit_sample(parameters)
71
+ if verbosity != Verbosity.QUIET:
72
+ _logger.info(f"Job id: {job.id}")
73
+ result = job.get_sample_result()
74
+
75
+ df = result.dataframe
76
+ return df
@@ -0,0 +1,113 @@
1
+ from typing import TYPE_CHECKING, Any
2
+
3
+ if TYPE_CHECKING:
4
+ from pandas import DataFrame
5
+
6
+ from classiq.interface.backend.backend_preferences import (
7
+ BackendPreferencesTypes,
8
+ ClassiqBackendPreferences,
9
+ GCPBackendPreferences,
10
+ )
11
+ from classiq.interface.backend.quantum_backend_providers import (
12
+ ClassiqNvidiaBackendNames,
13
+ ClassiqSimulatorBackendNames,
14
+ GoogleNvidiaBackendNames,
15
+ )
16
+ from classiq.interface.executor.execution_preferences import ExecutionPreferences
17
+ from classiq.interface.generator.model.preferences import create_random_seed
18
+ from classiq.interface.generator.model.preferences.preferences import (
19
+ TranspilationOption,
20
+ )
21
+ from classiq.interface.hardware import Provider
22
+
23
+ from classiq import (
24
+ ExecutionParams,
25
+ QuantumProgram,
26
+ )
27
+ from classiq.execution import ExecutionSession
28
+ from classiq.execution.functions.util._logging import _logger
29
+ from classiq.execution.functions.util.constants import Verbosity
30
+ from classiq.execution.functions.util.parse_provider_backend import (
31
+ _PROVIDER_TO_CANONICAL_NAME,
32
+ _parse_provider_backend,
33
+ )
34
+
35
+ _DEFAULT_STATE_VECTOR_BACKEND_NAME = "simulator"
36
+
37
+
38
+ def _calculate_state_vector(
39
+ qprog: QuantumProgram,
40
+ backend: str | None = None,
41
+ *,
42
+ parameters: ExecutionParams | None = None,
43
+ filters: dict[str, Any] | None = None,
44
+ random_seed: int | None = None,
45
+ transpilation_option: TranspilationOption = TranspilationOption.DECOMPOSE,
46
+ verbosity: Verbosity = Verbosity.INFO,
47
+ ) -> "DataFrame":
48
+ """
49
+ Calculate the state vector of a quantum program.
50
+
51
+ Args:
52
+ qprog: The quantum program
53
+ backend: The simulator on which to simulate the quantum program. Specified as "provider/device_id"
54
+ parameters: The classical parameters for the quantum program
55
+ filters: Only states where the variables match these values will be included in the state vector.
56
+ random_seed: The random seed used for transpilation and simulation
57
+ transpilation_option: Advanced configuration for hardware-specific transpilation
58
+ verbosity: What level of information should be logged
59
+
60
+ Returns: A dataframe containing the state vector
61
+ """
62
+ if backend is None:
63
+ backend = _DEFAULT_STATE_VECTOR_BACKEND_NAME
64
+
65
+ provider, raw_backend_name = _parse_provider_backend(backend)
66
+ backend_name_lower = raw_backend_name.lower()
67
+ backend_preferences: BackendPreferencesTypes
68
+
69
+ if provider == Provider.CLASSIQ:
70
+ if backend_name_lower == "simulator":
71
+ backend_name = str(ClassiqSimulatorBackendNames.SIMULATOR_STATEVECTOR)
72
+ elif backend_name_lower == "nvidia_simulator":
73
+ backend_name = str(ClassiqNvidiaBackendNames.SIMULATOR_STATEVECTOR)
74
+ else:
75
+ raise ValueError(
76
+ f"Unsupported backend '{backend}'. "
77
+ "Under the Classiq provider, only 'classiq/simulator' and 'classiq/nvidia_simulator' are supported."
78
+ )
79
+ backend_preferences = ClassiqBackendPreferences(backend_name=backend_name)
80
+ elif provider == Provider.GOOGLE:
81
+ if backend_name_lower == "cuquantum":
82
+ backend_name = str(GoogleNvidiaBackendNames.CUQUANTUM_STATEVECTOR)
83
+ else:
84
+ raise ValueError(
85
+ f"Unsupported backend '{backend}'. "
86
+ "Under the Google provider, only 'google/cuquantum' is supported."
87
+ )
88
+ backend_preferences = GCPBackendPreferences(backend_name=backend_name)
89
+ else:
90
+ raise ValueError(
91
+ f"Provider '{_PROVIDER_TO_CANONICAL_NAME.get(provider) or provider}' does not support this operation."
92
+ )
93
+
94
+ ep = ExecutionPreferences(
95
+ backend_preferences=backend_preferences,
96
+ random_seed=create_random_seed() if random_seed is None else random_seed,
97
+ transpile_to_hardware=transpilation_option,
98
+ )
99
+ if verbosity != Verbosity.QUIET:
100
+ _logger.info(f"Submitting job to {backend}")
101
+ with ExecutionSession(qprog, execution_preferences=ep) as session:
102
+ if filters is not None:
103
+ for output_name, value in filters.items():
104
+ session.set_measured_state_filter(
105
+ output_name, lambda state, val=value: state == val
106
+ )
107
+ job = session.submit_sample(parameters)
108
+ if verbosity != Verbosity.QUIET:
109
+ _logger.info(f"Job id: {job.id}")
110
+ result = job.get_sample_result()
111
+
112
+ df = result.dataframe
113
+ return df
File without changes
@@ -0,0 +1,19 @@
1
+ import logging
2
+
3
+ _logger = logging.getLogger(__name__)
4
+
5
+
6
+ def _setup_logging() -> None:
7
+ if _logger.handlers:
8
+ return
9
+
10
+ handler = logging.StreamHandler()
11
+ formatter = logging.Formatter("%(message)s")
12
+ handler.setFormatter(formatter)
13
+ _logger.addHandler(handler)
14
+ _logger.setLevel(logging.INFO)
15
+
16
+ _logger.propagate = False
17
+
18
+
19
+ _setup_logging()