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.
Files changed (83) hide show
  1. qilisdk/__init__.py +11 -2
  2. qilisdk/__init__.pyi +2 -3
  3. qilisdk/_logging.py +135 -0
  4. qilisdk/_optionals.py +5 -7
  5. qilisdk/analog/__init__.py +3 -18
  6. qilisdk/analog/exceptions.py +2 -4
  7. qilisdk/analog/hamiltonian.py +455 -110
  8. qilisdk/analog/linear_schedule.py +118 -0
  9. qilisdk/analog/schedule.py +272 -79
  10. qilisdk/backends/__init__.py +45 -0
  11. qilisdk/{digital/digital_algorithm.py → backends/__init__.pyi} +3 -5
  12. qilisdk/backends/backend.py +117 -0
  13. qilisdk/{extras/cuda → backends}/cuda_backend.py +152 -159
  14. qilisdk/backends/qutip_backend.py +492 -0
  15. qilisdk/common/__init__.py +48 -2
  16. qilisdk/common/algorithm.py +2 -1
  17. qilisdk/{extras/qaas/qaas_settings.py → common/exceptions.py} +12 -6
  18. qilisdk/common/model.py +1019 -1
  19. qilisdk/common/parameterizable.py +75 -0
  20. qilisdk/common/qtensor.py +666 -0
  21. qilisdk/common/result.py +2 -1
  22. qilisdk/common/variables.py +1931 -0
  23. qilisdk/{extras/cuda/cuda_analog_result.py → cost_functions/__init__.py} +3 -4
  24. qilisdk/cost_functions/cost_function.py +77 -0
  25. qilisdk/cost_functions/model_cost_function.py +145 -0
  26. qilisdk/cost_functions/observable_cost_function.py +109 -0
  27. qilisdk/digital/__init__.py +3 -22
  28. qilisdk/digital/ansatz.py +203 -160
  29. qilisdk/digital/circuit.py +81 -9
  30. qilisdk/digital/exceptions.py +12 -6
  31. qilisdk/digital/gates.py +228 -85
  32. qilisdk/{extras/qaas/qaas_analog_result.py → functionals/__init__.py} +14 -5
  33. qilisdk/functionals/functional.py +39 -0
  34. qilisdk/{extras/cuda/cuda_digital_result.py → functionals/functional_result.py} +3 -4
  35. qilisdk/functionals/sampling.py +81 -0
  36. qilisdk/functionals/sampling_result.py +92 -0
  37. qilisdk/functionals/time_evolution.py +98 -0
  38. qilisdk/functionals/time_evolution_result.py +84 -0
  39. qilisdk/functionals/variational_program.py +80 -0
  40. qilisdk/functionals/variational_program_result.py +69 -0
  41. qilisdk/logging_config.yaml +16 -0
  42. qilisdk/{common/backend.py → optimizers/__init__.py} +2 -1
  43. qilisdk/optimizers/optimizer.py +39 -0
  44. qilisdk/{common → optimizers}/optimizer_result.py +3 -12
  45. qilisdk/{common/optimizer.py → optimizers/scipy_optimizer.py} +10 -28
  46. qilisdk/settings.py +78 -0
  47. qilisdk/{extras → speqtrum}/__init__.py +7 -8
  48. qilisdk/{extras → speqtrum}/__init__.pyi +3 -3
  49. qilisdk/speqtrum/experiments/__init__.py +25 -0
  50. qilisdk/speqtrum/experiments/experiment_functional.py +124 -0
  51. qilisdk/speqtrum/experiments/experiment_result.py +231 -0
  52. qilisdk/{extras/qaas → speqtrum}/keyring.py +8 -4
  53. qilisdk/speqtrum/speqtrum.py +432 -0
  54. qilisdk/speqtrum/speqtrum_models.py +300 -0
  55. qilisdk/utils/__init__.py +0 -14
  56. qilisdk/utils/openqasm2.py +1 -1
  57. qilisdk/utils/serialization.py +1 -1
  58. qilisdk/utils/visualization/PlusJakartaSans-SemiBold.ttf +0 -0
  59. qilisdk/utils/visualization/__init__.py +24 -0
  60. qilisdk/utils/visualization/circuit_renderers.py +781 -0
  61. qilisdk/utils/visualization/schedule_renderers.py +161 -0
  62. qilisdk/utils/visualization/style.py +154 -0
  63. qilisdk/utils/visualization/themes.py +76 -0
  64. qilisdk/yaml.py +126 -0
  65. {qilisdk-0.1.4.dist-info → qilisdk-0.1.5.dist-info}/METADATA +180 -134
  66. qilisdk-0.1.5.dist-info/RECORD +69 -0
  67. qilisdk/analog/algorithms.py +0 -111
  68. qilisdk/analog/analog_backend.py +0 -43
  69. qilisdk/analog/analog_result.py +0 -114
  70. qilisdk/analog/quantum_objects.py +0 -596
  71. qilisdk/digital/digital_backend.py +0 -90
  72. qilisdk/digital/digital_result.py +0 -145
  73. qilisdk/digital/vqe.py +0 -166
  74. qilisdk/extras/cuda/__init__.py +0 -13
  75. qilisdk/extras/qaas/__init__.py +0 -13
  76. qilisdk/extras/qaas/models.py +0 -132
  77. qilisdk/extras/qaas/qaas_backend.py +0 -255
  78. qilisdk/extras/qaas/qaas_digital_result.py +0 -20
  79. qilisdk/extras/qaas/qaas_time_evolution_result.py +0 -20
  80. qilisdk/extras/qaas/qaas_vqe_result.py +0 -20
  81. qilisdk-0.1.4.dist-info/RECORD +0 -51
  82. {qilisdk-0.1.4.dist-info → qilisdk-0.1.5.dist-info}/WHEEL +0 -0
  83. {qilisdk-0.1.4.dist-info → qilisdk-0.1.5.dist-info}/licenses/LICENCE +0 -0
qilisdk/digital/gates.py CHANGED
@@ -20,6 +20,8 @@ import numpy as np
20
20
  from scipy.linalg import expm
21
21
  from typing_extensions import Self
22
22
 
23
+ from qilisdk.common.parameterizable import Parameterizable
24
+ from qilisdk.common.variables import Parameter
23
25
  from qilisdk.yaml import yaml
24
26
 
25
27
  from .exceptions import (
@@ -32,7 +34,7 @@ from .exceptions import (
32
34
  TBasicGate = TypeVar("TBasicGate", bound="BasicGate")
33
35
 
34
36
 
35
- class Gate(ABC):
37
+ class Gate(Parameterizable, ABC):
36
38
  """
37
39
  Represents a quantum gate that can be used in quantum circuits.
38
40
  """
@@ -103,54 +105,60 @@ class Gate(ABC):
103
105
  return len(self.qubits)
104
106
 
105
107
  @property
106
- def parameters(self) -> dict[str, float]:
108
+ def nparameters(self) -> int:
107
109
  """
108
- Retrieve a mapping of parameter names to their corresponding values.
110
+ Retrieve the number of parameters for the gate.
109
111
 
110
112
  Returns:
111
- dict[str, float]: A dictionary mapping each parameter name to its numeric value.
113
+ int: The count of parameters needed by the gate.
112
114
  """
113
- return {}
115
+ return len(self.get_parameters())
114
116
 
115
117
  @property
116
- def parameter_names(self) -> list[str]:
118
+ def is_parameterized(self) -> bool:
117
119
  """
118
- Retrieve the symbolic names of the gate's parameters.
120
+ Determine whether the gate requires parameters.
119
121
 
120
122
  Returns:
121
- list[str]: A list containing the names of the parameters.
123
+ bool: True if the gate is parameterized; otherwise, False.
122
124
  """
123
- return list(self.parameters.keys())
125
+ return self.nparameters != 0
124
126
 
125
127
  @property
126
- def parameter_values(self) -> list[float]:
128
+ def parameters(self) -> dict[str, Parameter]:
129
+ """Returns the raw parameter objects stored in the gate.
130
+
131
+ Returns:
132
+ dict[str, Parameter]: A dictionary mapping each Parameter object to its label.
127
133
  """
128
- Retrieve the numerical values assigned to the gate's parameters.
134
+ return {}
135
+
136
+ def get_parameters(self) -> dict[str, float]: # noqa: PLR6301
137
+ """
138
+ Retrieve a mapping of parameter names to their corresponding values.
129
139
 
130
140
  Returns:
131
- list[float]: A list containing the parameter values.
141
+ dict[str, float]: A dictionary mapping each parameter name to its numeric value.
132
142
  """
133
- return list(self.parameters.values())
143
+ return {}
134
144
 
135
- @property
136
- def nparameters(self) -> int:
145
+ def get_parameter_names(self) -> list[str]:
137
146
  """
138
- Retrieve the number of parameters for the gate.
147
+ Retrieve the symbolic names of the gate's parameters.
139
148
 
140
149
  Returns:
141
- int: The count of parameters needed by the gate.
150
+ list[str]: A list containing the names of the parameters.
142
151
  """
143
- return len(self.parameters)
152
+ return list(self.get_parameters())
144
153
 
145
- @property
146
- def is_parameterized(self) -> bool:
154
+ def get_parameter_values(self) -> list[float]:
147
155
  """
148
- Determine whether the gate requires parameters.
156
+ Retrieve the numerical values assigned to the gate's parameters.
149
157
 
150
158
  Returns:
151
- bool: True if the gate is parameterized; otherwise, False.
159
+ list[float]: A list containing the parameter values.
152
160
  """
153
- return self.nparameters != 0
161
+ return list(self.get_parameters().values())
154
162
 
155
163
  def set_parameters(self, parameters: dict[str, float]) -> None:
156
164
  """
@@ -166,7 +174,7 @@ class Gate(ABC):
166
174
  if not self.is_parameterized:
167
175
  raise GateNotParameterizedError
168
176
 
169
- if any(name not in self.parameters for name in parameters):
177
+ if any(name not in self.get_parameters() for name in parameters):
170
178
  raise InvalidParameterNameError
171
179
 
172
180
  def set_parameter_values(self, values: list[float]) -> None:
@@ -183,26 +191,34 @@ class Gate(ABC):
183
191
  if not self.is_parameterized:
184
192
  raise GateNotParameterizedError
185
193
 
186
- if len(values) != len(self.parameters):
194
+ if len(values) != len(self.get_parameters()):
187
195
  raise ParametersNotEqualError
188
196
 
197
+ def get_parameter_bounds(self) -> dict[str, tuple[float, float]]: # noqa: PLR6301
198
+ return {}
199
+
200
+ def set_parameter_bounds(self, ranges: dict[str, tuple[float, float]]) -> None:
201
+ if not self.is_parameterized:
202
+ raise GateNotParameterizedError
203
+
189
204
  def __repr__(self) -> str:
190
205
  qubits_str = f"({self.qubits[0]})" if self.nqubits == 1 else str(self.qubits)
191
206
  return f"{self.name}{qubits_str}"
192
207
 
193
208
 
209
+ @yaml.register_class
194
210
  class BasicGate(Gate):
195
211
  """
196
212
  Represents a quantum gate that can be used in quantum circuits.
197
213
  """
198
214
 
199
- def __init__(self, target_qubits: tuple[int, ...], parameters: dict[str, float] = {}) -> None:
215
+ def __init__(self, target_qubits: tuple[int, ...], parameters: dict[str, Parameter] = {}) -> None:
200
216
  # Check for duplicate integers in target_qubits.
201
217
  if len(target_qubits) != len(set(target_qubits)):
202
218
  raise ValueError("Duplicate target qubits found.")
203
219
 
204
220
  self._target_qubits: tuple[int, ...] = target_qubits
205
- self._parameters: dict[str, float] = parameters
221
+ self._parameters: dict[str, Parameter] = parameters
206
222
  self._matrix: np.ndarray = self._generate_matrix()
207
223
 
208
224
  @property
@@ -214,22 +230,38 @@ class BasicGate(Gate):
214
230
  return self._target_qubits
215
231
 
216
232
  @property
217
- def parameters(self) -> dict[str, float]:
218
- return dict(self._parameters)
233
+ def parameters(self) -> dict[str, Parameter]:
234
+ return self._parameters
235
+
236
+ def get_parameters(self) -> dict[str, float]:
237
+ return {k: v.value for k, v in self._parameters.items()}
219
238
 
220
239
  def set_parameters(self, parameters: dict[str, float]) -> None:
221
240
  super().set_parameters(parameters=parameters)
222
- self._parameters.update(parameters)
241
+ for k, v in parameters.items():
242
+ self._parameters[k].set_value(v)
223
243
  self._matrix = self._generate_matrix()
224
244
 
225
245
  def set_parameter_values(self, values: list[float]) -> None:
226
246
  super().set_parameter_values(values=values)
227
247
 
228
- for key, value in zip(self.parameters, values):
229
- self._parameters[key] = value
248
+ for key, value in zip(self.get_parameters(), values):
249
+ self._parameters[key].set_value(value)
230
250
 
231
251
  self._matrix = self._generate_matrix()
232
252
 
253
+ def get_parameter_bounds(self) -> dict[str, tuple[float, float]]:
254
+ return {k: v.bounds for k, v in self._parameters.items()}
255
+
256
+ def set_parameter_bounds(self, ranges: dict[str, tuple[float, float]]) -> None:
257
+ super().set_parameter_bounds(ranges=ranges)
258
+ for label, bound in ranges.items():
259
+ if label not in self._parameters:
260
+ raise ValueError(
261
+ f"The provided parameter label {label} is not defined in the list of parameters in this object."
262
+ )
263
+ self._parameters[label].set_bounds(bound[0], bound[1])
264
+
233
265
  def controlled(self: Self, *control_qubits: int) -> Controlled[Self]:
234
266
  """
235
267
  Creates a controlled version of this unitary gate.
@@ -293,18 +325,6 @@ class Modified(Gate, Generic[TBasicGate]):
293
325
  def target_qubits(self) -> tuple[int, ...]:
294
326
  return self._basic_gate.target_qubits
295
327
 
296
- @property
297
- def parameters(self) -> dict[str, float]:
298
- return self._basic_gate.parameters
299
-
300
- @property
301
- def parameter_names(self) -> list[str]:
302
- return self._basic_gate.parameter_names
303
-
304
- @property
305
- def parameter_values(self) -> list[float]:
306
- return self._basic_gate.parameter_values
307
-
308
328
  @property
309
329
  def nparameters(self) -> int:
310
330
  return self._basic_gate.nparameters
@@ -313,6 +333,19 @@ class Modified(Gate, Generic[TBasicGate]):
313
333
  def is_parameterized(self) -> bool:
314
334
  return self._basic_gate.is_parameterized
315
335
 
336
+ @property
337
+ def parameters(self) -> dict[str, Parameter]:
338
+ return self._basic_gate.parameters
339
+
340
+ def get_parameters(self) -> dict[str, float]:
341
+ return self._basic_gate.get_parameters()
342
+
343
+ def get_parameter_names(self) -> list[str]:
344
+ return self._basic_gate.get_parameter_names()
345
+
346
+ def get_parameter_values(self) -> list[float]:
347
+ return self._basic_gate.get_parameter_values()
348
+
316
349
  def set_parameters(self, parameters: dict[str, float]) -> None:
317
350
  self._basic_gate.set_parameters(parameters=parameters)
318
351
  self._matrix = self._generate_matrix()
@@ -321,6 +354,12 @@ class Modified(Gate, Generic[TBasicGate]):
321
354
  self._basic_gate.set_parameter_values(values=values)
322
355
  self._matrix = self._generate_matrix()
323
356
 
357
+ def get_parameter_bounds(self) -> dict[str, tuple[float, float]]:
358
+ return self._basic_gate.get_parameter_bounds()
359
+
360
+ def set_parameter_bounds(self, ranges: dict[str, tuple[float, float]]) -> None:
361
+ self._basic_gate.set_parameter_bounds(ranges)
362
+
324
363
  @abstractmethod
325
364
  def _generate_matrix(self) -> np.ndarray: ...
326
365
 
@@ -450,14 +489,48 @@ class M(Gate):
450
489
  return self._target_qubits
451
490
 
452
491
 
492
+ @yaml.register_class
493
+ class I(BasicGate):
494
+ """
495
+ The Identity gate.
496
+
497
+ The associated matrix is:
498
+
499
+ .. code-block:: text
500
+
501
+ [[1, 0],
502
+ [0, 1]]
503
+
504
+ """
505
+
506
+ def __init__(self, qubit: int) -> None:
507
+ """
508
+ Initialize a Pauli-X gate.
509
+
510
+ Args:
511
+ qubit (int): The target qubit index for the X gate.
512
+ """
513
+ super().__init__(target_qubits=(qubit,))
514
+
515
+ @property
516
+ def name(self) -> str:
517
+ return "I"
518
+
519
+ def _generate_matrix(self) -> np.ndarray: # noqa: PLR6301
520
+ return np.array([[1, 0], [0, 1]], dtype=complex)
521
+
522
+
453
523
  @yaml.register_class
454
524
  class X(BasicGate):
455
525
  """
456
526
  The Pauli-X gate.
457
527
 
458
528
  The associated matrix is:
459
- [[0, 1],
460
- [1, 0]]
529
+
530
+ .. code-block:: text
531
+
532
+ [[0, 1],
533
+ [1, 0]]
461
534
 
462
535
  This is a pi radians rotation around the X-axis in the Bloch sphere.
463
536
  """
@@ -487,8 +560,9 @@ class Y(BasicGate):
487
560
  The associated matrix is:
488
561
 
489
562
  .. code-block:: text
490
- [[0, -i],
491
- [i, 0]]
563
+
564
+ [[ 0, -i ],
565
+ [ i, 0 ]]
492
566
 
493
567
  This is a pi radians rotation around the Y-axis in the Bloch sphere.
494
568
  """
@@ -518,8 +592,9 @@ class Z(BasicGate):
518
592
  The associated matrix is:
519
593
 
520
594
  .. code-block:: text
595
+
521
596
  [[1, 0],
522
- [0, -1]]
597
+ [0, -1]]
523
598
 
524
599
  This is a pi radians rotation around the Z-axis in the Bloch sphere.
525
600
  """
@@ -549,8 +624,9 @@ class H(BasicGate):
549
624
  The associated matrix is:
550
625
 
551
626
  .. code-block:: text
552
- 1/sqrt(2) * [[1, 1],
553
- [1, -1]]
627
+
628
+ [[1/sqrt(2), 1/sqrt(2)],
629
+ [1/sqrt(2), -1/sqrt(2)]]
554
630
 
555
631
  This is a pi radians rotation around the (X+Z)-axis in the Bloch sphere.
556
632
  """
@@ -580,6 +656,7 @@ class S(BasicGate):
580
656
  The associated matrix is:
581
657
 
582
658
  .. code-block:: text
659
+
583
660
  [[1, 0],
584
661
  [0, i]]
585
662
 
@@ -611,6 +688,7 @@ class T(BasicGate):
611
688
  The associated matrix is:
612
689
 
613
690
  .. code-block:: text
691
+
614
692
  [[1, 0],
615
693
  [0, exp(i*pi/4)]]
616
694
 
@@ -642,6 +720,7 @@ class RX(BasicGate):
642
720
  The associated matrix is:
643
721
 
644
722
  .. code-block:: text
723
+
645
724
  [[cos(theta/2), -i*sin(theta/2)],
646
725
  [-i*sin(theta/2), cos(theta/2)]]
647
726
 
@@ -651,7 +730,7 @@ class RX(BasicGate):
651
730
 
652
731
  PARAMETER_NAMES: ClassVar[list[str]] = ["theta"]
653
732
 
654
- def __init__(self, qubit: int, *, theta: float) -> None:
733
+ def __init__(self, qubit: int, *, theta: float | Parameter) -> None:
655
734
  """
656
735
  Initialize an RX gate.
657
736
 
@@ -659,7 +738,10 @@ class RX(BasicGate):
659
738
  qubit (int): The target qubit index for the rotation.
660
739
  theta (float): The rotation angle (polar) in radians.
661
740
  """
662
- super().__init__(target_qubits=(qubit,), parameters={"theta": theta})
741
+ super().__init__(
742
+ target_qubits=(qubit,),
743
+ parameters={"theta": theta if isinstance(theta, Parameter) else Parameter("theta", theta)},
744
+ )
663
745
 
664
746
  @property
665
747
  def name(self) -> str:
@@ -667,10 +749,10 @@ class RX(BasicGate):
667
749
 
668
750
  @property
669
751
  def theta(self) -> float:
670
- return self.parameters["theta"]
752
+ return self.get_parameters()["theta"]
671
753
 
672
754
  def _generate_matrix(self) -> np.ndarray:
673
- theta = self.parameters["theta"]
755
+ theta = self.theta
674
756
  cos_half = np.cos(theta / 2)
675
757
  sin_half = np.sin(theta / 2)
676
758
  return np.array([[cos_half, -1j * sin_half], [-1j * sin_half, cos_half]], dtype=complex)
@@ -684,6 +766,7 @@ class RY(BasicGate):
684
766
  The associated matrix is:
685
767
 
686
768
  .. code-block:: text
769
+
687
770
  [[cos(theta/2), -sin(theta/2)],
688
771
  [sin(theta/2), cos(theta/2)]]
689
772
 
@@ -693,7 +776,7 @@ class RY(BasicGate):
693
776
 
694
777
  PARAMETER_NAMES: ClassVar[list[str]] = ["theta"]
695
778
 
696
- def __init__(self, qubit: int, *, theta: float) -> None:
779
+ def __init__(self, qubit: int, *, theta: float | Parameter) -> None:
697
780
  """
698
781
  Initialize an RY gate.
699
782
 
@@ -701,7 +784,10 @@ class RY(BasicGate):
701
784
  qubit (int): The target qubit index for the rotation.
702
785
  theta (float): The rotation angle (polar) in radians.
703
786
  """
704
- super().__init__(target_qubits=(qubit,), parameters={"theta": theta})
787
+ super().__init__(
788
+ target_qubits=(qubit,),
789
+ parameters={"theta": theta if isinstance(theta, Parameter) else Parameter("theta", theta)},
790
+ )
705
791
 
706
792
  @property
707
793
  def name(self) -> str:
@@ -709,10 +795,10 @@ class RY(BasicGate):
709
795
 
710
796
  @property
711
797
  def theta(self) -> float:
712
- return self.parameters["theta"]
798
+ return self.get_parameters()["theta"]
713
799
 
714
800
  def _generate_matrix(self) -> np.ndarray:
715
- theta = self.parameters["theta"]
801
+ theta = self.theta
716
802
  cos_half = np.cos(theta / 2)
717
803
  sin_half = np.sin(theta / 2)
718
804
  return np.array([[cos_half, -sin_half], [sin_half, cos_half]], dtype=complex)
@@ -726,6 +812,7 @@ class RZ(BasicGate):
726
812
  The associated matrix is:
727
813
 
728
814
  .. code-block:: text
815
+
729
816
  [[exp(-i*phi/2), 0],
730
817
  [0, exp(i*phi/2)]]
731
818
 
@@ -743,7 +830,7 @@ class RZ(BasicGate):
743
830
 
744
831
  PARAMETER_NAMES: ClassVar[list[str]] = ["phi"]
745
832
 
746
- def __init__(self, qubit: int, *, phi: float) -> None:
833
+ def __init__(self, qubit: int, *, phi: float | Parameter) -> None:
747
834
  """
748
835
  Initialize an RZ gate.
749
836
 
@@ -751,21 +838,22 @@ class RZ(BasicGate):
751
838
  qubit (int): The target qubit index for the rotation.
752
839
  phi (float): The rotation angle (azimuthal) in radians.
753
840
  """
754
- super().__init__(target_qubits=(qubit,), parameters={"phi": phi})
841
+ super().__init__(
842
+ target_qubits=(qubit,),
843
+ parameters={"phi": phi if isinstance(phi, Parameter) else Parameter("phi", phi)},
844
+ )
755
845
 
756
846
  @property
757
847
  def name(self) -> str:
758
848
  return "RZ"
759
849
 
760
850
  @property
761
- def theta(self) -> float:
762
- return self.parameters["theta"]
851
+ def phi(self) -> float:
852
+ return self.get_parameters()["phi"]
763
853
 
764
854
  def _generate_matrix(self) -> np.ndarray:
765
- phi = self.parameters["phi"]
766
- cos_half = np.cos(phi / 2)
767
- sin_half = np.sin(phi / 2)
768
- return np.array([[cos_half, -sin_half], [sin_half, cos_half]], dtype=complex)
855
+ phi = self.phi
856
+ return np.array([[np.exp(-0.5j * phi), 0.0], [0.0, np.exp(0.5j * phi)]], dtype=complex)
769
857
 
770
858
 
771
859
  @yaml.register_class
@@ -776,6 +864,7 @@ class U1(BasicGate):
776
864
  The associated matrix is:
777
865
 
778
866
  .. code-block:: text
867
+
779
868
  [[1, 0],
780
869
  [0, exp(i*phi)]]
781
870
 
@@ -790,7 +879,7 @@ class U1(BasicGate):
790
879
 
791
880
  PARAMETER_NAMES: ClassVar[list[str]] = ["phi"]
792
881
 
793
- def __init__(self, qubit: int, *, phi: float) -> None:
882
+ def __init__(self, qubit: int, *, phi: float | Parameter) -> None:
794
883
  """
795
884
  Initialize a U1 gate.
796
885
 
@@ -798,7 +887,10 @@ class U1(BasicGate):
798
887
  qubit (int): The target qubit index for the U1 gate.
799
888
  phi (float): The phase to add, or equivalently the rotation angle (azimuthal) in radians.
800
889
  """
801
- super().__init__(target_qubits=(qubit,), parameters={"phi": phi})
890
+ super().__init__(
891
+ target_qubits=(qubit,),
892
+ parameters={"phi": phi if isinstance(phi, Parameter) else Parameter("phi", phi)},
893
+ )
802
894
 
803
895
  @property
804
896
  def name(self) -> str:
@@ -806,10 +898,10 @@ class U1(BasicGate):
806
898
 
807
899
  @property
808
900
  def phi(self) -> float:
809
- return self.parameters["phi"]
901
+ return self.get_parameters()["phi"]
810
902
 
811
903
  def _generate_matrix(self) -> np.ndarray:
812
- phi = self.parameters["phi"]
904
+ phi = self.phi
813
905
  return np.array([[1, 0], [0, np.exp(1j * phi)]], dtype=complex)
814
906
 
815
907
 
@@ -821,6 +913,7 @@ class U2(BasicGate):
821
913
  The associated matrix is:
822
914
 
823
915
  .. code-block:: text
916
+
824
917
  1/sqrt(2)*[[1, -exp(i*gamma)],
825
918
  [exp(i*phi), exp(i*(phi+gamma))]]
826
919
 
@@ -838,7 +931,7 @@ class U2(BasicGate):
838
931
 
839
932
  PARAMETER_NAMES: ClassVar[list[str]] = ["phi", "gamma"]
840
933
 
841
- def __init__(self, qubit: int, *, phi: float, gamma: float) -> None:
934
+ def __init__(self, qubit: int, *, phi: float | Parameter, gamma: float | Parameter) -> None:
842
935
  """
843
936
  Initialize a U2 gate.
844
937
 
@@ -847,7 +940,13 @@ class U2(BasicGate):
847
940
  phi (float): The first phase parameter, or equivalently the first rotation angle (azimuthal) in radians.
848
941
  gamma (float): The second phase parameter, or equivalently the second rotation angle (azimuthal) in radians..
849
942
  """
850
- super().__init__(target_qubits=(qubit,), parameters={"phi": phi, "gamma": gamma})
943
+ super().__init__(
944
+ target_qubits=(qubit,),
945
+ parameters={
946
+ "phi": phi if isinstance(phi, Parameter) else Parameter("phi", phi),
947
+ "gamma": gamma if isinstance(gamma, Parameter) else Parameter("gamma", gamma),
948
+ },
949
+ )
851
950
 
852
951
  @property
853
952
  def name(self) -> str:
@@ -855,15 +954,15 @@ class U2(BasicGate):
855
954
 
856
955
  @property
857
956
  def phi(self) -> float:
858
- return self.parameters["phi"]
957
+ return self.get_parameters()["phi"]
859
958
 
860
959
  @property
861
960
  def gamma(self) -> float:
862
- return self.parameters["gamma"]
961
+ return self.get_parameters()["gamma"]
863
962
 
864
963
  def _generate_matrix(self) -> np.ndarray:
865
- phi = self.parameters["phi"]
866
- gamma = self.parameters["gamma"]
964
+ phi = self.phi
965
+ gamma = self.gamma
867
966
  return (1 / np.sqrt(2)) * np.array(
868
967
  [
869
968
  [1, -np.exp(1j * gamma)],
@@ -881,6 +980,7 @@ class U3(BasicGate):
881
980
  The associated matrix is:
882
981
 
883
982
  .. code-block:: text
983
+
884
984
  [[cos(theta/2), -exp(i*gamma/2*sin(theta/2))],
885
985
  [exp(i*phi/2)*sin(theta/2), exp(i*(phi+gamma))*cos(theta/2)]]
886
986
 
@@ -899,7 +999,9 @@ class U3(BasicGate):
899
999
 
900
1000
  PARAMETER_NAMES: ClassVar[list[str]] = ["theta", "phi", "gamma"]
901
1001
 
902
- def __init__(self, qubit: int, *, theta: float, phi: float, gamma: float) -> None:
1002
+ def __init__(
1003
+ self, qubit: int, *, theta: float | Parameter, phi: float | Parameter, gamma: float | Parameter
1004
+ ) -> None:
903
1005
  """
904
1006
  Initialize a U3 gate.
905
1007
 
@@ -909,7 +1011,14 @@ class U3(BasicGate):
909
1011
  phi (float): The first phase parameter, or equivalently the first rotation angle (azimuthal) in radians.
910
1012
  gamma (float): The second phase parameter, or equivalently the second rotation angle (azimuthal) in radians.
911
1013
  """
912
- super().__init__(target_qubits=(qubit,), parameters={"theta": theta, "phi": phi, "gamma": gamma})
1014
+ super().__init__(
1015
+ target_qubits=(qubit,),
1016
+ parameters={
1017
+ "theta": theta if isinstance(theta, Parameter) else Parameter("theta", theta),
1018
+ "phi": phi if isinstance(phi, Parameter) else Parameter("phi", phi),
1019
+ "gamma": gamma if isinstance(gamma, Parameter) else Parameter("gamma", gamma),
1020
+ },
1021
+ )
913
1022
 
914
1023
  @property
915
1024
  def name(self) -> str:
@@ -917,20 +1026,20 @@ class U3(BasicGate):
917
1026
 
918
1027
  @property
919
1028
  def theta(self) -> float:
920
- return self.parameters["theta"]
1029
+ return self.get_parameters()["theta"]
921
1030
 
922
1031
  @property
923
1032
  def phi(self) -> float:
924
- return self.parameters["phi"]
1033
+ return self.get_parameters()["phi"]
925
1034
 
926
1035
  @property
927
1036
  def gamma(self) -> float:
928
- return self.parameters["gamma"]
1037
+ return self.get_parameters()["gamma"]
929
1038
 
930
1039
  def _generate_matrix(self) -> np.ndarray:
931
- theta = self.parameters["theta"]
932
- phi = self.parameters["phi"]
933
- gamma = self.parameters["gamma"]
1040
+ theta = self.theta
1041
+ phi = self.phi
1042
+ gamma = self.gamma
934
1043
  return np.array(
935
1044
  [
936
1045
  [np.cos(theta / 2), -np.exp(1j * gamma) * np.sin(theta / 2)],
@@ -948,6 +1057,7 @@ class CNOT(Controlled[X]):
948
1057
  The associated matrix is:
949
1058
 
950
1059
  .. code-block:: text
1060
+
951
1061
  [[1, 0, 0, 0],
952
1062
  [0, 1, 0, 0],
953
1063
  [0, 0, 0, 1],
@@ -973,6 +1083,7 @@ class CZ(Controlled[Z]):
973
1083
  The associated matrix is:
974
1084
 
975
1085
  .. code-block:: text
1086
+
976
1087
  [[1, 0, 0, 0],
977
1088
  [0, 1, 0, 0],
978
1089
  [0, 0, 1, 0],
@@ -987,3 +1098,35 @@ class CZ(Controlled[Z]):
987
1098
 
988
1099
  def __init__(self, control: int, target: int) -> None:
989
1100
  super().__init__(control, basic_gate=Z(target))
1101
+
1102
+
1103
+ @yaml.register_class
1104
+ class SWAP(BasicGate):
1105
+ """
1106
+ The SWAP gate.
1107
+
1108
+ The associated matrix is:
1109
+
1110
+ .. code-block:: text
1111
+
1112
+ [[1, 0, 0, 0],
1113
+ [0, 0, 1, 0],
1114
+ [0, 1, 0, 0],
1115
+ [0, 0, 0, 1]]
1116
+
1117
+ """
1118
+
1119
+ def __init__(self, qubit_a: int, qubit_b: int) -> None:
1120
+ """
1121
+ Args:
1122
+ qubit_a (int): First qubit to swap with.
1123
+ qubit_b (int): Second qubit to swap with.
1124
+ """
1125
+ super().__init__(target_qubits=(qubit_a, qubit_b))
1126
+
1127
+ @property
1128
+ def name(self) -> str:
1129
+ return "SWAP"
1130
+
1131
+ def _generate_matrix(self) -> np.ndarray: # noqa: PLR6301
1132
+ return np.array([[1, 0, 0, 0], [0, 0, 1, 0], [0, 1, 0, 0], [0, 0, 0, 1]], dtype=complex)
@@ -12,9 +12,18 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- from qilisdk.analog.analog_result import AnalogResult
16
- from qilisdk.yaml import yaml
15
+ from .sampling import Sampling
16
+ from .sampling_result import SamplingResult
17
+ from .time_evolution import TimeEvolution
18
+ from .time_evolution_result import TimeEvolutionResult
19
+ from .variational_program import VariationalProgram
20
+ from .variational_program_result import VariationalProgramResult
17
21
 
18
-
19
- @yaml.register_class
20
- class QaaSAnalogResult(AnalogResult): ...
22
+ __all__ = [
23
+ "Sampling",
24
+ "SamplingResult",
25
+ "TimeEvolution",
26
+ "TimeEvolutionResult",
27
+ "VariationalProgram",
28
+ "VariationalProgramResult",
29
+ ]