qilisdk 0.1.4__py3-none-any.whl → 0.1.5__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.
- qilisdk/__init__.py +11 -2
- qilisdk/__init__.pyi +2 -3
- qilisdk/_logging.py +135 -0
- qilisdk/_optionals.py +5 -7
- qilisdk/analog/__init__.py +3 -18
- qilisdk/analog/exceptions.py +2 -4
- qilisdk/analog/hamiltonian.py +455 -110
- qilisdk/analog/linear_schedule.py +118 -0
- qilisdk/analog/schedule.py +272 -79
- qilisdk/backends/__init__.py +45 -0
- qilisdk/{digital/digital_algorithm.py → backends/__init__.pyi} +3 -5
- qilisdk/backends/backend.py +117 -0
- qilisdk/{extras/cuda → backends}/cuda_backend.py +152 -159
- qilisdk/backends/qutip_backend.py +492 -0
- qilisdk/common/__init__.py +48 -2
- qilisdk/common/algorithm.py +2 -1
- qilisdk/{extras/qaas/qaas_settings.py → common/exceptions.py} +12 -6
- qilisdk/common/model.py +1019 -1
- qilisdk/common/parameterizable.py +75 -0
- qilisdk/common/qtensor.py +666 -0
- qilisdk/common/result.py +2 -1
- qilisdk/common/variables.py +1931 -0
- qilisdk/{extras/cuda/cuda_analog_result.py → cost_functions/__init__.py} +3 -4
- qilisdk/cost_functions/cost_function.py +77 -0
- qilisdk/cost_functions/model_cost_function.py +145 -0
- qilisdk/cost_functions/observable_cost_function.py +109 -0
- qilisdk/digital/__init__.py +3 -22
- qilisdk/digital/ansatz.py +203 -160
- qilisdk/digital/circuit.py +81 -9
- qilisdk/digital/exceptions.py +12 -6
- qilisdk/digital/gates.py +228 -85
- qilisdk/{extras/qaas/qaas_analog_result.py → functionals/__init__.py} +14 -5
- qilisdk/functionals/functional.py +39 -0
- qilisdk/{extras/cuda/cuda_digital_result.py → functionals/functional_result.py} +3 -4
- qilisdk/functionals/sampling.py +81 -0
- qilisdk/functionals/sampling_result.py +92 -0
- qilisdk/functionals/time_evolution.py +98 -0
- qilisdk/functionals/time_evolution_result.py +84 -0
- qilisdk/functionals/variational_program.py +80 -0
- qilisdk/functionals/variational_program_result.py +69 -0
- qilisdk/logging_config.yaml +16 -0
- qilisdk/{common/backend.py → optimizers/__init__.py} +2 -1
- qilisdk/optimizers/optimizer.py +39 -0
- qilisdk/{common → optimizers}/optimizer_result.py +3 -12
- qilisdk/{common/optimizer.py → optimizers/scipy_optimizer.py} +10 -28
- qilisdk/settings.py +78 -0
- qilisdk/{extras → speqtrum}/__init__.py +7 -8
- qilisdk/{extras → speqtrum}/__init__.pyi +3 -3
- qilisdk/speqtrum/experiments/__init__.py +25 -0
- qilisdk/speqtrum/experiments/experiment_functional.py +124 -0
- qilisdk/speqtrum/experiments/experiment_result.py +231 -0
- qilisdk/{extras/qaas → speqtrum}/keyring.py +8 -4
- qilisdk/speqtrum/speqtrum.py +432 -0
- qilisdk/speqtrum/speqtrum_models.py +300 -0
- qilisdk/utils/__init__.py +0 -14
- qilisdk/utils/openqasm2.py +1 -1
- qilisdk/utils/serialization.py +1 -1
- qilisdk/utils/visualization/PlusJakartaSans-SemiBold.ttf +0 -0
- qilisdk/utils/visualization/__init__.py +24 -0
- qilisdk/utils/visualization/circuit_renderers.py +781 -0
- qilisdk/utils/visualization/schedule_renderers.py +161 -0
- qilisdk/utils/visualization/style.py +154 -0
- qilisdk/utils/visualization/themes.py +76 -0
- qilisdk/yaml.py +126 -0
- {qilisdk-0.1.4.dist-info → qilisdk-0.1.5.dist-info}/METADATA +180 -134
- qilisdk-0.1.5.dist-info/RECORD +69 -0
- qilisdk/analog/algorithms.py +0 -111
- qilisdk/analog/analog_backend.py +0 -43
- qilisdk/analog/analog_result.py +0 -114
- qilisdk/analog/quantum_objects.py +0 -596
- qilisdk/digital/digital_backend.py +0 -90
- qilisdk/digital/digital_result.py +0 -145
- qilisdk/digital/vqe.py +0 -166
- qilisdk/extras/cuda/__init__.py +0 -13
- qilisdk/extras/qaas/__init__.py +0 -13
- qilisdk/extras/qaas/models.py +0 -132
- qilisdk/extras/qaas/qaas_backend.py +0 -255
- qilisdk/extras/qaas/qaas_digital_result.py +0 -20
- qilisdk/extras/qaas/qaas_time_evolution_result.py +0 -20
- qilisdk/extras/qaas/qaas_vqe_result.py +0 -20
- qilisdk-0.1.4.dist-info/RECORD +0 -51
- {qilisdk-0.1.4.dist-info → qilisdk-0.1.5.dist-info}/WHEEL +0 -0
- {qilisdk-0.1.4.dist-info → qilisdk-0.1.5.dist-info}/licenses/LICENCE +0 -0
qilisdk/digital/ansatz.py
CHANGED
|
@@ -1,160 +1,203 @@
|
|
|
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 ABC
|
|
15
|
-
from typing import
|
|
16
|
-
|
|
17
|
-
from qilisdk.digital.circuit import Circuit
|
|
18
|
-
from qilisdk.digital.gates import CNOT, CZ, U1, U2, U3
|
|
19
|
-
from qilisdk.yaml import yaml
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
"
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
self.
|
|
95
|
-
self.
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
return
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
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 ABC
|
|
15
|
+
from typing import Iterator, Literal, Type
|
|
16
|
+
|
|
17
|
+
from qilisdk.digital.circuit import Circuit
|
|
18
|
+
from qilisdk.digital.gates import CNOT, CZ, U1, U2, U3
|
|
19
|
+
from qilisdk.yaml import yaml
|
|
20
|
+
|
|
21
|
+
Connectivity = Literal["circular", "linear", "full"] | list[tuple[int, int]]
|
|
22
|
+
Structure = Literal["grouped", "interposed"]
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class Ansatz(Circuit, ABC):
|
|
26
|
+
"""Abstract template for parameterised digital circuits."""
|
|
27
|
+
|
|
28
|
+
def __init__(self, nqubits: int) -> None:
|
|
29
|
+
"""
|
|
30
|
+
Args:
|
|
31
|
+
nqubits (int): Number of logical qubits in the circuit.
|
|
32
|
+
"""
|
|
33
|
+
super().__init__(nqubits=nqubits)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@yaml.register_class
|
|
37
|
+
class HardwareEfficientAnsatz(Ansatz):
|
|
38
|
+
"""
|
|
39
|
+
Hardware-efficient ansatz with `(layers + 1)` single-qubit blocks and ``layers``
|
|
40
|
+
entangling blocks.
|
|
41
|
+
|
|
42
|
+
Example:
|
|
43
|
+
.. code-block:: python
|
|
44
|
+
|
|
45
|
+
from qilisdk.digital.ansatz import HardwareEfficientAnsatz
|
|
46
|
+
from qilisdk.digital.gates import U3, CNOT
|
|
47
|
+
|
|
48
|
+
ansatz = HardwareEfficientAnsatz(
|
|
49
|
+
nqubits=4,
|
|
50
|
+
layers=3,
|
|
51
|
+
connectivity="linear",
|
|
52
|
+
structure="grouped",
|
|
53
|
+
one_qubit_gate=U3,
|
|
54
|
+
two_qubit_gate=CNOT,
|
|
55
|
+
)
|
|
56
|
+
ansatz.draw()
|
|
57
|
+
|
|
58
|
+
Notes:
|
|
59
|
+
``structure="grouped"`` applies full single-qubit layers followed by entanglers,
|
|
60
|
+
while ``structure="interposed"`` alternates single-qubit updates with entanglers
|
|
61
|
+
per qubit. No measurements are added automatically.
|
|
62
|
+
"""
|
|
63
|
+
|
|
64
|
+
def __init__(
|
|
65
|
+
self,
|
|
66
|
+
nqubits: int,
|
|
67
|
+
layers: int = 1,
|
|
68
|
+
connectivity: Connectivity = "linear",
|
|
69
|
+
structure: Structure = "grouped",
|
|
70
|
+
one_qubit_gate: Type[U1 | U2 | U3] = U1,
|
|
71
|
+
two_qubit_gate: Type[CZ | CNOT] = CZ,
|
|
72
|
+
) -> None:
|
|
73
|
+
"""
|
|
74
|
+
Args:
|
|
75
|
+
nqubits (int): Number of qubits in the circuit.
|
|
76
|
+
layers (int, optional): Number of entangling layers. Defaults to 1.
|
|
77
|
+
connectivity (Connectivity, optional): Topology used for two-qubit gates.
|
|
78
|
+
Accepts ``"linear"``, ``"circular"``, ``"full"``, or an explicit list of edges.
|
|
79
|
+
Defaults to ``"linear"``.
|
|
80
|
+
structure (Structure, optional): Layout of single- and two-qubit gates within each layer.
|
|
81
|
+
``"grouped"`` applies all single-qubit gates before the entangler block; ``"interposed"``
|
|
82
|
+
interleaves them per qubit. Defaults to ``"grouped"``.
|
|
83
|
+
one_qubit_gate (Type[U1 | U2 | U3], optional): Parameterised single-qubit gate class. Defaults to :class:`U1`.
|
|
84
|
+
two_qubit_gate (Type[CZ | CNOT], optional): Entangling gate class. Defaults to :class:`CZ`.
|
|
85
|
+
|
|
86
|
+
Raises:
|
|
87
|
+
ValueError: If ``layers`` is negative or the connectivity definition is invalid.
|
|
88
|
+
"""
|
|
89
|
+
super().__init__(nqubits)
|
|
90
|
+
|
|
91
|
+
if layers < 0:
|
|
92
|
+
raise ValueError("layers must be >= 0")
|
|
93
|
+
|
|
94
|
+
self._layers = int(layers)
|
|
95
|
+
self._connectivity = tuple(self._normalize_connectivity(connectivity))
|
|
96
|
+
self._structure: Structure = "grouped" if structure.lower() == "grouped" else "interposed"
|
|
97
|
+
self._one_qubit_gate: type[U1 | U2 | U3] = one_qubit_gate
|
|
98
|
+
self._two_qubit_gate: type[CZ | CNOT] = two_qubit_gate
|
|
99
|
+
|
|
100
|
+
self._build_circuit()
|
|
101
|
+
|
|
102
|
+
@property
|
|
103
|
+
def layers(self) -> int:
|
|
104
|
+
"""Number of entangling layers."""
|
|
105
|
+
return self._layers
|
|
106
|
+
|
|
107
|
+
@property
|
|
108
|
+
def connectivity(self) -> tuple[tuple[int, int], ...]:
|
|
109
|
+
"""Entangling edges as an immutable tuple of (control, target) pairs."""
|
|
110
|
+
return self._connectivity
|
|
111
|
+
|
|
112
|
+
@property
|
|
113
|
+
def structure(self) -> Structure:
|
|
114
|
+
"""Declared structure ('grouped' or 'interposed')."""
|
|
115
|
+
return self._structure
|
|
116
|
+
|
|
117
|
+
@property
|
|
118
|
+
def one_qubit_gate(self) -> type[U1 | U2 | U3]:
|
|
119
|
+
"""Single-qubit gate class used for parameterized layers (U1, U2, or U3)."""
|
|
120
|
+
return self._one_qubit_gate
|
|
121
|
+
|
|
122
|
+
@property
|
|
123
|
+
def two_qubit_gate(self) -> type[CZ | CNOT]:
|
|
124
|
+
"""Two-qubit entangling gate class (CZ or CNOT)."""
|
|
125
|
+
return self._two_qubit_gate
|
|
126
|
+
|
|
127
|
+
def _normalize_connectivity(self, connectivity: Connectivity) -> list[tuple[int, int]]:
|
|
128
|
+
"""
|
|
129
|
+
Returns:
|
|
130
|
+
list[tuple[int, int]]: a validated list of entangling edges derived from ``connectivity``.
|
|
131
|
+
|
|
132
|
+
Raises:
|
|
133
|
+
ValueError: If ``connectivity`` is invalid.
|
|
134
|
+
"""
|
|
135
|
+
if isinstance(connectivity, list):
|
|
136
|
+
edges = connectivity
|
|
137
|
+
else:
|
|
138
|
+
kind = connectivity.lower()
|
|
139
|
+
if kind == "full":
|
|
140
|
+
edges = [(i, j) for i in range(self.nqubits) for j in range(i + 1, self.nqubits)]
|
|
141
|
+
elif kind == "circular":
|
|
142
|
+
edges = (
|
|
143
|
+
[]
|
|
144
|
+
if self.nqubits < 2 # noqa: PLR2004
|
|
145
|
+
else [(i, i + 1) for i in range(self.nqubits - 1)] + [(self.nqubits - 1, 0)]
|
|
146
|
+
)
|
|
147
|
+
elif kind == "linear":
|
|
148
|
+
edges = [(i, i + 1) for i in range(self.nqubits - 1)]
|
|
149
|
+
else:
|
|
150
|
+
raise ValueError(f"Unrecognized connectivity: {connectivity!r}")
|
|
151
|
+
|
|
152
|
+
# basic validation
|
|
153
|
+
for a, b in edges:
|
|
154
|
+
if not (0 <= a < self.nqubits and 0 <= b < self.nqubits):
|
|
155
|
+
raise ValueError(f"Edge {(a, b)} out of range for {self.nqubits} qubits.")
|
|
156
|
+
if a == b:
|
|
157
|
+
raise ValueError(f"Self-edge {(a, b)} is not allowed.")
|
|
158
|
+
return edges
|
|
159
|
+
|
|
160
|
+
def _parameter_blocks(self) -> Iterator[dict[str, float]]:
|
|
161
|
+
"""Yield dictionaries initialised for each parameterised single-qubit gate in build order."""
|
|
162
|
+
names = tuple(self.one_qubit_gate.PARAMETER_NAMES)
|
|
163
|
+
blocks = (self.layers + 1) * self.nqubits
|
|
164
|
+
|
|
165
|
+
zero = dict.fromkeys(names, 0.0)
|
|
166
|
+
for _ in range(blocks):
|
|
167
|
+
# fresh dict each time
|
|
168
|
+
yield dict(zero)
|
|
169
|
+
|
|
170
|
+
def _apply_single_qubit(self, qubit: int, parameter_iterator: Iterator[dict[str, float]]) -> None:
|
|
171
|
+
"""Apply one parameterised single-qubit gate to ``qubit`` using the next parameter block."""
|
|
172
|
+
params = next(parameter_iterator)
|
|
173
|
+
self.add(self.one_qubit_gate(qubit, **params))
|
|
174
|
+
|
|
175
|
+
def _apply_single_qubit_block(self, parameter_iterator: Iterator[dict[str, float]]) -> None:
|
|
176
|
+
"""Apply a parameterised gate to every qubit using successive parameter blocks."""
|
|
177
|
+
for qubit in range(self.nqubits):
|
|
178
|
+
params = next(parameter_iterator)
|
|
179
|
+
self.add(self.one_qubit_gate(qubit, **params))
|
|
180
|
+
|
|
181
|
+
def _apply_entanglers(self) -> None:
|
|
182
|
+
"""Append the entangling block across all connectivity edges."""
|
|
183
|
+
for i, j in self.connectivity:
|
|
184
|
+
self.add(self.two_qubit_gate(i, j))
|
|
185
|
+
|
|
186
|
+
def _build_circuit(self) -> None:
|
|
187
|
+
"""Populate the circuit according to the current structure and connectivity settings."""
|
|
188
|
+
# Parameter iterator covering all single-qubit blocks, in order
|
|
189
|
+
parameter_iterator = iter(self._parameter_blocks())
|
|
190
|
+
|
|
191
|
+
# U(0)
|
|
192
|
+
self._apply_single_qubit_block(parameter_iterator)
|
|
193
|
+
|
|
194
|
+
# For each remaining layer: U -> E
|
|
195
|
+
if self.structure == "grouped":
|
|
196
|
+
for _ in range(self.layers):
|
|
197
|
+
self._apply_single_qubit_block(parameter_iterator)
|
|
198
|
+
self._apply_entanglers()
|
|
199
|
+
else:
|
|
200
|
+
for _ in range(self.layers):
|
|
201
|
+
for q in range(self.nqubits):
|
|
202
|
+
self._apply_single_qubit(q, parameter_iterator)
|
|
203
|
+
self._apply_entanglers()
|
qilisdk/digital/circuit.py
CHANGED
|
@@ -11,8 +11,12 @@
|
|
|
11
11
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
|
+
|
|
14
15
|
import numpy as np
|
|
15
16
|
|
|
17
|
+
from qilisdk.common.parameterizable import Parameterizable
|
|
18
|
+
from qilisdk.common.variables import Parameter, RealNumber
|
|
19
|
+
from qilisdk.utils.visualization import CircuitStyle
|
|
16
20
|
from qilisdk.yaml import yaml
|
|
17
21
|
|
|
18
22
|
from .exceptions import ParametersNotEqualError, QubitOutOfRangeError
|
|
@@ -20,7 +24,7 @@ from .gates import Gate
|
|
|
20
24
|
|
|
21
25
|
|
|
22
26
|
@yaml.register_class
|
|
23
|
-
class Circuit:
|
|
27
|
+
class Circuit(Parameterizable):
|
|
24
28
|
def __init__(self, nqubits: int) -> None:
|
|
25
29
|
"""
|
|
26
30
|
Initialize a Circuit instance with a specified number of qubits.
|
|
@@ -31,7 +35,7 @@ class Circuit:
|
|
|
31
35
|
self._nqubits: int = nqubits
|
|
32
36
|
self._gates: list[Gate] = []
|
|
33
37
|
self._init_state: np.ndarray = np.zeros(nqubits)
|
|
34
|
-
self.
|
|
38
|
+
self._parameters: dict[str, Parameter] = {}
|
|
35
39
|
|
|
36
40
|
@property
|
|
37
41
|
def nqubits(self) -> int:
|
|
@@ -51,7 +55,7 @@ class Circuit:
|
|
|
51
55
|
Returns:
|
|
52
56
|
int: The total count of parameters from all parameterized gates.
|
|
53
57
|
"""
|
|
54
|
-
return len(
|
|
58
|
+
return len(self._parameters)
|
|
55
59
|
|
|
56
60
|
@property
|
|
57
61
|
def gates(self) -> list[Gate]:
|
|
@@ -70,7 +74,25 @@ class Circuit:
|
|
|
70
74
|
Returns:
|
|
71
75
|
list[float]: A list of parameter values from each parameterized gate.
|
|
72
76
|
"""
|
|
73
|
-
return [value for
|
|
77
|
+
return [param.value for param in self._parameters.values()]
|
|
78
|
+
|
|
79
|
+
def get_parameter_names(self) -> list[str]:
|
|
80
|
+
"""
|
|
81
|
+
Retrieve the parameter values from all parameterized gates in the circuit.
|
|
82
|
+
|
|
83
|
+
Returns:
|
|
84
|
+
list[float]: A list of parameter values from each parameterized gate.
|
|
85
|
+
"""
|
|
86
|
+
return list(self._parameters.keys())
|
|
87
|
+
|
|
88
|
+
def get_parameters(self) -> dict[str, float]:
|
|
89
|
+
"""
|
|
90
|
+
Retrieve the parameter names and values from all parameterized gates in the circuit.
|
|
91
|
+
|
|
92
|
+
Returns:
|
|
93
|
+
dict[str, float]: A dictionary of the parameters with their current values.
|
|
94
|
+
"""
|
|
95
|
+
return {label: param.value for label, param in self._parameters.items()}
|
|
74
96
|
|
|
75
97
|
def set_parameter_values(self, values: list[float]) -> None:
|
|
76
98
|
"""
|
|
@@ -84,10 +106,33 @@ class Circuit:
|
|
|
84
106
|
"""
|
|
85
107
|
if len(values) != self.nparameters:
|
|
86
108
|
raise ParametersNotEqualError
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
109
|
+
for i, parameter in enumerate(self._parameters.values()):
|
|
110
|
+
parameter.set_value(values[i])
|
|
111
|
+
|
|
112
|
+
def set_parameters(self, parameter_dict: dict[str, RealNumber]) -> None:
|
|
113
|
+
"""Set the parameter values by their label. No need to provide the full list of parameters.
|
|
114
|
+
|
|
115
|
+
Args:
|
|
116
|
+
parameter_dict (dict[str, RealNumber]): A dictionary with the labels of the parameters to be modified and their new value.
|
|
117
|
+
|
|
118
|
+
Raises:
|
|
119
|
+
ValueError: if the label provided doesn't correspond to a parameter defined in this circuit.
|
|
120
|
+
"""
|
|
121
|
+
for label, param in parameter_dict.items():
|
|
122
|
+
if label not in self._parameters:
|
|
123
|
+
raise ValueError(f"Parameter {label} is not defined in this circuit.")
|
|
124
|
+
self._parameters[label].set_value(param)
|
|
125
|
+
|
|
126
|
+
def get_parameter_bounds(self) -> dict[str, tuple[float, float]]:
|
|
127
|
+
return {k: v.bounds for k, v in self._parameters.items()}
|
|
128
|
+
|
|
129
|
+
def set_parameter_bounds(self, ranges: dict[str, tuple[float, float]]) -> None:
|
|
130
|
+
for label, bound in ranges.items():
|
|
131
|
+
if label not in self._parameters:
|
|
132
|
+
raise ValueError(
|
|
133
|
+
f"The provided parameter label {label} is not defined in the list of parameters in this object."
|
|
134
|
+
)
|
|
135
|
+
self._parameters[label].set_bounds(bound[0], bound[1])
|
|
91
136
|
|
|
92
137
|
def add(self, gate: Gate) -> None:
|
|
93
138
|
"""
|
|
@@ -102,5 +147,32 @@ class Circuit:
|
|
|
102
147
|
if any(qubit >= self.nqubits for qubit in gate.qubits):
|
|
103
148
|
raise QubitOutOfRangeError
|
|
104
149
|
if gate.is_parameterized:
|
|
105
|
-
|
|
150
|
+
param_base_label = f"{gate.name}({','.join(map(str, gate.qubits))})"
|
|
151
|
+
for label, parameter in gate.parameters.items():
|
|
152
|
+
if label == parameter.label:
|
|
153
|
+
parameter_label = param_base_label + f"_{label}_{len(self._parameters)}"
|
|
154
|
+
else:
|
|
155
|
+
parameter_label = parameter.label
|
|
156
|
+
self._parameters[parameter_label] = gate.parameters[label]
|
|
106
157
|
self._gates.append(gate)
|
|
158
|
+
|
|
159
|
+
def draw(self, style: CircuitStyle = CircuitStyle(), filepath: str | None = None) -> None:
|
|
160
|
+
"""
|
|
161
|
+
Render this circuit with Matplotlib and optionally save it to a file.
|
|
162
|
+
|
|
163
|
+
The circuit is rendered using the provided style configuration. If ``filepath`` is
|
|
164
|
+
given, the resulting figure is saved to disk (the output format is inferred
|
|
165
|
+
from the file extension, e.g. ``.png``, ``.pdf``, ``.svg``).
|
|
166
|
+
|
|
167
|
+
Args:
|
|
168
|
+
style (CircuitStyle): Visual style configuration applied to the plot.
|
|
169
|
+
If not provided, the default :class:`CircuitStyle` is used.
|
|
170
|
+
filepath (str | None): Destination file path for the rendered figure.
|
|
171
|
+
If ``None``, the figure is not saved.
|
|
172
|
+
"""
|
|
173
|
+
from qilisdk.utils.visualization.circuit_renderers import MatplotlibCircuitRenderer # noqa: PLC0415
|
|
174
|
+
|
|
175
|
+
renderer = MatplotlibCircuitRenderer(self, style=style)
|
|
176
|
+
renderer.plot()
|
|
177
|
+
if filepath:
|
|
178
|
+
renderer.save(filepath)
|
qilisdk/digital/exceptions.py
CHANGED
|
@@ -13,19 +13,25 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
15
|
|
|
16
|
-
class QubitOutOfRangeError(Exception):
|
|
16
|
+
class QubitOutOfRangeError(Exception):
|
|
17
|
+
"""Raised when a qubit index is outside the defined circuit range."""
|
|
17
18
|
|
|
18
19
|
|
|
19
|
-
class GateHasNoMatrixError(Exception):
|
|
20
|
+
class GateHasNoMatrixError(Exception):
|
|
21
|
+
"""Raised when a gate lacks an associated matrix representation."""
|
|
20
22
|
|
|
21
23
|
|
|
22
|
-
class GateNotParameterizedError(Exception):
|
|
24
|
+
class GateNotParameterizedError(Exception):
|
|
25
|
+
"""Raised when attempting to set parameters on a non-parameterized gate."""
|
|
23
26
|
|
|
24
27
|
|
|
25
|
-
class ParametersNotEqualError(Exception):
|
|
28
|
+
class ParametersNotEqualError(Exception):
|
|
29
|
+
"""Raised when parameterized gates receive mismatched parameter values."""
|
|
26
30
|
|
|
27
31
|
|
|
28
|
-
class InvalidParameterNameError(Exception):
|
|
32
|
+
class InvalidParameterNameError(Exception):
|
|
33
|
+
"""Raised when an unknown parameter name is supplied to a gate."""
|
|
29
34
|
|
|
30
35
|
|
|
31
|
-
class UnsupportedGateError(Exception):
|
|
36
|
+
class UnsupportedGateError(Exception):
|
|
37
|
+
"""Raised when a gate is not supported by the target backend."""
|