1"""
2Defines classes for quantum systems
3"""
4
5from typing import Callable, Optional, Union, Any
6
7import numpy as np
8import tensorflow as tf
9
10from py_ste.evolvers import UnitaryEvolver
11
12from .._hilbert_space import HilbertSpace
13
14def generate_channel_couplings(number_channels: list[int]) -> np.ndarray[bool]:
15 """Generates a boolean array indicating which channels couple to which
16 drives.
17
18 Parameters
19 ----------
20 number_chanels : list[int]
21 A list with the nth entry indicating the number of channels that
22 correspond the nth drive.
23
24 Returns
25 -------
26 NDArray[Shape[``len(number_channels)``, total_number_channels], bool]
27 An entry is `True` if the channel corresponds to the drive.
28 """
29 ...
30
31# Defining classes
32class ExpValCustom:
33 """
34 A class implimenting :meth:`QuantumSystem.evolved_expectation_value()` with
35 a `TensorFlow <https://www.tensorflow.org>`__ gradient.
36 """
37
38 system: "QuantumSystem"
39 "The system in which to take the expectation value"
40
41 initial_state: np.ndarray[complex]
42 "The initial state for the integrator"
43
44 dt: float
45 "The integrator time step"
46
47 observable: np.ndarray[complex]
48 "The observable to take the expectation value of"
49
50 switching_function: Any
51 """
52 The value of the switching function multiplied by :attr:`dt` evaluated at
53 each integration timestep
54 """
55
56 def __init__(self,
57 system: "QuantumSystem",
58 initial_state: np.ndarray[complex],
59 dt: float,
60 observable: np.ndarray[complex]):
61 """
62 Initialises the class with the `system` in which to take the expectation
63 value and the `observable` in the `system` to take the expectation value
64 of. Additionally, the initial state before evolution and
65 the integrator time step are specified.
66
67 Parameters
68 ----------
69 system : QuantumSystem
70 The system in which to take the expectation value
71 initial_state : NDArray[Shape[``system.state_shape``], complex]
72 The initial state for the integrator
73 dt : float
74 The integrator time step
75 observable : NDArray[Shape[``system.dim``, ``system.dim``], complex])
76 The observable to take the expectation value of
77 """
78 ...
79 @tf.custom_gradient
80 def run(self, ctrl_amp):
81 """
82 Computes the expectation value of the :attr:`observable` in the
83 :attr:`system` with respect to the :attr:`initial_state` evolved under
84 the Hamiltonian generated by the specified control amplitudes.
85
86 Parameters
87 ----------
88 ctrl_amp : tf.Tensor[Shape[n_time_steps, ``system.n_ctrl``], tf.complex128]
89 $\left(a_{ij}\right)$ The control amplitudes at each time step
90 expressed as an $N\times\textrm{length}$ matrix where the element
91 $a_{ij}$ corresponds to the control amplitude of the $j$th control
92 Hamiltonian at the $i$th time step.
93
94 Returns
95 -------
96 tf.Tensor[Shape[], tf.complex128]
97 The expectation value
98
99 Note
100 ----
101 This function is differentiable using TensorFlow's ``tf.GradientTape``.
102
103 Note
104 ----
105 This function uses
106 :meth:`~py_ste.evolvers.DenseUnitaryEvolver.switching_function()`
107 from `PySTE <https://PySTE.readthedocs.io>`__.
108 """
109 ...
110
111class GateInfidelityCustom():
112 """
113 A class implimenting :meth:`QuantumSystem.evolved_gate_infidelity()` with
114 a `TensorFlow <https://www.tensorflow.org>`__ gradient.
115 """
116
117 system: "QuantumSystem"
118 "The system in which to calculate the gate infidelity"
119
120 dt: float
121 "The integrator time step"
122
123 target: np.ndarray[complex]
124 "The target gate to calculate the gate infidelity with respect to."
125
126 switching_function: Any
127 """
128 The value of the switching function multiplied by :attr:`dt` evaluated at
129 each integration timestep
130 """
131
132 def __init__(self,
133 system: "QuantumSystem",
134 dt: float,
135 target: np.ndarray[complex]):
136 """
137 Initialises the class with the `system` in which to calculate the
138 gate infidelity and the `target` gate calculate the gate infidelity
139 from. Additionally, the integrator time step is specified.
140
141 Parameters
142 ----------
143 system : QuantumSystem
144 The system in which to calculate the gate infidelity
145 dt : float
146 The integrator time step
147 target : NDArray[Shape[``system.dim``, ``system.dim``], complex])
148 The target gate to calculate the gate infidelity with respect to
149 """
150 ...
151 @tf.custom_gradient
152 def run(self, ctrl_amp):
153 """
154 Computes the gate infidelity from :attr:`target` of the evolution due to
155 the :attr:`system` Hamiltonian generated by the specified control
156 amplitudes.
157
158 Parameters
159 ----------
160 ctrl_amp : tf.Tensor[Shape[n_time_steps, ``system.n_ctrl``], tf.complex128]
161 $\left(a_{ij}\right)$ The control amplitudes at each time step
162 expressed as an $N\times\textrm{length}$ matrix where the element
163 $a_{ij}$ corresponds to the control amplitude of the $j$th control
164 Hamiltonian at the $i$th time step.
165
166 Returns
167 -------
168 tf.Tensor[Shape[], tf.complex128]
169 The gate infidelity
170
171 Note
172 ----
173 This function is differentiable using TensorFlow's ``tf.GradientTape``.
174
175 Note
176 ----
177 This function uses
178 :meth:`~py_ste.evolvers.DenseUnitaryEvolver.gate_switching_function()`
179 from `PySTE <https://PySTE.readthedocs.io>`__.
180 """
181 ...
182
[docs]
183class QuantumSystem:
184 """
185 A class storing the properties of a quantum system.
186 """
187 _evolver: Optional[UnitaryEvolver] = None
188 "The integrator used for time evolutions of the system."
189
190 _hilbert_space: HilbertSpace
191 "The Hilbert space of the system"
192
193 _H0: np.ndarray
194 "The systems drift Hamiltonian as a :attr:`dim` x :attr:`dim` matrix."
195
196 _Hs: np.ndarray
197 """
198 An array of the system's control Hamiltonians with shape
199 (:attr:`n_ctrl`, :attr:`dim`, :attr:`dim`).
200 """
201
202 _graph_processing: Callable[..., tuple]
203 "A Tensorflow graph of :attr:`_processing()`"
204
205 _processing: Callable[..., tuple]
206 """
207 Executes :meth:`_pre_processing()` followed by
208 :meth:`_envolope_processing()` eagerly (i.e. without using a TensorFlow
209 graph). Nonetheless, :meth:`_eager_processing()` is still auto
210 differentiable.
211
212 Parameters
213 ----------
214 ctrl_amp : NDArray[Shape[n_time_steps, :attr:`n_ctrl`], complex]
215 The envolope control amplitudes
216 initial_state : NDArray[Shape[:attr:`state_shape`], complex]
217 The initial state for the integrator
218 dt : float
219 The itegration time step
220 frequencies : NDArray[Shape[n_time_steps, :attr:`n_ctrl`], complex]
221 The frequencies to modulate the control amplitudes with
222 number_channels : list[int]
223 The number of channels associated with each control Hamiltonian
224
225 Warning
226 -------
227 This must be a ``list`` and not an ``NDArray`` or a
228 `TensorFlow <https://www.tensorflow.org>`__ tensor.
229
230 Returns
231 -------
232 tuple[tf.Tensor[Shape[n_time_steps, :attr:`n_ctrl`], complex], tf.Tensor[Shape[:attr:`state_shape`], complex], tf.Tensor[Shape[], float]]
233 A tuple of:
234 1. Control amplitudes
235 2. Initial state
236 3. Integrator time step
237 """
238
239 _using_graph: bool
240 """
241 Whether to use TensorFlow graphs during computation. Using a TensorFlow
242 graph will increase the speed of computation. However, you have to be
243 careful that function parameters have not been baked into the graph leading
244 to unexpected behaviour.
245 """
246
[docs]
247 def __init__(self,
248 H0: np.ndarray[complex],
249 Hs: np.ndarray[complex],
250 hilbert_space: HilbertSpace,
251 use_graph: bool = True):
252 """
253 Initialises a new :class:`QuantumSystem`.
254
255 Parameters
256 ----------
257 H0 : NDArray[Shape[:attr:`dim`, :attr:`dim`], complex]
258 The systems drift Hamiltonian
259 Hs : NDArray[Shape[:attr:`n_ctrl`, :attr:`dim`, :attr:`dim`], complex] | NDArray[Shape[:attr:`n_ctrl` * :attr:`dim`, :attr:`dim`], complex]
260 The systems control Hamiltonians either as an array of control
261 Hamiltonians or the control Hamiltonians stacked along the first
262 axis.
263 hilbert_space : HilbertSpace
264 The Hilbert space of the system
265 use_graph : bool = True
266 Whether to use TensorFlow graphs during computation.
267 """
268 ...
269
270 def __del__(self):
271 ...
272 @property
273 def using_graph(self) -> bool:
274 """
275 Whether to use `TensorFlow <https://www.tensorflow.org>`__ graphs during
276 computation. Using a `TensorFlow <https://www.tensorflow.org>`__ graph
277 will increase the speed of computation. However, you have to be careful
278 that function parameters have not been baked into the graph leading to
279 unexpected behaviour.
280 """
281 ...
282 @using_graph.setter
283 def using_graph(self, value: bool):
284 ...
285 @property
286 def hilbert_space(self) -> HilbertSpace:
287 "The Hilbert space of the system"
288 ...
289 @property
290 def H0(self) -> np.ndarray[complex]:
291 """
292 The systems drift Hamiltonian as a :attr:`dim` x :attr:`dim` matrix.
293
294 See Also
295 --------
296 :attr:`Hs`
297 """
298 ...
299 @property
300 def Hs(self) -> np.ndarray[complex]:
301 """
302 An array of the system's control Hamiltonians with shape
303 (:attr:`n_ctrl`, :attr:`dim`, :attr:`dim`).
304
305 See Also
306 --------
307 :attr:`H0`
308 """
309 ...
310 @property
311 def dim(self) -> int:
312 """
313 The dimension of states in the quantum system.
314
315 See Also
316 --------
317 :attr:`state_shape`
318 """
319 ...
320 @property
321 def state_shape(self) -> tuple[int]:
322 """
323 The shape of the states in the system.
324
325 See Also
326 --------
327 :attr:`dim`
328 """
329 ...
330 @property
331 def n_ctrl(self) -> int:
332 """
333 The number of control Hamiltonians.
334 """
335 ...
336 @property
337 def evolver(self) -> UnitaryEvolver:
338 """
339 The integrator used for time evolutions of the system.
340
341 Note
342 ----
343 The `evolver` can take a while to initialise and so is not initialised
344 until `evolver` is is first used or when :meth:`initialise_evolver()` is
345 called. Using `evolver` before calling :meth:`initialise_evolver()`
346 initialises the `evolver` with the default parameters of
347 :meth:`initialise_evolver()`.
348 """
349 ...
[docs]
350 def initialise_evolver(self,
351 sparse: bool = False,
352 force_dynamic: bool = False):
353 """
354 Initialises :attr:`evolver` with an evolver from
355 `PySTE <https://PySTE.readthedocs.io>`__.
356 `PySTE <https://PySTE.readthedocs.io>`__ is Python
357 wrapper around the C++ header-only library
358 `Suzuki-Trotter-Evolver <https://Suzuki-Trotter-Evolver.readthedocs.io>`__:
359 a fast Schrödinger solver utilising the first-order Suzuki-Trotter
360 expansion.
361
362 Warning
363 -------
364 This can take a very long time to execute, especially for large Hilbert
365 space dimensions. If you plan to evolve the same quantum system many
366 times we recommended pickling the :attr:`evolver`.
367
368 Parameters
369 ----------
370 sparse : bool
371 Whether to use sparse or dense matrices during integration.
372 To make a decision on whether sparse or dense matrices are likely to
373 lead to faster integration you can consult the benchmarks at
374 https://PySTE.readthedocs.io/en/latest/benchmarks.
375 force_dynamic : bool
376 Whether to force `PySTE <https://PySTE.readthedocs.io>`__ to use a
377 dynamic evolver.
378
379 Note
380 ----
381 `PySTE <https://PySTE.readthedocs.io>`__ has precompiled evolvers
382 for specific Hilbert space dimensions and numbers of control
383 Hamiltonians. When these cannot be found
384 `PySTE <https://PySTE.readthedocs.io>`__ uses less efficient
385 evolvers with the Hilbert space dimension and the number of controls
386 determined dynamically at runtime.
387 """
388 ...
389 def _H(self, ctrl_amp: np.ndarray[float]) -> np.ndarray[complex]:
390 """
391 Computes the system Hamiltonian for the specified control amplitudes.
392
393 Parameters
394 ----------
395 ctrl_amp : NDArray[Shape[s := Any_Shape, :attr:`n_ctrl`], float]
396 The control amplitudes (stored in the last axis). The prior axes
397 allow for multiple sets of control amplitudes to be passed and the
398 Hamiltonian for each computed.
399
400 Returns
401 -------
402 NDArray[Shape[s, :attr:`dim`, :attr:`dim`], complex]
403 The system's Hamiltonian (stored in the last two axes).
404 """
405 ...
[docs]
406 def H(self,
407 ctrl_amp: Union[np.ndarray[float], np.ndarray[Callable[[float], np.ndarray[float]]]]
408 ) -> Union[np.ndarray[complex], Callable[[float], np.ndarray[complex]]]:
409 """
410 Computes the system Hamiltonian for the specified control amplitudes.
411
412 Parameters
413 ----------
414 ctrl_amp : NDArray[Shape[s := Any_Shape, :attr:`n_ctrl`], float | Callable[[float], np.ndarray[float]]]
415 The control amplitudes (stored in the last axis). The prior axes
416 allow for multiple sets of control amplitudes to be passed and the
417 Hamiltonian for each computed. The control amplitudes can be passed
418 as ``np.ndarray[float]`` to compute the system Hamiltonian for a
419 specific value of the control ampltiudes. Alternatively, the control
420 amplitudes can be passed as
421 ``np.ndarray[Callable[[float], np.ndarray[float]]]`` where each
422 element is a function of time. This will generate a time-dependent
423 Hamiltonian: a function that takes a single parameter (time) and
424 returns the Hamiltonian at this time.
425
426 Returns
427 -------
428 NDArray[Shape[s, :attr:`dim`, :attr:`dim`], complex] | NDArray[Shape[s], Callable[[float], np.ndarray[complex]]]]
429 Either the systems Hamiltonian stored in the last two axes (if
430 specific control amplitudes were passed) or a collection of
431 time-dependent Hamiltonians (if time-dependent controls were
432 passed).
433 """
434 ...
[docs]
435 def _pre_processing(self,
436 ctrl_amp : np.ndarray[complex],
437 initial_state : np.ndarray[complex],
438 dt: float,
439 frequencies: np.ndarray[complex],
440 number_channels: list[int]
441 ) -> tuple:
442 """
443 When calling any evolution method (listed in the
444 :ref:`See also section <pre_processing_see_also>`) :meth:`_pre_processing()` is
445 executed on the arguements before the control amplitudes are modulated
446 by the frequencies (during :meth:`_envolope_processing()`) and then finally
447 the modulated control amplitudes are used by the evolution method.
448
449 :meth:`_pre_processing()` should be overridden to produce desired pulse
450 shapes. You can either override :meth:`_pre_processing()` directly by
451 creating a child class, or you can use :meth:`pulse_form()`.
452
453 For :meth:`gradient()` to function correctly :meth:`_pre_processing()`
454 should be written in `TensorFlow <https://www.tensorflow.org>`__.
455
456 Parameters
457 ----------
458 ctrl_amp : NDArray[Shape[n_time_steps, :attr:`n_ctrl`], complex]
459 The envolope control amplitudes
460 initial_state : NDArray[Shape[:attr:`state_shape`], complex]
461 The initial state for the integrator
462 dt : float
463 The itegration time step
464 frequencies : NDArray[Shape[n_time_steps, :attr:`n_ctrl`], complex]
465 The frequencies to modulate the control amplitudes with
466 number_channels : list[int]
467 The number of channels associated with each control Hamiltonian
468
469 Warning
470 -------
471 This must be a ``list`` and not an ``NDArray`` or a
472 `TensorFlow <https://www.tensorflow.org>`__ tensor.
473
474 Returns
475 -------
476 tuple[tf.Tensor[Shape[n_time_steps, total_n_channels], tf.complex128], tf.Tensor[Shape[:attr:`state_shape`], tf.complex128], float, tf.Tensor[Shape[n_time_steps, total_n_channels], tf.complex128], list[int]]
477 A tuple of
478 1. The control amplitude envolopes
479 2. The initial state
480 3. The integrator time step
481 4. The frequencies to modulate the control amplitude envolopes with
482 5. A list of the number of channels for each control Hamiltonian
483
484 Warning
485 -------
486 The number of channels for each control Hamiltonian must be stored
487 as a ``list`` and not an ``NDArray`` or a
488 `TensorFlow <https://www.tensorflow.org>`__ tensor.
489
490 Warning
491 -------
492 Keyword arguments are not supported.
493
494 .. _pre_processing_see_also:
495
496 See Also
497 --------
498 * :meth:`propagate()`
499 * :meth:`propagate_collection()`
500 * :meth:`propagate_all()`
501 * :meth:`get_evolution()`
502 * :meth:`evolved_expectation_value()`
503 * :meth:`evolved_expectation_value_all()`
504 * :meth:`evolved_inner_product()`
505 * :meth:`evolved_inner_product_all()`
506 * :meth:`evolved_gate_infidelity()`
507 * :meth:`get_driving_pulses()`
508 * :meth:`gradient()`
509 * :meth:`gate_gradient()`
510 """
511 ...
[docs]
512 def _envolope_processing(self,
513 ctrl_amp,
514 dt: float,
515 frequencies,
516 number_channels: list[int]
517 ) -> tuple:
518 """
519 When calling any evolution method (listed in the
520 :ref:`See also section <envolope_processing_see_also>` section)
521 :meth:`_pre_processing()` is executed on the arguements before the
522 control amplitudes are modulated by the frequencies during
523 :meth:`_envolope_processing()` and then finally the modulated control
524 amplitudes are used by the evolution method.
525
526 Parameters
527 ----------
528 ctrl_amp : tf.Tensor[Shape[n_time_steps, total_n_channels], tf.complex128]
529 The envolope control amplitudes
530 dt : float
531 The itegration time step
532 frequencies : tf.Tensor[Shape[n_time_steps, total_n_channels], tf.complex128]
533 The frequencies to modulate the control amplitudes with
534 number_channels : list[int]
535 The number of channels associated with each control Hamiltonian
536
537 Warning
538 -------
539 This must be a ``list`` and not an ``NDArray`` or a
540 `TensorFlow <https://www.tensorflow.org>`__ tensor.
541
542 Returns
543 -------
544 tf.Tensor[Shape[n_time_steps, :attr:`n_ctrl`], tf.complex128]
545 The modulated control amplitudes
546
547
548 .. _envolope_processing_see_also:
549
550 See Also
551 --------
552 * :meth:`propagate()`
553 * :meth:`propagate_collection()`
554 * :meth:`propagate_all()`
555 * :meth:`get_evolution()`
556 * :meth:`evolved_expectation_value()`
557 * :meth:`evolved_expectation_value_all()`
558 * :meth:`evolved_inner_product()`
559 * :meth:`evolved_inner_product_all()`
560 * :meth:`evolved_gate_infidelity()`
561 * :meth:`get_driving_pulses()`
562 * :meth:`gradient()`
563 * :meth:`gate_gradient()`
564 """
565 ...
[docs]
566 def propagate(self,
567 ctrl_amp : np.ndarray[complex],
568 initial_state : np.ndarray[complex],
569 dt: float,
570 frequencies: np.ndarray[complex],
571 number_channels: list[int]
572 ) -> np.ndarray[complex]:
573 """
574 Evolves a state vector under the time-dependent Hamiltonian defined by
575 the control amplitudes using
576 :meth:`~py_ste.evolvers.DenseUnitaryEvolver.propagate()`
577 from `PySTE <https://PySTE.readthedocs.io>`__.
578
579 Parameters
580 ----------
581 ctrl_amp : NDArray[Shape[n_time_steps, :attr:`n_ctrl`], complex]
582 The envolope control amplitudes
583 initial_state : NDArray[Shape[:attr:`state_shape`], complex]
584 The initial state for the integrator
585 dt : float
586 The itegration time step
587 frequencies : NDArray[Shape[n_time_steps, :attr:`n_ctrl`], complex]
588 The frequencies to modulate the control amplitudes with
589 number_channels : list[int]
590 The number of channels associated with each control Hamiltonian
591
592 Warning
593 -------
594 This must be a ``list`` and not an ``NDArray`` or a
595 `TensorFlow <https://www.tensorflow.org>`__ tensor.
596
597 Warning
598 -------
599 Keyword arguments are not supported.
600
601 Returns
602 -------
603 NDArray[Shape[:attr:`state_shape`], complex]
604 The final state
605
606 See Also
607 --------
608 * :meth:`propagate_collection()`
609 * :meth:`propagate_all()`
610 * :meth:`get_evolution()`
611 """
612 ...
[docs]
613 def propagate_collection(self,
614 ctrl_amp : np.ndarray[complex],
615 initial_states : np.ndarray[complex],
616 dt: float,
617 frequencies: np.ndarray[complex],
618 number_channels: list[int]
619 ) -> np.ndarray[complex]:
620 """
621 Evolves a collection of state vectors under the time-dependent
622 Hamiltonian defined by the control amplitudes using
623 :meth:`~py_ste.evolvers.DenseUnitaryEvolver.propagate_collection()`
624 from `PySTE <https://PySTE.readthedocs.io>`__.
625
626 Parameters
627 ----------
628 ctrl_amp : NDArray[Shape[n_time_steps, :attr:`n_ctrl`], complex]
629 The envolope control amplitudes
630 initial_states : NDArray[Shape[n_states, :attr:`state_shape`], complex]
631 The initial state for the integrator
632 dt : float
633 The itegration time step
634 frequencies : NDArray[Shape[n_time_steps, :attr:`n_ctrl`], complex]
635 The frequencies to modulate the control amplitudes with
636 number_channels : list[int]
637 The number of channels associated with each control Hamiltonian
638
639 Warning
640 -------
641 This must be a ``list`` and not an ``NDArray`` or a
642 `TensorFlow <https://www.tensorflow.org>`__ tensor.
643
644 Warning
645 -------
646 Keyword arguments are not supported.
647
648 Returns
649 -------
650 NDArray[Shape[n_states, :attr:`state_shape`], complex]
651 The final state
652
653 See Also
654 --------
655 * :meth:`propagate()`
656 * :meth:`propagate_all()`
657 * :meth:`get_evolution()`
658 """
659 ...
[docs]
660 def propagate_all(self,
661 ctrl_amp : np.ndarray[complex],
662 initial_states : np.ndarray[complex],
663 dt: float,
664 frequencies: np.ndarray[complex],
665 number_channels: list[int]
666 ) -> np.ndarray[complex]:
667 """
668 Evolves a state vector under the time-dependent Hamiltonian defined by
669 the control amplitudes using
670 :meth:`~py_ste.evolvers.DenseUnitaryEvolver.propagate_all()`
671 from `PySTE <https://PySTE.readthedocs.io>`__ and returns the state at
672 each time-step.
673
674 Parameters
675 ----------
676 ctrl_amp : NDArray[Shape[n_time_steps, :attr:`n_ctrl`], complex]
677 The envolope control amplitudes
678 initial_state : NDArray[Shape[:attr:`state_shape`], complex]
679 The initial state for the integrator
680 dt : float
681 The itegration time step
682 frequencies : NDArray[Shape[n_time_steps, :attr:`n_ctrl`], complex]
683 The frequencies to modulate the control amplitudes with
684 number_channels : list[int]
685 The number of channels associated with each control Hamiltonian
686
687 Warning
688 -------
689 This must be a ``list`` and not an ``NDArray`` or a
690 `TensorFlow <https://www.tensorflow.org>`__ tensor.
691
692 Warning
693 -------
694 Keyword arguments are not supported.
695
696 Returns
697 -------
698 NDArray[Shape[:attr:`state_shape`, n_time_steps+1], complex]
699 The state at each integrator time step (including the initial
700 state).
701
702 See Also
703 --------
704 * :meth:`propagate()`
705 * :meth:`propagate_collection()`
706 * :meth:`get_evolution()`
707 """
708 ...
[docs]
709 def evolved_expectation_value(self,
710 ctrl_amp : np.ndarray[complex],
711 initial_state : np.ndarray[complex],
712 dt: float,
713 frequencies: np.ndarray[complex],
714 number_channels: list[int],
715 observable : np.ndarray[complex]
716 ) -> complex:
717 """
718 Evolves a state vector under the time-dependent Hamiltonian defined by
719 the control amplitudes and computes the expectation value of a specified
720 observable with respect to the final state using
721 :meth:`~py_ste.evolvers.DenseUnitaryEvolver.evolved_expectation_value()`
722 from `PySTE <https://PySTE.readthedocs.io>`__.
723
724 Parameters
725 ----------
726 ctrl_amp : tf.Tensor[Shape[n_time_steps, total_n_channels], tf.complex128]
727 The envolope control amplitudes
728 initial_state : NDArray[Shape[:attr:`state_shape`], complex]
729 The initial state for the integrator
730 dt : float
731 The itegration time step
732 frequencies : tf.Tensor[Shape[n_time_steps, total_n_channels], tf.complex128]
733 The frequencies to modulate the control amplitudes with
734 number_channels : list[int]
735 The number of channels associated with each control Hamiltonian
736
737 Warning
738 -------
739 This must be a ``list`` and not an ``NDArray`` or a
740 `TensorFlow <https://www.tensorflow.org>`__ tensor.
741 observable : NDArray[Shape[:attr:`dim`, :attr:`dim`], complex]
742 The observable to take the expectation value of.
743
744 Warning
745 -------
746 Keyword arguments are not supported.
747
748 Returns
749 -------
750 complex
751 The expectation value.
752
753 See Also
754 --------
755 * :meth:`evolved_expectation_value_all()`
756 * :meth:`gradient()`
757 """
758 ...
[docs]
759 def evolved_expectation_value_all(self,
760 ctrl_amp : np.ndarray[complex],
761 initial_state : np.ndarray[complex],
762 dt: float,
763 frequencies: np.ndarray[complex],
764 number_channels: list[int],
765 observable : np.ndarray[complex]
766 ) -> np.ndarray[complex]:
767 """
768 Evolves a state vector under the time-dependent Hamiltonian defined by
769 the control amplitudes and computes the expectation value of a specified
770 observable with respect to the state at each time-step using
771 :meth:`~py_ste.evolvers.DenseUnitaryEvolver.evolved_expectation_value_all()`
772 from `PySTE <https://PySTE.readthedocs.io>`__.
773
774 Parameters
775 ----------
776 ctrl_amp : tf.Tensor[Shape[n_time_steps, total_n_channels], tf.complex128]
777 The envolope control amplitudes
778 initial_state : NDArray[Shape[:attr:`state_shape`], complex]
779 The initial state for the integrator
780 dt : float
781 The itegration time step
782 frequencies : tf.Tensor[Shape[n_time_steps, total_n_channels], tf.complex128]
783 The frequencies to modulate the control amplitudes with
784 number_channels : list[int]
785 The number of channels associated with each control Hamiltonian
786
787 Warning
788 -------
789 This must be a ``list`` and not an ``NDArray`` or a
790 `TensorFlow <https://www.tensorflow.org>`__ tensor.
791 observable : NDArray[Shape[:attr:`dim`, :attr:`dim`], complex]
792 The observable to take the expectation value of.
793
794 Warning
795 -------
796 Keyword arguments are not supported.
797
798 Returns
799 -------
800 NDArray[Shape[n_time_steps+1], complex]
801 The expectation value of the state at each integrator time step
802 (including the initial state) with respect to the observable.
803
804 See Also
805 --------
806 * :meth:`evolved_expectation_value()`
807 * :meth:`gradient()`
808 """
809 ...
[docs]
810 def evolved_inner_product(self, *args) -> complex:
811 """
812 Evolves a state vector under the time-dependent Hamiltonian defined by
813 the control amplitudes and computes the inner product of the final state
814 vector with a fixed vector using
815 :meth:`~py_ste.evolvers.DenseUnitaryEvolver.evolved_inner_product()`
816 from `PySTE <https://PySTE.readthedocs.io>`__.
817
818 Parameters
819 ----------
820 ctrl_amp : tf.Tensor[Shape[n_time_steps, total_n_channels], tf.complex128]
821 The envolope control amplitudes
822 initial_state : NDArray[Shape[:attr:`state_shape`], complex]
823 The initial state for the integrator
824 dt : float
825 The itegration time step
826 frequencies : tf.Tensor[Shape[n_time_steps, total_n_channels], tf.complex128]
827 The frequencies to modulate the control amplitudes with
828 number_channels : list[int]
829 The number of channels associated with each control Hamiltonian
830
831 Warning
832 -------
833 This must be a ``list`` and not an ``NDArray`` or a
834 `TensorFlow <https://www.tensorflow.org>`__ tensor.
835 fixed_vector : NDArray[Shape[:attr:`dim`, :attr:`dim`], complex]
836 The fixed vector to calculate the inner product with.
837
838 Warning
839 -------
840 Keyword arguments are not supported.
841
842 Returns
843 -------
844 complex
845 The inner product of the evolved state vector with the fixed vector.
846
847 See Also
848 --------
849 * :meth:`evolved_inner_product_all()`
850 """
851 ...
[docs]
852 def evolved_inner_product_all(self, *args) -> complex:
853 """
854 Evolves a state vector under the time-dependent Hamiltonian defined by
855 the control amplitudes and computes the innper product of state at each
856 time-step with a fixed vector using
857 :meth:`~py_ste.evolvers.DenseUnitaryEvolver.evolved_inner_product_all()`
858 from `PySTE <https://PySTE.readthedocs.io>`__.
859
860 Parameters
861 ----------
862 ctrl_amp : tf.Tensor[Shape[n_time_steps, total_n_channels], tf.complex128]
863 The envolope control amplitudes
864 initial_state : NDArray[Shape[:attr:`state_shape`], complex]
865 The initial state for the integrator
866 dt : float
867 The itegration time step
868 frequencies : tf.Tensor[Shape[n_time_steps, total_n_channels], tf.complex128]
869 The frequencies to modulate the control amplitudes with
870 number_channels : list[int]
871 The number of channels associated with each control Hamiltonian
872
873 Warning
874 -------
875 This must be a ``list`` and not an ``NDArray`` or a
876 `TensorFlow <https://www.tensorflow.org>`__ tensor.
877 fixed_vector : NDArray[Shape[:attr:`dim`, :attr:`dim`], complex]
878 The fixed vector to calculate the inner product with.
879
880 Warning
881 -------
882 Keyword arguments are not supported.
883
884 Returns
885 -------
886 NDArray[Shape[n_time_steps+1], complex]
887 The inner product of state at each integrator time step (including
888 the initial state) with the fixed vector.
889
890 See Also
891 --------
892 * :meth:`evolved_inner_product()`
893 """
894 ...
[docs]
895 def get_evolution(self, *args) -> np.ndarray[complex]:
896 """
897 Computes the unitary evolution of the system under the time-dependent
898 Hamiltonian defined by the control amplitudes using
899 :meth:`~py_ste.evolvers.DenseUnitaryEvolver.get_evolution()`
900 from `PySTE <https://PySTE.readthedocs.io>`__.
901
902 Parameters
903 ----------
904 ctrl_amp : tf.Tensor[Shape[n_time_steps, total_n_channels], tf.complex128]
905 The envolope control amplitudes
906 initial_state : NDArray[Shape[:attr:`state_shape`], complex]
907 This is a redundant parameter for this function.
908 dt : float
909 The itegration time step
910 frequencies : tf.Tensor[Shape[n_time_steps, total_n_channels], tf.complex128]
911 The frequencies to modulate the control amplitudes with
912 number_channels : list[int]
913 The number of channels associated with each control Hamiltonian
914
915 Warning
916 -------
917 This must be a ``list`` and not an ``NDArray`` or a
918 `TensorFlow <https://www.tensorflow.org>`__ tensor.
919
920 Warning
921 -------
922 Keyword arguments are not supported.
923
924 Returns
925 -------
926 NDArray[Shape[:attr:`dim`, :attr:`dim`], complex]
927 The unitary corresponding to the evolution of the system.
928
929 See Also
930 --------
931 * :meth:`propagate()`
932 * :meth:`propagate_collection()`
933 * :meth:`propagate_all()`
934 """
935 ...
[docs]
936 def evolved_gate_infidelity(self, *args) -> float:
937 """
938 Evolves the system under the time-dependent Hamiltonian defined by
939 the control amplitudes and computes the gate infidelity to the target
940 gate using
941 :meth:`~py_ste.evolvers.DenseUnitaryEvolver.evolved_gate_infidelity()`
942 from `PySTE <https://PySTE.readthedocs.io>`__.
943
944 Parameters
945 ----------
946 ctrl_amp : tf.Tensor[Shape[n_time_steps, total_n_channels], tf.complex128]
947 The envolope control amplitudes
948 initial_state : NDArray[Shape[:attr:`state_shape`], complex]
949 This is a redundant parameter for this function.
950 dt : float
951 The itegration time step
952 frequencies : tf.Tensor[Shape[n_time_steps, total_n_channels], tf.complex128]
953 The frequencies to modulate the control amplitudes with
954 number_channels : list[int]
955 The number of channels associated with each control Hamiltonian
956
957 Warning
958 -------
959 This must be a ``list`` and not an ``NDArray`` or a
960 `TensorFlow <https://www.tensorflow.org>`__ tensor.
961 target : NDArray[Shape[:attr:`dim`, :attr:`dim`], complex]
962 The target gate to calculate the gate infidelity with respect to.
963
964 Warning
965 -------
966 Keyword arguments are not supported.
967
968 Returns
969 -------
970 float
971 The gate infidelity
972
973 See Also
974 --------
975 * :meth:`gate_gradient()`
976 """
977 ...
[docs]
978 def get_driving_pulses(self,
979 ctrl_amp : np.ndarray[complex],
980 initial_states : np.ndarray[complex],
981 dt: float,
982 frequencies: np.ndarray[complex],
983 number_channels: list[int]
984 ) -> tuple[np.ndarray[complex], np.ndarray[complex], float]:
985 """
986 When calling any evolution method (listed in the
987 :ref:`See also section <get_driving_pulses_see_also>`) :meth:`get_driving_pulses()`
988 is executed on the arguements before the evolution method.
989
990 Parameters
991 ----------
992 ctrl_amp : NDArray[Shape[n_time_steps, :attr:`n_ctrl`], complex]
993 The envolope control amplitudes
994 initial_state : NDArray[Shape[:attr:`state_shape`], complex]
995 The initial state for the integrator
996 dt : float
997 The itegration time step
998 frequencies : NDArray[Shape[n_time_steps, :attr:`n_ctrl`], complex]
999 The frequencies to modulate the control amplitudes with
1000 number_channels : list[int]
1001 The number of channels associated with each control Hamiltonian
1002
1003 Warning
1004 -------
1005 This must be a ``list`` and not an ``NDArray`` or a
1006 `TensorFlow <https://www.tensorflow.org>`__ tensor.
1007
1008 Warning
1009 -------
1010 Keyword arguments are not supported.
1011
1012 Returns
1013 -------
1014 tuple[NDArray[Shape[n_time_steps, :attr:`n_ctrl`], complex], NDArray[Shape[:attr:`state_shape`], complex], float]
1015 A tuple of:
1016 1. Control amplitudes
1017 2. Initial state
1018 3. Integrator time step
1019
1020
1021 .. _get_driving_pulses_see_also:
1022
1023 See Also
1024 --------
1025 * :meth:`propagate()`
1026 * :meth:`propagate_collection()`
1027 * :meth:`propagate_all()`
1028 * :meth:`get_evolution()`
1029 * :meth:`evolved_expectation_value()`
1030 * :meth:`evolved_expectation_value_all()`
1031 * :meth:`evolved_inner_product()`
1032 * :meth:`evolved_inner_product_all()`
1033 * :meth:`evolved_gate_infidelity()`
1034 * :meth:`gradient()`
1035 * :meth:`gate_gradient()`
1036 """
1037 ...
1038 def _eager_processing(self,
1039 ctrl_amp : np.ndarray[complex],
1040 initial_states : np.ndarray[complex],
1041 dt: float,
1042 frequencies: np.ndarray[complex],
1043 number_channels: list[int]
1044 ) -> tuple:
1045 """
1046 Executes :meth:`_pre_processing()` followed by
1047 :meth:`_envolope_processing()` eagerly (i.e. without using a
1048 `TensorFlow <https://www.tensorflow.org>`__ graph). Nonetheless,
1049 :meth:`_eager_processing()` is still auto differentiable.
1050
1051 Parameters
1052 ----------
1053 ctrl_amp : NDArray[Shape[n_time_steps, :attr:`n_ctrl`], complex]
1054 The envolope control amplitudes
1055 initial_state : NDArray[Shape[:attr:`state_shape`], complex]
1056 The initial state for the integrator
1057 dt : float
1058 The itegration time step
1059 frequencies : NDArray[Shape[n_time_steps, :attr:`n_ctrl`], complex]
1060 The frequencies to modulate the control amplitudes with
1061 number_channels : list[int]
1062 The number of channels associated with each control Hamiltonian
1063
1064 Warning
1065 -------
1066 This must be a ``list`` and not an ``NDArray`` or a
1067 `TensorFlow <https://www.tensorflow.org>`__ tensor.
1068
1069 Warning
1070 -------
1071 Keyword arguments are not supported.
1072
1073 Returns
1074 -------
1075 tuple[tf.Tensor[Shape[n_time_steps, :attr:`n_ctrl`], complex], tf.Tensor[Shape[:attr:`state_shape`], complex], tf.Tensor[Shape[], float]]
1076 A tuple of:
1077 1. Control amplitudes
1078 2. Initial state
1079 3. Integrator time step
1080 """
1081 ...
1082 def _traceable_eager_processing(self,
1083 ctrl_amp : np.ndarray[complex],
1084 initial_states : np.ndarray[complex],
1085 dt: float,
1086 frequencies: np.ndarray[complex],
1087 number_channels: list[int]
1088 ) -> tuple:
1089 """
1090 A function that will be traced by
1091 `TensorFlow <https://www.tensorflow.org>`__ to produce a graph of
1092 :meth:`_pre_processing()` followed by :meth:`_envolope_processing()`.
1093
1094 Parameters
1095 ----------
1096 ctrl_amp : NDArray[Shape[n_time_steps, :attr:`n_ctrl`], complex]
1097 The envolope control amplitudes
1098 initial_state : NDArray[Shape[:attr:`state_shape`], complex]
1099 The initial state for the integrator
1100 dt : float
1101 The itegration time step
1102 frequencies : NDArray[Shape[n_time_steps, :attr:`n_ctrl`], complex]
1103 The frequencies to modulate the control amplitudes with
1104 number_channels : list[int]
1105 The number of channels associated with each control Hamiltonian
1106
1107 Warning
1108 -------
1109 This must be a ``list`` and not an ``NDArray`` or a
1110 `TensorFlow <https://www.tensorflow.org>`__ tensor.
1111
1112 Warning
1113 -------
1114 Keyword arguments are not supported.
1115
1116 Returns
1117 -------
1118 tuple[tf.Tensor[Shape[n_time_steps, :attr:`n_ctrl`], complex], tf.Tensor[Shape[:attr:`state_shape`], complex], tf.Tensor[Shape[], float]]
1119 A tuple of:
1120 1. Control amplitudes
1121 2. Initial state
1122 3. Integrator time step
1123 """
1124 ...
[docs]
1125 def gradient(self,
1126 ctrl_amp : np.ndarray[complex],
1127 initial_state : np.ndarray[complex],
1128 dt: float,
1129 frequencies: np.ndarray[complex],
1130 number_channels: list[int],
1131 observable : np.ndarray[complex]
1132 ) -> tuple[float, np.ndarray[float]]:
1133 """
1134 Evolves a state vector under the time-dependent Hamiltonian defined by
1135 the control amplitudes and computes the expectation value of a specified
1136 observable with respect to the final state and then computes the
1137 gradient of the final state with respect to the first argument
1138 (``args[0]``) using
1139 :meth:`~py_ste.evolvers.DenseUnitaryEvolver.switching_function()`
1140 from `PySTE <https://PySTE.readthedocs.io>`__.
1141
1142 Parameters
1143 ----------
1144 ctrl_amp : tf.Tensor[Shape[n_time_steps, total_n_channels], tf.complex128]
1145 The envolope control amplitudes
1146 initial_state : NDArray[Shape[:attr:`state_shape`], complex]
1147 The initial state for the integrator
1148 dt : float
1149 The itegration time step
1150 frequencies : tf.Tensor[Shape[n_time_steps, total_n_channels], tf.complex128]
1151 The frequencies to modulate the control amplitudes with
1152 number_channels : list[int]
1153 The number of channels associated with each control Hamiltonian
1154
1155 Warning
1156 -------
1157 This must be a ``list`` and not an ``NDArray`` or a
1158 `TensorFlow <https://www.tensorflow.org>`__ tensor.
1159 observable : NDArray[Shape[:attr:`dim`, :attr:`dim`], complex]
1160 The observable to take the expectation value of.
1161
1162 Warning
1163 -------
1164 Keyword arguments are not supported.
1165
1166 Returns
1167 -------
1168 tuple[complex, NDArray[Shape[n_parameters], float]]
1169 A tuple of the expectation value and the gradient.
1170
1171 See Also
1172 --------
1173 * :meth:`evolved_expectation_value()`
1174 * :meth:`evolved_expectation_value_all()`
1175 """
1176 ...
[docs]
1177 def gate_gradient(self, *args) -> tuple[float, np.ndarray[float]]:
1178 """
1179 Evolves the system under the time-dependent Hamiltonian defined by
1180 the control amplitudes and computes the gate infidelity to the target
1181 gate and then computes the gradient with respect to the first argument
1182 (``args[0]``) using
1183 :meth:`~py_ste.evolvers.DenseUnitaryEvolver.gate_switching_function()`
1184 from `PySTE <https://PySTE.readthedocs.io>`__.
1185
1186 Parameters
1187 ----------
1188 ctrl_amp : tf.Tensor[Shape[n_time_steps, total_n_channels], tf.complex128]
1189 The envolope control amplitudes
1190 initial_state : NDArray[Shape[:attr:`state_shape`], complex]
1191 This is a redundant parameter for this function.
1192 dt : float
1193 The itegration time step
1194 frequencies : tf.Tensor[Shape[n_time_steps, total_n_channels], tf.complex128]
1195 The frequencies to modulate the control amplitudes with
1196 number_channels : list[int]
1197 The number of channels associated with each control Hamiltonian
1198
1199 Warning
1200 -------
1201 This must be a ``list`` and not an ``NDArray`` or a
1202 `TensorFlow <https://www.tensorflow.org>`__ tensor.
1203 observable : NDArray[Shape[:attr:`dim`, :attr:`dim`], complex]
1204 The observable to take the expectation value of.
1205
1206 Warning
1207 -------
1208 Keyword arguments are not supported.
1209
1210 Returns
1211 -------
1212 tuple[complex, NDArray[Shape[n_parameters], float]]
1213 A tuple of the gate infidelity value and the gradient.
1214
1215 See Also
1216 --------
1217 * :meth:`evolved_gate_infidelity()`
1218 * :meth:`gradient()`
1219 """
1220 ...
1247
1538