qilisdk 0.1.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 (47) hide show
  1. qilisdk/__init__.py +47 -0
  2. qilisdk/__init__.pyi +30 -0
  3. qilisdk/_optionals.py +105 -0
  4. qilisdk/analog/__init__.py +17 -0
  5. qilisdk/analog/algorithms.py +111 -0
  6. qilisdk/analog/analog_backend.py +43 -0
  7. qilisdk/analog/analog_result.py +114 -0
  8. qilisdk/analog/exceptions.py +19 -0
  9. qilisdk/analog/hamiltonian.py +706 -0
  10. qilisdk/analog/quantum_objects.py +486 -0
  11. qilisdk/analog/schedule.py +311 -0
  12. qilisdk/common/__init__.py +20 -0
  13. qilisdk/common/algorithm.py +17 -0
  14. qilisdk/common/backend.py +16 -0
  15. qilisdk/common/model.py +16 -0
  16. qilisdk/common/optimizer.py +136 -0
  17. qilisdk/common/optimizer_result.py +110 -0
  18. qilisdk/common/result.py +17 -0
  19. qilisdk/digital/__init__.py +66 -0
  20. qilisdk/digital/ansatz.py +143 -0
  21. qilisdk/digital/circuit.py +106 -0
  22. qilisdk/digital/digital_algorithm.py +20 -0
  23. qilisdk/digital/digital_backend.py +90 -0
  24. qilisdk/digital/digital_result.py +145 -0
  25. qilisdk/digital/exceptions.py +31 -0
  26. qilisdk/digital/gates.py +989 -0
  27. qilisdk/digital/vqe.py +165 -0
  28. qilisdk/extras/__init__.py +13 -0
  29. qilisdk/extras/cuda/__init__.py +18 -0
  30. qilisdk/extras/cuda/cuda_analog_result.py +19 -0
  31. qilisdk/extras/cuda/cuda_backend.py +398 -0
  32. qilisdk/extras/cuda/cuda_digital_result.py +19 -0
  33. qilisdk/extras/qaas/__init__.py +13 -0
  34. qilisdk/extras/qaas/keyring.py +54 -0
  35. qilisdk/extras/qaas/models.py +57 -0
  36. qilisdk/extras/qaas/qaas_backend.py +154 -0
  37. qilisdk/extras/qaas/qaas_digital_result.py +20 -0
  38. qilisdk/extras/qaas/qaas_settings.py +23 -0
  39. qilisdk/py.typed +0 -0
  40. qilisdk/utils/__init__.py +27 -0
  41. qilisdk/utils/openqasm2.py +215 -0
  42. qilisdk/utils/serialization.py +128 -0
  43. qilisdk/yaml.py +71 -0
  44. qilisdk-0.1.0.dist-info/METADATA +237 -0
  45. qilisdk-0.1.0.dist-info/RECORD +47 -0
  46. qilisdk-0.1.0.dist-info/WHEEL +4 -0
  47. qilisdk-0.1.0.dist-info/licenses/LICENCE +201 -0
qilisdk/__init__.py ADDED
@@ -0,0 +1,47 @@
1
+ # Copyright 2025 Qilimanjaro Quantum Tech
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ import sys
16
+ from typing import List
17
+
18
+ from qilisdk.common import Algorithm, Model, Optimizer, Result
19
+
20
+ from ._optionals import ImportedFeature, OptionalFeature, Symbol, import_optional_dependencies
21
+
22
+ # Put your always-available, core symbols here
23
+ __all__ = ["Algorithm", "Model", "Optimizer", "Result"]
24
+
25
+ # Define your optional features
26
+ OPTIONAL_FEATURES: List[OptionalFeature] = [
27
+ OptionalFeature(
28
+ name="cuda-backend",
29
+ dependencies=["cudaq"],
30
+ symbols=[Symbol(path="qilisdk.extras.cuda.cuda_backend", name="CudaBackend")],
31
+ ),
32
+ OptionalFeature(
33
+ name="qaas",
34
+ dependencies=["httpx", "keyring", "pydantic", "pydantic-settings"],
35
+ symbols=[Symbol(path="qilisdk.extras.qaas.qaas_backend", name="QaaSBackend")],
36
+ ),
37
+ # Add more OptionalFeature() entries for other extras if needed
38
+ ]
39
+
40
+ current_module = sys.modules[__name__]
41
+
42
+ # Dynamically import (or stub) each feature's symbols and attach them
43
+ for feature in OPTIONAL_FEATURES:
44
+ imported_feature: ImportedFeature = import_optional_dependencies(feature)
45
+ for symbol_name, symbol_obj in imported_feature.symbols.items():
46
+ setattr(current_module, symbol_name, symbol_obj)
47
+ __all__ += [symbol_name] # noqa: PLE0604
qilisdk/__init__.pyi ADDED
@@ -0,0 +1,30 @@
1
+ # Copyright 2025 Qilimanjaro Quantum Tech
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ from qilisdk.analog import Hamiltonian
16
+ from qilisdk.common import Algorithm, Model, Optimizer, Result
17
+ from qilisdk.digital import DigitalSimulationMethod
18
+ from qilisdk.extras.cuda import CudaBackend
19
+ from qilisdk.extras.qaas.qaas_backend import QaaSBackend
20
+
21
+ __all__ = [
22
+ "Algorithm",
23
+ "CudaBackend",
24
+ "DigitalSimulationMethod",
25
+ "Hamiltonian",
26
+ "Model",
27
+ "Optimizer",
28
+ "QaaSBackend",
29
+ "Result",
30
+ ]
qilisdk/_optionals.py ADDED
@@ -0,0 +1,105 @@
1
+ # Copyright 2025 Qilimanjaro Quantum Tech
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ import importlib
16
+ import importlib.metadata
17
+ from dataclasses import dataclass
18
+ from typing import Any, Callable
19
+
20
+
21
+ class OptionalDependencyError(ImportError):
22
+ """Raised when an optional dependency is missing, with a custom message."""
23
+
24
+
25
+ @dataclass(frozen=True)
26
+ class Symbol:
27
+ path: str
28
+ name: str
29
+
30
+
31
+ @dataclass(frozen=True)
32
+ class OptionalFeature:
33
+ """Holds metadata about an optional feature.
34
+
35
+ Attributes:
36
+ feature_name (str):
37
+ The name of the extras group in pyproject.toml
38
+ distributions (list[str]):
39
+ The PyPI distribution names that must be installed
40
+ import_path (str):
41
+ The Python import path to the module containing the real symbols
42
+ symbols (list[str]):
43
+ Which symbols (classes, functions, etc.) to re-export
44
+ """
45
+
46
+ name: str
47
+ dependencies: list[str]
48
+ symbols: list[Symbol]
49
+
50
+
51
+ @dataclass
52
+ class ImportedFeature:
53
+ """Holds the result of an optional import.
54
+
55
+ Attributes:
56
+ feature_name (str):
57
+ A label for the feature (e.g. 'qibo-backend').
58
+ symbol_map (dict[str, Union[Any, Callable]]):
59
+ A mapping from symbol name to the real or stubbed object.
60
+ If the required dependency is missing, the symbol is a stub
61
+ that raises an error when called.
62
+ """
63
+
64
+ name: str
65
+ symbols: dict[str, Any | Callable]
66
+
67
+
68
+ def import_optional_dependencies(feature: OptionalFeature) -> ImportedFeature:
69
+ """Tries to import a submodule at `feature.import_path` along with the required
70
+ distributions. If successful, returns a dict mapping each symbol to the
71
+ actual imported symbol. Otherwise returns stubs that raise an error on usage.
72
+
73
+ Args:
74
+ feature (OptionalFeature): An OptionalFeature instance describing the optional group
75
+
76
+ Returns:
77
+ Dict[str, Union[Any, Callable]]: A dict { symbol_name: symbol_or_stub }
78
+ """
79
+ missing: list[str] = []
80
+ for dist in feature.dependencies:
81
+ try:
82
+ importlib.metadata.version(dist)
83
+ except importlib.metadata.PackageNotFoundError:
84
+ missing.append(dist)
85
+
86
+ if missing:
87
+ # Build stubs that raise a helpful error
88
+ def make_stub(symbol_name: str) -> Callable:
89
+ def _stub(*args: Any, **kwargs: Any) -> None:
90
+ raise OptionalDependencyError(
91
+ f"Using {symbol_name} requires installing the '{feature.name}' optional feature: `pip install qilisdk[{feature.name}]`\n"
92
+ )
93
+
94
+ _stub.__name__ = symbol_name
95
+ return _stub
96
+
97
+ stubs = {symbol.name: make_stub(symbol.name) for symbol in feature.symbols}
98
+ return ImportedFeature(name=feature.name, symbols=stubs)
99
+
100
+ # All dependencies are present => import the real module
101
+ symbols = {}
102
+ for symbol in feature.symbols:
103
+ module = importlib.import_module(symbol.path)
104
+ symbols[symbol.name] = getattr(module, symbol.name)
105
+ return ImportedFeature(name=feature.name, symbols=symbols)
@@ -0,0 +1,17 @@
1
+ # Copyright 2025 Qilimanjaro Quantum Tech
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ from .hamiltonian import Hamiltonian, I, X, Y, Z
16
+
17
+ __all__ = ["Hamiltonian", "I", "X", "Y", "Z"]
@@ -0,0 +1,111 @@
1
+ # Copyright 2025 Qilimanjaro Quantum Tech
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ from abc import abstractmethod
15
+
16
+ from qilisdk.analog.analog_backend import AnalogBackend
17
+ from qilisdk.analog.analog_result import AnalogResult
18
+ from qilisdk.analog.hamiltonian import Hamiltonian, PauliOperator
19
+ from qilisdk.analog.quantum_objects import QuantumObject
20
+ from qilisdk.analog.schedule import Schedule
21
+ from qilisdk.common.algorithm import Algorithm
22
+ from qilisdk.yaml import yaml
23
+
24
+ Complex = int | float | complex
25
+
26
+
27
+ @yaml.register_class
28
+ class AnalogAlgorithm(Algorithm):
29
+ """
30
+ Abstract base class for analog quantum algorithms.
31
+
32
+ This class provides the foundational interface for analog quantum algorithms
33
+ that simulate the dynamics of quantum systems. It holds a reference to an
34
+ AnalogBackend instance responsible for executing quantum operations. Subclasses
35
+ must implement the evolve() method to perform the algorithm-specific simulation
36
+ and return an AnalogResult.
37
+
38
+ Attributes:
39
+ backend (AnalogBackend): The backend instance used to execute the quantum
40
+ simulation operations.
41
+ """
42
+
43
+ @abstractmethod
44
+ def evolve(self, backend: AnalogBackend, store_intermediate_results: bool = False) -> AnalogResult:
45
+ """
46
+ Execute the analog quantum algorithm's evolution process.
47
+
48
+ This abstract method defines the interface for simulating the time evolution
49
+ of a quantum system. Subclasses must implement this method to perform the
50
+ simulation using the provided backend, and to return the simulation results
51
+ encapsulated in an AnalogResult object.
52
+
53
+ Args:
54
+ store_intermediate_results (bool, optional): If True, the algorithm should
55
+ store and include intermediate results during the simulation. Defaults to False.
56
+
57
+ Returns:
58
+ AnalogResult: The result of the simulation, which includes the final state,
59
+ measured observables, and any intermediate data if requested.
60
+ """
61
+
62
+
63
+ @yaml.register_class
64
+ class TimeEvolution(AnalogAlgorithm):
65
+ def __init__(
66
+ self,
67
+ schedule: Schedule,
68
+ observables: list[PauliOperator | Hamiltonian],
69
+ initial_state: QuantumObject,
70
+ n_shots: int = 1000,
71
+ ) -> None:
72
+ """
73
+ Initialize the TimeEvolution simulation.
74
+
75
+ Args:
76
+ backend (AnalogBackend): The backend to use for simulating the dynamics.
77
+ schedule (Schedule): The evolution schedule defining the time-dependent Hamiltonian.
78
+ observables (list[PauliOperator | Hamiltonian]): A list of observables to measure at the end of the evolution.
79
+ initial_state (QuantumObject): The initial quantum state from which the simulation starts.
80
+ n_shots (int, optional): The number of simulation repetitions (shots). Defaults to 1000.
81
+ """
82
+ super().__init__()
83
+ self.initial_state = initial_state
84
+ self.schedule = schedule
85
+ self.observables = observables
86
+ self.n_shots = n_shots
87
+
88
+ def evolve(self, backend: AnalogBackend, store_intermediate_results: bool = False) -> AnalogResult:
89
+ """
90
+ Execute the time evolution algorithm.
91
+
92
+ This method performs the quantum dynamics evolution according to
93
+ the provided schedule, initial state, and observables. The computation
94
+ is delegated to the configured backend, which may optionally store
95
+ intermediate results during the evolution.
96
+
97
+ Args:
98
+ store_intermediate_results (bool, optional): If True, the algorithm
99
+ will store intermediate results during the time evolution.
100
+ Defaults to False.
101
+
102
+ Returns:
103
+ AnalogResult: The result of the evolution, including the final state
104
+ and measured observables (and intermediate results if requested).
105
+ """
106
+ return backend.evolve(
107
+ schedule=self.schedule,
108
+ initial_state=self.initial_state,
109
+ observables=self.observables,
110
+ store_intermediate_results=store_intermediate_results,
111
+ )
@@ -0,0 +1,43 @@
1
+ # Copyright 2025 Qilimanjaro Quantum Tech
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ from abc import abstractmethod
15
+
16
+ from qilisdk.analog.analog_result import AnalogResult
17
+ from qilisdk.analog.hamiltonian import Hamiltonian, PauliOperator
18
+ from qilisdk.analog.quantum_objects import QuantumObject
19
+ from qilisdk.analog.schedule import Schedule
20
+ from qilisdk.common.backend import Backend
21
+
22
+
23
+ class AnalogBackend(Backend):
24
+ @abstractmethod
25
+ def evolve(
26
+ self,
27
+ schedule: Schedule,
28
+ initial_state: QuantumObject,
29
+ observables: list[PauliOperator | Hamiltonian],
30
+ store_intermediate_results: bool = False,
31
+ ) -> AnalogResult:
32
+ """
33
+ Computes the time evolution under of an initial state under the given schedule.
34
+
35
+ Args:
36
+ schedule (Schedule): The evolution schedule of the system.
37
+ initial_state (QuantumObject): the initial state of the evolution.
38
+ observables (list[PauliOperator | Hamiltonian]): the list of observables to be measured at the end of the evolution.
39
+ store_intermediate_results (bool): A flag to store the intermediate results along the evolution.
40
+
41
+ Returns:
42
+ AnalogResult: The results of the evolution.
43
+ """
@@ -0,0 +1,114 @@
1
+ # Copyright 2025 Qilimanjaro Quantum Tech
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ from pprint import pformat
15
+
16
+ import numpy as np
17
+
18
+ from qilisdk.analog.quantum_objects import QuantumObject
19
+ from qilisdk.common import Result
20
+ from qilisdk.yaml import yaml
21
+
22
+
23
+ @yaml.register_class
24
+ class AnalogResult(Result):
25
+ """
26
+ Encapsulates the outcome of an analog quantum simulation.
27
+
28
+ This result class stores key outputs from the simulation, including the
29
+ final expected measurement values, the complete time-evolution of expectation
30
+ values (if available), the final quantum state, and any intermediate quantum states.
31
+
32
+ Attributes:
33
+ _final_expected_values (np.ndarray): The final expectation values measured at the end of the simulation.
34
+ _expected_values (np.ndarray): The time-series of expectation values recorded during the simulation.
35
+ _final_state (QuantumObject | None): The final quantum state resulting from the simulation.
36
+ _intermediate_states (list[QuantumObject] | None): A list of intermediate quantum states obtained during evolution.
37
+ """
38
+
39
+ def __init__(
40
+ self,
41
+ final_expected_values: np.ndarray | None = None,
42
+ expected_values: np.ndarray | None = None,
43
+ final_state: QuantumObject | None = None,
44
+ intermediate_states: list[QuantumObject] | None = None,
45
+ ) -> None:
46
+ """
47
+ Initialize an AnalogResult instance with simulation outputs.
48
+
49
+ Args:
50
+ final_expected_values (np.ndarray | None, optional): An array of the final expectation
51
+ values measured at the end of the simulation. Defaults to an empty array if None.
52
+ expected_values (np.ndarray | None, optional): An array containing the evolution of
53
+ expectation values during the simulation. Defaults to an empty array if None.
54
+ final_state (QuantumObject | None, optional): The final quantum state as a QuantumObject.
55
+ Defaults to None.
56
+ intermediate_states (list[QuantumObject] | None, optional): A list of QuantumObjects representing
57
+ the intermediate states during the simulation. Defaults to None.
58
+ """
59
+ super().__init__()
60
+ self._final_expected_values = final_expected_values if final_expected_values is not None else np.array([])
61
+ self._expected_values = expected_values if expected_values is not None else np.array([])
62
+ self._final_state = final_state
63
+ self._intermediate_states = intermediate_states
64
+
65
+ @property
66
+ def final_expected_values(self) -> np.ndarray:
67
+ """
68
+ Get the final expectation values measured at the end of the simulation.
69
+
70
+ Returns:
71
+ np.ndarray: An array of the final expected values.
72
+ """
73
+ return self._final_expected_values
74
+
75
+ @property
76
+ def expected_values(self) -> np.ndarray:
77
+ """
78
+ Get the evolution of expectation values recorded during the simulation.
79
+
80
+ Returns:
81
+ np.ndarray: An array of expectation values over the course of the simulation.
82
+ """
83
+ return self._expected_values
84
+
85
+ @property
86
+ def final_state(self) -> QuantumObject | None:
87
+ """
88
+ Get the final quantum state produced by the simulation.
89
+
90
+ Returns:
91
+ QuantumObject | None: The final quantum state, or None if not available.
92
+ """
93
+ return self._final_state
94
+
95
+ @property
96
+ def intermediate_states(self) -> list[QuantumObject] | None:
97
+ """
98
+ Get the list of intermediate quantum states recorded during the simulation.
99
+
100
+ Returns:
101
+ list[QuantumObject] | None: A list of intermediate quantum states, or None if not stored.
102
+ """
103
+ return self._intermediate_states
104
+
105
+ def __repr__(self) -> str:
106
+ class_name = self.__class__.__name__
107
+ return (
108
+ f"{class_name}(\n"
109
+ f" final_expected_values={pformat(self.final_expected_values)},\n"
110
+ f" expected_values={pformat(self.expected_values)}\n"
111
+ f" final_state={pformat(self.final_state)}\n"
112
+ f" intermediate_states={pformat(self.intermediate_states)}\n"
113
+ ")"
114
+ )
@@ -0,0 +1,19 @@
1
+ # Copyright 2025 Qilimanjaro Quantum Tech
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+
16
+ class InvalidHamiltonianOperation(Exception): ...
17
+
18
+
19
+ class NotSupportedOperation(Exception): ...