Source code for qugrad.systems._systems

   1"""
   2Defines classes for quantum systems
   3"""
   4
   5from typing import Callable, Optional, Union
   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    def __init__(self,
  51                 system: "QuantumSystem",
  52                 initial_state: np.ndarray[complex],
  53                 dt: float,
  54                 observable: np.ndarray[complex]):
  55        """
  56        Initialises the class with the `system` in which to take the expectation
  57        value and the `observable` in the `system` to take the expectation value
  58        of. Additionally, the initial state before evolution and
  59        the integrator time step are specified.
  60
  61        Parameters
  62        ----------
  63        system : QuantumSystem
  64            The system in which to take the expectation value
  65        initial_state : NDArray[Shape[``system.state_shape``], complex]
  66            The initial state for the integrator
  67        dt : float
  68            The integrator time step
  69        observable : NDArray[Shape[``system.dim``, ``system.dim``], complex])
  70            The observable to take the expectation value of
  71        """
  72        ...
  73    @tf.custom_gradient
  74    def run(self, ctrl_amp):
  75        """
  76        Computes the expectation value of the :attr:`observable` in the
  77        :attr:`system` with respect to the :attr:`initial_state` evolved under
  78        the Hamiltonian generated by the specified control amplitudes.
  79
  80        Parameters
  81        ----------
  82        ctrl_amp : tf.Tensor[Shape[n_time_steps, ``system.n_ctrl``], tf.complex128]
  83            The control amplitudes
  84
  85        Returns
  86        -------
  87        tf.Tensor[Shape[], tf.complex128]
  88            The expectation value
  89
  90        Note
  91        ----
  92        This function is differentiable using TensorFlow's ``tf.GradientTape``.
  93        """
  94        ...
  95
[docs] 96class QuantumSystem: 97 """ 98 A class storing the properties of a quantum system. 99 """ 100 _evolver: Optional[UnitaryEvolver] = None 101 "The integrator used for time evolutions of the system." 102 103 _hilbert_space: HilbertSpace 104 "The Hilbert space of the system" 105 106 _H0: np.ndarray 107 "The systems drift Hamiltonian as a :attr:`dim` x :attr:`dim` matrix." 108 109 _Hs: np.ndarray 110 """ 111 An array of the system's control Hamiltonians with shape 112 (:attr:`n_ctrl`, :attr:`dim`, :attr:`dim`). 113 """ 114 115 _graph_processing: Callable[..., tuple] 116 "A Tensorflow graph of :attr:`_processing()`" 117 118 _processing: Callable[..., tuple] 119 """ 120 Executes :meth:`_pre_processing()` followed by 121 :meth:`_envolope_processing()` eagerly (i.e. without using a TensorFlow 122 graph). Nonetheless, :meth:`_eager_processing()` is still auto 123 differentiable. 124 125 Parameters 126 ---------- 127 ctrl_amp : NDArray[Shape[n_time_steps, :attr:`n_ctrl`], complex] 128 The envolope control amplitudes 129 initial_state : NDArray[Shape[:attr:`state_shape`], complex] 130 The initial state for the integrator 131 dt : float 132 The itegration time step 133 frequencies : NDArray[Shape[n_time_steps, :attr:`n_ctrl`], complex] 134 The frequencies to modulate the control amplitudes with 135 number_channels : list[int] 136 The number of channels associated with each control Hamiltonian 137 138 Warning 139 ------- 140 This must be a ``list`` and not an ``NDArray`` or a 141 `TensorFlow <https://www.tensorflow.org>`__ tensor. 142 143 Returns 144 ------- 145 tuple[tf.Tensor[Shape[n_time_steps, :attr:`n_ctrl`], complex], tf.Tensor[Shape[:attr:`state_shape`], complex], tf.Tensor[Shape[], float]] 146 A tuple of: 147 1. Control amplitudes 148 2. Initial state 149 3. Integrator time step 150 """ 151 152 _using_graph: bool 153 """ 154 Whether to use TensorFlow graphs during computation. Using a TensorFlow 155 graph will increase the speed of computation. However, you have to be 156 careful that function parameters have not been baked into the graph leading 157 to unexpected behaviour. 158 """ 159
[docs] 160 def __init__(self, 161 H0: np.ndarray[complex], 162 Hs: np.ndarray[complex], 163 hilbert_space: HilbertSpace, 164 use_graph: bool = True): 165 """ 166 Initialises a new :class:`QuantumSystem`. 167 168 Parameters 169 ---------- 170 H0 : NDArray[Shape[:attr:`dim`, :attr:`dim`], complex] 171 The systems drift Hamiltonian 172 Hs : NDArray[Shape[:attr:`n_ctrl`, :attr:`dim`, :attr:`dim`], complex] | NDArray[Shape[:attr:`n_ctrl` * :attr:`dim`, :attr:`dim`], complex] 173 The systems control Hamiltonians either as an array of control 174 Hamiltonians or the control Hamiltonians stacked along the first 175 axis. 176 hilbert_space : HilbertSpace 177 The Hilbert space of the system 178 use_graph : bool = True 179 Whether to use TensorFlow graphs during computation. 180 """ 181 ...
182 183 def __del__(self): 184 # to force clear up of tracing 185 del self._graph_processing 186 del self._processing 187 @property 188 def using_graph(self) -> bool: 189 """ 190 Whether to use `TensorFlow <https://www.tensorflow.org>`__ graphs during 191 computation. Using a `TensorFlow <https://www.tensorflow.org>`__ graph 192 will increase the speed of computation. However, you have to be careful 193 that function parameters have not been baked into the graph leading to 194 unexpected behaviour. 195 """ 196 ... 197 @using_graph.setter 198 def using_graph(self, value: bool): 199 ... 200 @property 201 def hilbert_space(self) -> HilbertSpace: 202 "The Hilbert space of the system" 203 ... 204 @property 205 def H0(self) -> np.ndarray[complex]: 206 """ 207 The systems drift Hamiltonian as a :attr:`dim` x :attr:`dim` matrix. 208 209 See Also 210 -------- 211 :attr:`Hs` 212 """ 213 ... 214 @property 215 def Hs(self) -> np.ndarray[complex]: 216 """ 217 An array of the system's control Hamiltonians with shape 218 (:attr:`n_ctrl`, :attr:`dim`, :attr:`dim`). 219 220 See Also 221 -------- 222 :attr:`H0` 223 """ 224 ... 225 @property 226 def dim(self) -> int: 227 """ 228 The dimension of states in the quantum system. 229 230 See Also 231 -------- 232 :attr:`state_shape` 233 """ 234 ... 235 @property 236 def state_shape(self) -> tuple[int]: 237 """ 238 The shape of the states in the system. 239 240 See Also 241 -------- 242 :attr:`dim` 243 """ 244 ... 245 @property 246 def n_ctrl(self) -> int: 247 """ 248 The number of control Hamiltonians. 249 """ 250 ... 251 @property 252 def evolver(self) -> UnitaryEvolver: 253 """ 254 The integrator used for time evolutions of the system. 255 256 Note 257 ---- 258 The `evolver` can take a while to initialise and so is not initialised 259 until `evolver` is is first used or when :meth:`initialise_evolver()` is 260 called. Using `evolver` before calling :meth:`initialise_evolver()` 261 initialises the `evolver` with the default parameters of 262 :meth:`initialise_evolver()`. 263 """ 264 ...
[docs] 265 def initialise_evolver(self, 266 sparse: bool = False, 267 force_dynamic: bool = False): 268 """ 269 Initialises :attr:`evolver` with an evolver from 270 `PySTE <https://PySTE.readthedocs.io>`__. 271 `PySTE <https://PySTE.readthedocs.io>`__ is Python 272 wrapper around the C++ header-only library 273 `Suzuki-Trotter-Evolver <https://Suzuki-Trotter-Evolver.readthedocs.io>`__: 274 a fast Schrödinger solver utilising the first-order Suzuki-Trotter 275 expansion. 276 277 Warning 278 ------- 279 This can take a very long time to execute, especially for large Hilbert 280 space dimensions. If you plan to evolve the same quantum system many 281 times we recommended pickling the :attr:`evolver`. 282 283 Parameters 284 ---------- 285 sparse : bool 286 Whether to use sparse or dense matrices during integration. 287 To make a decision on whether sparse or dense matrices are likely to 288 lead to faster integration you can consult the benchmarks at 289 https://PySTE.readthedocs.io/en/latest/benchmarks. 290 force_dynamic : bool 291 Whether to force `PySTE <https://PySTE.readthedocs.io>`__ to use a 292 dynamic evolver. 293 294 Note 295 ---- 296 `PySTE <https://PySTE.readthedocs.io>`__ has precompiled evolvers 297 for specific Hilbert space dimensions and numbers of control 298 Hamiltonians. When these cannot be found 299 `PySTE <https://PySTE.readthedocs.io>`__ uses less efficient 300 evolvers with the Hilbert space dimension and the number of controls 301 determined dynamically at runtime. 302 """ 303 ...
304 def _H(self, ctrl_amp: np.ndarray[float]) -> np.ndarray[complex]: 305 """ 306 Computes the system Hamiltonian for the specified control amplitudes. 307 308 Parameters 309 ---------- 310 ctrl_amp : NDArray[Shape[s := Any_Shape, :attr:`n_ctrl`], float] 311 The control amplitudes (stored in the last axis). The prior axes 312 allow for multiple sets of control amplitudes to be passed and the 313 Hamiltonian for each computed. 314 315 Returns 316 ------- 317 NDArray[Shape[s, :attr:`dim`, :attr:`dim`], complex] 318 The system's Hamiltonian (stored in the last two axes). 319 """ 320 ...
[docs] 321 def H(self, 322 ctrl_amp: Union[np.ndarray[float], np.ndarray[Callable[[float], np.ndarray[float]]]] 323 ) -> Union[np.ndarray[complex], Callable[[float], np.ndarray[complex]]]: 324 """ 325 Computes the system Hamiltonian for the specified control amplitudes. 326 327 Parameters 328 ---------- 329 ctrl_amp : NDArray[Shape[s := Any_Shape, :attr:`n_ctrl`], float | Callable[[float], np.ndarray[float]]] 330 The control amplitudes (stored in the last axis). The prior axes 331 allow for multiple sets of control amplitudes to be passed and the 332 Hamiltonian for each computed. The control amplitudes can be passed 333 as ``np.ndarray[float]`` to compute the system Hamiltonian for a 334 specific value of the control ampltiudes. Alternatively, the control 335 amplitudes can be passed as 336 ``np.ndarray[Callable[[float], np.ndarray[float]]]`` where each 337 element is a function of time. This will generate a time-dependent 338 Hamiltonian: a function that takes a single parameter (time) and 339 returns the Hamiltonian at this time. 340 341 Returns 342 ------- 343 NDArray[Shape[s, :attr:`dim`, :attr:`dim`], complex] | NDArray[Shape[s], Callable[[float], np.ndarray[complex]]]] 344 Either the systems Hamiltonian stored in the last two axes (if 345 specific control amplitudes were passed) or a collection of 346 time-dependent Hamiltonians (if time-dependent controls were 347 passed). 348 """ 349 ...
[docs] 350 def _pre_processing(self, 351 ctrl_amp : np.ndarray[complex], 352 initial_state : np.ndarray[complex], 353 dt: float, 354 frequencies: np.ndarray[complex], 355 number_channels: list[int] 356 ) -> tuple: 357 """ 358 When calling any evolution method (listed in the 359 :ref:`See also section <pre_processing_see_also>`) :meth:`_pre_processing()` is 360 executed on the arguements before the control amplitudes are modulated 361 by the frequencies (during :meth:`_envolope_processing()`) and then finally 362 the modulated control amplitudes are used by the evolution method. 363 364 :meth:`_pre_processing()` should be overridden to produce desired pulse 365 shapes. You can either override :meth:`_pre_processing()` directly by 366 creating a child class, or you can use :meth:`pulse_form()`. 367 368 For :meth:`gradient()` to function correctly :meth:`_pre_processing()` 369 should be written in `TensorFlow <https://www.tensorflow.org>`__. 370 371 Parameters 372 ---------- 373 ctrl_amp : NDArray[Shape[n_time_steps, :attr:`n_ctrl`], complex] 374 The envolope control amplitudes 375 initial_state : NDArray[Shape[:attr:`state_shape`], complex] 376 The initial state for the integrator 377 dt : float 378 The itegration time step 379 frequencies : NDArray[Shape[n_time_steps, :attr:`n_ctrl`], complex] 380 The frequencies to modulate the control amplitudes with 381 number_channels : list[int] 382 The number of channels associated with each control Hamiltonian 383 384 Warning 385 ------- 386 This must be a ``list`` and not an ``NDArray`` or a 387 `TensorFlow <https://www.tensorflow.org>`__ tensor. 388 389 Returns 390 ------- 391 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]] 392 A tuple of 393 1. The control amplitude envolopes 394 2. The initial state 395 3. The integrator time step 396 4. The frequencies to modulate the control amplitude envolopes with 397 5. A list of the number of channels for each control Hamiltonian 398 399 Warning 400 ------- 401 The number of channels for each control Hamiltonian must be stored 402 as a ``list`` and not an ``NDArray`` or a 403 `TensorFlow <https://www.tensorflow.org>`__ tensor. 404 405 Warning 406 ------- 407 Keyword arguments are not supported. 408 409 .. _pre_processing_see_also: 410 411 See Also 412 -------- 413 * :meth:`propagate()` 414 * :meth:`propagate_collection()` 415 * :meth:`propagate_all()` 416 * :meth:`evolved_expectation_value()` 417 * :meth:`evolved_expectation_value_all()` 418 * :meth:`get_driving_pulses()` 419 * :meth:`gradient()` 420 """ 421 ...
[docs] 422 def _envolope_processing(self, 423 ctrl_amp, 424 dt: float, 425 frequencies, 426 number_channels: list[int] 427 ) -> tuple: 428 """ 429 When calling any evolution method (listed in the 430 :ref:`See also section <envolope_processing_see_also>` section) 431 :meth:`_pre_processing()` is executed on the arguements before the 432 control amplitudes are modulated by the frequencies during 433 :meth:`_envolope_processing()` and then finally the modulated control 434 amplitudes are used by the evolution method. 435 436 Parameters 437 ---------- 438 ctrl_amp : tf.Tensor[Shape[n_time_steps, total_n_channels], tf.complex128] 439 The envolope control amplitudes 440 dt : float 441 The itegration time step 442 frequencies : tf.Tensor[Shape[n_time_steps, total_n_channels], tf.complex128] 443 The frequencies to modulate the control amplitudes with 444 number_channels : list[int] 445 The number of channels associated with each control Hamiltonian 446 447 Warning 448 ------- 449 This must be a ``list`` and not an ``NDArray`` or a 450 `TensorFlow <https://www.tensorflow.org>`__ tensor. 451 452 Returns 453 ------- 454 tf.Tensor[Shape[n_time_steps, :attr:`n_ctrl`], tf.complex128] 455 The modulated control amplitudes 456 457 458 .. _envolope_processing_see_also: 459 460 See Also 461 -------- 462 * :meth:`propagate()` 463 * :meth:`propagate_collection()` 464 * :meth:`propagate_all()` 465 * :meth:`evolved_expectation_value()` 466 * :meth:`evolved_expectation_value_all()` 467 * :meth:`get_driving_pulses()` 468 * :meth:`gradient()` 469 """ 470 ...
[docs] 471 def propagate(self, 472 ctrl_amp : np.ndarray[complex], 473 initial_state : np.ndarray[complex], 474 dt: float, 475 frequencies: np.ndarray[complex], 476 number_channels: list[int] 477 ) -> np.ndarray[complex]: 478 """ 479 Evolves a state vector under the time-dependent Hamiltonian defined by 480 the control amplitudes using 481 :meth:`~py_ste.evolvers.DenseUnitaryEvolver.propagate()` 482 from `PySTE <https://PySTE.readthedocs.io>`__. 483 484 Parameters 485 ---------- 486 ctrl_amp : NDArray[Shape[n_time_steps, :attr:`n_ctrl`], complex] 487 The envolope control amplitudes 488 initial_state : NDArray[Shape[:attr:`state_shape`], complex] 489 The initial state for the integrator 490 dt : float 491 The itegration time step 492 frequencies : NDArray[Shape[n_time_steps, :attr:`n_ctrl`], complex] 493 The frequencies to modulate the control amplitudes with 494 number_channels : list[int] 495 The number of channels associated with each control Hamiltonian 496 497 Warning 498 ------- 499 This must be a ``list`` and not an ``NDArray`` or a 500 `TensorFlow <https://www.tensorflow.org>`__ tensor. 501 502 Warning 503 ------- 504 Keyword arguments are not supported. 505 506 Returns 507 ------- 508 NDArray[Shape[:attr:`state_shape`], complex] 509 The final state 510 511 See Also 512 -------- 513 * :meth:`propagate_collection()` 514 * :meth:`propagate_all()` 515 """ 516 ...
[docs] 517 def propagate_collection(self, 518 ctrl_amp : np.ndarray[complex], 519 initial_states : np.ndarray[complex], 520 dt: float, 521 frequencies: np.ndarray[complex], 522 number_channels: list[int] 523 ) -> np.ndarray[complex]: 524 """ 525 Evolves a collection of state vectors under the time-dependent 526 Hamiltonian defined by the control amplitudes using 527 :meth:`~py_ste.evolvers.DenseUnitaryEvolver.propagate_collection()` 528 from `PySTE <https://PySTE.readthedocs.io>`__. 529 530 Parameters 531 ---------- 532 ctrl_amp : NDArray[Shape[n_time_steps, :attr:`n_ctrl`], complex] 533 The envolope control amplitudes 534 initial_states : NDArray[Shape[n_states, :attr:`state_shape`], complex] 535 The initial state for the integrator 536 dt : float 537 The itegration time step 538 frequencies : NDArray[Shape[n_time_steps, :attr:`n_ctrl`], complex] 539 The frequencies to modulate the control amplitudes with 540 number_channels : list[int] 541 The number of channels associated with each control Hamiltonian 542 543 Warning 544 ------- 545 This must be a ``list`` and not an ``NDArray`` or a 546 `TensorFlow <https://www.tensorflow.org>`__ tensor. 547 548 Warning 549 ------- 550 Keyword arguments are not supported. 551 552 Returns 553 ------- 554 NDArray[Shape[n_states, :attr:`state_shape`], complex] 555 The final state 556 557 See Also 558 -------- 559 * :meth:`propagate()` 560 * :meth:`propagate_all()` 561 """ 562 ...
[docs] 563 def propagate_all(self, 564 ctrl_amp : np.ndarray[complex], 565 initial_states : np.ndarray[complex], 566 dt: float, 567 frequencies: np.ndarray[complex], 568 number_channels: list[int] 569 ) -> np.ndarray[complex]: 570 """ 571 Evolves a state vector under the time-dependent Hamiltonian defined by 572 the control amplitudes using 573 :meth:`~py_ste.evolvers.DenseUnitaryEvolver.propagate_all()` 574 from `PySTE <https://PySTE.readthedocs.io>`__ and returns the state at 575 each time-step. 576 577 Parameters 578 ---------- 579 ctrl_amp : NDArray[Shape[n_time_steps, :attr:`n_ctrl`], complex] 580 The envolope control amplitudes 581 initial_state : NDArray[Shape[:attr:`state_shape`], complex] 582 The initial state for the integrator 583 dt : float 584 The itegration time step 585 frequencies : NDArray[Shape[n_time_steps, :attr:`n_ctrl`], complex] 586 The frequencies to modulate the control amplitudes with 587 number_channels : list[int] 588 The number of channels associated with each control Hamiltonian 589 590 Warning 591 ------- 592 This must be a ``list`` and not an ``NDArray`` or a 593 `TensorFlow <https://www.tensorflow.org>`__ tensor. 594 595 Warning 596 ------- 597 Keyword arguments are not supported. 598 599 Returns 600 ------- 601 NDArray[Shape[n_time_steps+1, :attr:`state_shape`], complex] 602 The state at each integrator time step (including the initial 603 state). 604 605 See Also 606 -------- 607 * :meth:`propagate()` 608 * :meth:`propagate_collection()` 609 """ 610 ...
[docs] 611 def evolved_expectation_value(self, 612 ctrl_amp : np.ndarray[complex], 613 initial_state : np.ndarray[complex], 614 dt: float, 615 frequencies: np.ndarray[complex], 616 number_channels: list[int], 617 observable : np.ndarray[complex] 618 ) -> complex: 619 """ 620 Evolves a state vector under the time-dependent Hamiltonian defined by 621 the control amplitudes and computes the expectation value of a specified 622 observable with respect to the final state using 623 :meth:`~py_ste.evolvers.DenseUnitaryEvolver.evolved_expectation_value()` 624 from `PySTE <https://PySTE.readthedocs.io>`__. 625 626 Parameters 627 ---------- 628 ctrl_amp : tf.Tensor[Shape[n_time_steps, total_n_channels], tf.complex128] 629 The envolope control amplitudes 630 initial_state : NDArray[Shape[:attr:`state_shape`], complex] 631 The initial state for the integrator 632 dt : float 633 The itegration time step 634 frequencies : tf.Tensor[Shape[n_time_steps, total_n_channels], tf.complex128] 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 observable : NDArray[Shape[:attr:`dim`, :attr:`dim`], complex] 644 The observable to take the expectation value of. 645 646 Warning 647 ------- 648 Keyword arguments are not supported. 649 650 Returns 651 ------- 652 complex 653 The expectation value. 654 655 See Also 656 -------- 657 * :meth:`evolved_expectation_value_all()` 658 * :meth:`gradient()` 659 """ 660 ...
[docs] 661 def evolved_expectation_value_all(self, 662 ctrl_amp : np.ndarray[complex], 663 initial_state : np.ndarray[complex], 664 dt: float, 665 frequencies: np.ndarray[complex], 666 number_channels: list[int], 667 observable : np.ndarray[complex] 668 ) -> np.ndarray[complex]: 669 """ 670 Evolves a state vector under the time-dependent Hamiltonian defined by 671 the control amplitudes and computes the expectation value of a specified 672 observable with respect to the state at each time-step using 673 :meth:`~py_ste.evolvers.DenseUnitaryEvolver.evolved_expectation_value_all()` 674 from `PySTE <https://PySTE.readthedocs.io>`__. 675 676 Parameters 677 ---------- 678 ctrl_amp : tf.Tensor[Shape[n_time_steps, total_n_channels], tf.complex128] 679 The envolope control amplitudes 680 initial_state : NDArray[Shape[:attr:`state_shape`], complex] 681 The initial state for the integrator 682 dt : float 683 The itegration time step 684 frequencies : tf.Tensor[Shape[n_time_steps, total_n_channels], tf.complex128] 685 The frequencies to modulate the control amplitudes with 686 number_channels : list[int] 687 The number of channels associated with each control Hamiltonian 688 689 Warning 690 ------- 691 This must be a ``list`` and not an ``NDArray`` or a 692 `TensorFlow <https://www.tensorflow.org>`__ tensor. 693 observable : NDArray[Shape[:attr:`dim`, :attr:`dim`], complex] 694 The observable to take the expectation value of. 695 696 Warning 697 ------- 698 Keyword arguments are not supported. 699 700 Returns 701 ------- 702 NDArray[Shape[n_time_steps+1], complex] 703 The state at each integrator time step (including the initial 704 state). 705 706 See Also 707 -------- 708 * :meth:`evolved_expectation_value()` 709 * :meth:`gradient()` 710 """ 711 ...
[docs] 712 def get_driving_pulses(self, 713 ctrl_amp : np.ndarray[complex], 714 initial_states : np.ndarray[complex], 715 dt: float, 716 frequencies: np.ndarray[complex], 717 number_channels: list[int] 718 ) -> tuple[np.ndarray[complex], np.ndarray[complex], float]: 719 """ 720 When calling any evolution method (listed in the 721 :ref:`See also section <get_driving_pulses_see_also>`) :meth:`get_driving_pulses()` 722 is executed on the arguements before the evolution method. 723 724 Parameters 725 ---------- 726 ctrl_amp : NDArray[Shape[n_time_steps, :attr:`n_ctrl`], complex] 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 : NDArray[Shape[n_time_steps, :attr:`n_ctrl`], complex] 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 742 Warning 743 ------- 744 Keyword arguments are not supported. 745 746 Returns 747 ------- 748 tuple[NDArray[Shape[n_time_steps, :attr:`n_ctrl`], complex], NDArray[Shape[:attr:`state_shape`], complex], float] 749 A tuple of: 750 1. Control amplitudes 751 2. Initial state 752 3. Integrator time step 753 754 755 .. _get_driving_pulses_see_also: 756 757 See Also 758 -------- 759 * :meth:`propagate()` 760 * :meth:`propagate_collection()` 761 * :meth:`propagate_all()` 762 * :meth:`evolved_expectation_value()` 763 * :meth:`evolved_expectation_value_all()` 764 * :meth:`gradient()` 765 """ 766 ...
767 def _eager_processing(self, 768 ctrl_amp : np.ndarray[complex], 769 initial_states : np.ndarray[complex], 770 dt: float, 771 frequencies: np.ndarray[complex], 772 number_channels: list[int] 773 ) -> tuple: 774 """ 775 Executes :meth:`_pre_processing()` followed by 776 :meth:`_envolope_processing()` eagerly (i.e. without using a 777 `TensorFlow <https://www.tensorflow.org>`__ graph). Nonetheless, 778 :meth:`_eager_processing()` is still auto differentiable. 779 780 Parameters 781 ---------- 782 ctrl_amp : NDArray[Shape[n_time_steps, :attr:`n_ctrl`], complex] 783 The envolope control amplitudes 784 initial_state : NDArray[Shape[:attr:`state_shape`], complex] 785 The initial state for the integrator 786 dt : float 787 The itegration time step 788 frequencies : NDArray[Shape[n_time_steps, :attr:`n_ctrl`], complex] 789 The frequencies to modulate the control amplitudes with 790 number_channels : list[int] 791 The number of channels associated with each control Hamiltonian 792 793 Warning 794 ------- 795 This must be a ``list`` and not an ``NDArray`` or a 796 `TensorFlow <https://www.tensorflow.org>`__ tensor. 797 798 Warning 799 ------- 800 Keyword arguments are not supported. 801 802 Returns 803 ------- 804 tuple[tf.Tensor[Shape[n_time_steps, :attr:`n_ctrl`], complex], tf.Tensor[Shape[:attr:`state_shape`], complex], tf.Tensor[Shape[], float]] 805 A tuple of: 806 1. Control amplitudes 807 2. Initial state 808 3. Integrator time step 809 """ 810 ... 811 def _traceable_eager_processing(self, 812 ctrl_amp : np.ndarray[complex], 813 initial_states : np.ndarray[complex], 814 dt: float, 815 frequencies: np.ndarray[complex], 816 number_channels: list[int] 817 ) -> tuple: 818 """ 819 A function that will be traced by 820 `TensorFlow <https://www.tensorflow.org>`__ to produce a graph of 821 :meth:`_pre_processing()` followed by :meth:`_envolope_processing()`. 822 823 Parameters 824 ---------- 825 ctrl_amp : NDArray[Shape[n_time_steps, :attr:`n_ctrl`], complex] 826 The envolope control amplitudes 827 initial_state : NDArray[Shape[:attr:`state_shape`], complex] 828 The initial state for the integrator 829 dt : float 830 The itegration time step 831 frequencies : NDArray[Shape[n_time_steps, :attr:`n_ctrl`], complex] 832 The frequencies to modulate the control amplitudes with 833 number_channels : list[int] 834 The number of channels associated with each control Hamiltonian 835 836 Warning 837 ------- 838 This must be a ``list`` and not an ``NDArray`` or a 839 `TensorFlow <https://www.tensorflow.org>`__ tensor. 840 841 Warning 842 ------- 843 Keyword arguments are not supported. 844 845 Returns 846 ------- 847 tuple[tf.Tensor[Shape[n_time_steps, :attr:`n_ctrl`], complex], tf.Tensor[Shape[:attr:`state_shape`], complex], tf.Tensor[Shape[], float]] 848 A tuple of: 849 1. Control amplitudes 850 2. Initial state 851 3. Integrator time step 852 """ 853 ...
[docs] 854 def gradient(self, 855 ctrl_amp : np.ndarray[complex], 856 initial_state : np.ndarray[complex], 857 dt: float, 858 frequencies: np.ndarray[complex], 859 number_channels: list[int], 860 observable : np.ndarray[complex] 861 ) -> tuple[float, np.ndarray[float]]: 862 """ 863 Evolves a state vector under the time-dependent Hamiltonian defined by 864 the control amplitudes and computes the expectation value of a specified 865 observable with respect to the final state and then computes the 866 gradient of the final state with respect to the first argument 867 (``args[0]``) using 868 :meth:`~py_ste.evolvers.DenseUnitaryEvolver.switching_function()` 869 from `PySTE <https://PySTE.readthedocs.io>`__. 870 871 Parameters 872 ---------- 873 ctrl_amp : tf.Tensor[Shape[n_time_steps, total_n_channels], tf.complex128] 874 The envolope control amplitudes 875 initial_state : NDArray[Shape[:attr:`state_shape`], complex] 876 The initial state for the integrator 877 dt : float 878 The itegration time step 879 frequencies : tf.Tensor[Shape[n_time_steps, total_n_channels], tf.complex128] 880 The frequencies to modulate the control amplitudes with 881 number_channels : list[int] 882 The number of channels associated with each control Hamiltonian 883 884 Warning 885 ------- 886 This must be a ``list`` and not an ``NDArray`` or a 887 `TensorFlow <https://www.tensorflow.org>`__ tensor. 888 observable : NDArray[Shape[:attr:`dim`, :attr:`dim`], complex] 889 The observable to take the expectation value of. 890 891 Warning 892 ------- 893 Keyword arguments are not supported. 894 895 Returns 896 ------- 897 tuple[complex, NDArray[Shape[n_parameters], float]] 898 A tuple of the expectation value and the gradient. 899 900 See Also 901 -------- 902 * :meth:`evolved_expectation_value()` 903 * :meth:`evolved_expectation_value_all()` 904 """ 905 ...
[docs] 906 def pulse_form(self, 907 pulse_function: Callable, 908 path: Optional[str] = None 909 ) -> "PulseForm": 910 """ 911 Initialises a new :class:`QuantumSystem` in which 912 :meth:`_pre_processing()` corresponds to executing ``pulse_function()`` 913 and piping the output into the previous definition of 914 :meth:`_pre_processing()`. 915 916 Parameters 917 ---------- 918 pulse_function : Callable 919 The function to compose with :meth:`_pre_processing()`. 920 921 Returns 922 ------- 923 PulseForm 924 The new :class:`QuantumSystem` 925 """ 926 ...
927
[docs] 928class TransformedSystem(QuantumSystem): 929 """ 930 A base class for representing a transformation on a :class:`qugrad.QuantumSystem`. 931 """ 932 933 _original_system: QuantumSystem 934 "The system that was transformed into this system" 935 936 _base_system: QuantumSystem 937 """ 938 The system before any transformations were applied. That is `_base_system` 939 is the recursive :attr:`original_system` 940 (``original_system.original_system.original_system....``) until 941 :attr:`original_system` is no longer a :class:`TransformedSystem`. 942 """ 943
[docs] 944 def __init__(self, 945 original_system: QuantumSystem, 946 H0: np.ndarray[complex], 947 Hs: Union[np.ndarray[complex], np.ndarray[complex]], 948 hilbert_space: HilbertSpace): 949 """ 950 Performs a transformation on a :class:`qugrad.QuantumSystem`. 951 952 Parameters 953 ---------- 954 original_system: QuantumSystem 955 The system to be transformed into this system 956 H0: NDArray[Shape[:attr:`dim`, :attr:`dim`], complex] 957 The new drift Hamiltonian 958 Hs: NDArray[Shape[":attr:`n_ctrl`, :attr:`dim`, :attr:`dim`"], complex] | NDArray[Shape[:attr:`n_ctrl` * :attr:`dim`, :attr:`dim`], complex] 959 The new control Hamiltonians either as an array of control 960 Hamiltonians or the control Hamiltonians stacked along the first 961 axis. 962 hilbert_space: HilbertSpace 963 The new Hilbert space of the system 964 """ 965 ...
966 @property 967 def original_system(self) -> QuantumSystem: 968 "The system that was transformed into this system" 969 ... 970 @property 971 def base_system(self) -> QuantumSystem: 972 """ 973 The system before any transformations were applied. That is 974 :attr:`base_system` is the recursive :attr:`original_system` 975 (``original_system.original_system.original_system....``) until 976 :attr:`original_system` is no longer a :class:`TransformedSystem`. 977 """ 978 ...
[docs] 979 def _pre_processing(self, *args): 980 """ 981 When calling any evolution method (listed in the 982 :ref:`See also section <TransformedSystem_pre_processing_see_also>` 983 section) :meth:`_pre_processing()` is executed on the arguements before 984 the control amplitudes are modulated by the frequencies (during 985 :meth:`_envolope_processing()`) and then finally the modulated control 986 amplitudes are used by the evolution method. 987 988 This is a placeholder for ``original_system._pre_processing()``. 989 990 Parameters 991 ---------- 992 *args 993 The placeholder parameters. The actual parameters will be the same 994 as ``original_system._pre_processing()``. 995 996 Returns 997 ------- 998 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]] 999 A tuple of 1000 1. The control amplitude envolopes 1001 2. The initial state 1002 3. The integrator time step 1003 4. The frequencies to modulate the control amplitude envolopes with 1004 5. A list of the number of channels for each control Hamiltonian 1005 1006 Warning 1007 ------- 1008 The number of channels for each control Hamiltonian must be stored 1009 as a ``list`` and not an ``NDArray`` or a 1010 `TensorFlow <https://www.tensorflow.org>`__ tensor. 1011 1012 1013 .. _TransformedSystem_pre_processing_see_also: 1014 1015 See Also 1016 -------- 1017 * :meth:`propagate()` 1018 * :meth:`propagate_collection()` 1019 * :meth:`propagate_all()` 1020 * :meth:`evolved_expectation_value()` 1021 * :meth:`evolved_expectation_value_all()` 1022 * :meth:`get_driving_pulses()` 1023 * :meth:`gradient()` 1024 """ 1025 ...
[docs] 1026 def propagate(self, *args) -> np.ndarray[complex]: 1027 """ 1028 Evolves a state vector under the time-dependent Hamiltonian defined by 1029 the control amplitudes using 1030 :meth:`~py_ste.evolvers.DenseUnitaryEvolver.propagate()` 1031 from `PySTE <https://PySTE.readthedocs.io>`__. 1032 1033 Parameters 1034 ---------- 1035 *args 1036 The placeholder parameters. The actual parameters will be the same 1037 as ``original_system._pre_processing()``. 1038 1039 Returns 1040 ------- 1041 NDArray[Shape[:attr:`state_shape`], complex] 1042 The final state 1043 1044 See Also 1045 -------- 1046 * :meth:`propagate_collection()` 1047 * :meth:`propagate_all()` 1048 """ 1049 ...
[docs] 1050 def propagate_collection(self, *args) -> np.ndarray[complex]: 1051 """ 1052 Evolves a collection of state vectors under the time-dependent 1053 Hamiltonian defined by the control amplitudes using 1054 :meth:`~py_ste.evolvers.DenseUnitaryEvolver.propagate_collection()` 1055 from `PySTE <https://PySTE.readthedocs.io>`__. 1056 1057 Parameters 1058 ---------- 1059 *args 1060 The placeholder parameters. The actual parameters will be the same 1061 as ``original_system._pre_processing()``. 1062 1063 Returns 1064 ------- 1065 NDArray[Shape[n_states, :attr:`state_shape`], complex] 1066 The final state 1067 1068 See Also 1069 -------- 1070 * :meth:`propagate()` 1071 * :meth:`propagate_all()` 1072 """ 1073 ...
[docs] 1074 def propagate_all(self, *args) -> np.ndarray[complex]: 1075 """ 1076 Evolves a state vector under the time-dependent Hamiltonian defined by 1077 the control amplitudes using 1078 :meth:`~py_ste.evolvers.DenseUnitaryEvolver.propagate_all()` 1079 from `PySTE <https://PySTE.readthedocs.io>`__ and returns the state at 1080 each time-step. 1081 1082 Parameters 1083 ---------- 1084 *args 1085 The placeholder parameters. The actual parameters will be the same 1086 as ``original_system._pre_processing()``. 1087 1088 Returns 1089 ------- 1090 NDArray[Shape[n_time_steps+1, :attr:`state_shape`], complex] 1091 The state at each integrator time step (including the initial 1092 state). 1093 1094 See Also 1095 -------- 1096 * :meth:`propagate()` 1097 * :meth:`propagate_collection()` 1098 """ 1099 ...
[docs] 1100 def evolved_expectation_value(self, *args) -> complex: 1101 """ 1102 Evolves a state vector under the time-dependent Hamiltonian defined by 1103 the control amplitudes and computes the expectation value of a specified 1104 observable with respect to the final state using 1105 :meth:`~py_ste.evolvers.DenseUnitaryEvolver.evolved_expectation_value()` 1106 from `PySTE <https://PySTE.readthedocs.io>`__. 1107 1108 Parameters 1109 ---------- 1110 ``*args[:-1]`` 1111 The placeholder parameters. The actual parameters will be the same 1112 as ``original_system._pre_processing()``. 1113 ``args[-1]`` : NDArray[Shape[:attr:`dim`, :attr:`dim`], complex] 1114 The observable to take the expectation value of. 1115 1116 1117 Returns 1118 ------- 1119 complex 1120 The expectation value. 1121 1122 See Also 1123 -------- 1124 * :meth:`evolved_expectation_value_all()` 1125 * :meth:`gradient()` 1126 """ 1127 ...
[docs] 1128 def evolved_expectation_value_all(self, *args) -> np.ndarray[complex]: 1129 """ 1130 Evolves a state vector under the time-dependent Hamiltonian defined by 1131 the control amplitudes and computes the expectation value of a specified 1132 observable with respect to the state at each time-step using 1133 :meth:`~py_ste.evolvers.DenseUnitaryEvolver.evolved_expectation_value_all()` 1134 from `PySTE <https://PySTE.readthedocs.io>`__. 1135 1136 Parameters 1137 ---------- 1138 ``*args[:-1]`` 1139 The placeholder parameters. The actual parameters will be the same 1140 as ``original_system._pre_processing()``. 1141 ``args[-1]`` : NDArray[Shape[:attr:`dim`, :attr:`dim`], complex] 1142 The observable to take the expectation value of. 1143 1144 Returns 1145 ------- 1146 NDArray[Shape[n_time_steps+1], complex] 1147 The state at each integrator time step (including the initial 1148 state). 1149 1150 See Also 1151 -------- 1152 * :meth:`evolved_expectation_value()` 1153 * :meth:`gradient()` 1154 """ 1155 ...
[docs] 1156 def get_driving_pulses(self, *args) -> tuple[np.ndarray[complex], np.ndarray[complex], float]: 1157 """ 1158 When calling any evolution method (listed in the 1159 :ref:`See also section <get_driving_pulses_see_also>`) :meth:`get_driving_pulses()` 1160 is executed on the arguements before the evolution method. 1161 1162 Parameters 1163 ---------- 1164 *args 1165 The placeholder parameters. The actual parameters will be the same 1166 as ``original_system._pre_processing()``. 1167 1168 Returns 1169 ------- 1170 tuple[NDArray[Shape[n_time_steps, :attr:`n_ctrl`], complex], NDArray[Shape[:attr:`state_shape`], complex], float] 1171 A tuple of: 1172 1. Control amplitudes 1173 2. Initial state 1174 3. Integrator time step 1175 1176 1177 .. _get_driving_pulses_see_also: 1178 1179 See Also 1180 -------- 1181 * :meth:`propagate()` 1182 * :meth:`propagate_collection()` 1183 * :meth:`propagate_all()` 1184 * :meth:`evolved_expectation_value()` 1185 * :meth:`evolved_expectation_value_all()` 1186 * :meth:`gradient()` 1187 """ 1188 ...
[docs] 1189 def gradient(self, *args) -> tuple[float, np.ndarray[float]]: 1190 """ 1191 Evolves a state vector under the time-dependent Hamiltonian defined by 1192 the control amplitudes and computes the expectation value of a specified 1193 observable with respect to the final state and then computes the 1194 gradient of the final state with respect to the first argument 1195 (``args[0]``) using 1196 :meth:`~py_ste.evolvers.DenseUnitaryEvoler.switching_function()` 1197 from `PySTE <https://PySTE.readthedocs.io>`__. 1198 1199 Parameters 1200 ---------- 1201 ``*args[:-1]`` 1202 The placeholder parameters. The actual parameters will be the same 1203 as ``original_system._pre_processing()``. 1204 ``args[-1]`` : NDArray[Shape[:attr:`dim`, :attr:`dim`], complex] 1205 The observable to take the expectation value of. 1206 1207 Returns 1208 ------- 1209 tuple[complex, NDArray[Shape[n_parameters], float]] 1210 A tuple of the expectation value and the gradient. 1211 1212 See Also 1213 -------- 1214 * :meth:`evolved_expectation_value()` 1215 * :meth:`evolved_expectation_value_all()` 1216 """ 1217 ...
1218
[docs] 1219class PulseForm(TransformedSystem): 1220 """ 1221 A transformed :class:`qugrad.QuantumSystem` in which :meth:`_pre_processing()` 1222 has been composed with another pre processing function. 1223 """
[docs] 1224 def __init__(self, 1225 original_system: QuantumSystem, 1226 pulse_function: Callable, 1227 append: bool = False): 1228 """ 1229 Initialises a new :class:`qugrad.QuantumSystem` in which :meth:`_pre_processing()` 1230 corresponds to running ``pulse_function()`` and piping the output into 1231 ``original_system._pre_processing()``. 1232 1233 Parameters 1234 ---------- 1235 original_system : QuantumSystem 1236 The system that was transformed into this system 1237 pulse_function : Callable 1238 The function to compose with :meth:`_pre_processing()`. 1239 append : bool 1240 Whether to prepend 1241 (``original_system._pre_processing(*pulse_function())``) 1242 or append (``pulse_function(*original_system._pre_processing())``) 1243 ``pulse_function``. 1244 """ 1245 ...
[docs] 1246 def _pre_processing(self, *args): 1247 """ 1248 When calling any evolution method (listed in the 1249 :ref:`See also section <PulseForm_pre_processing_see_also>` 1250 section) :meth:`_pre_processing()` is executed on the arguements before 1251 the control amplitudes are modulated by the frequencies (during 1252 :meth:`_envolope_processing()`) and then finally the modulated control 1253 amplitudes are used by the evolution method. 1254 1255 This is a placeholder for 1256 ``original_system._pre_processing(*pulse_function())`` 1257 (or ``pulse_function(*original_system._pre_processing())`` if 1258 attr:`appended` is ``True``). 1259 1260 Parameters 1261 ---------- 1262 *args 1263 The placeholder parameters. The actual parameters will be the same 1264 as :attr:`pulse_function` if ``append`` is ``False`` or 1265 ``original_system._pre_processing()`` if ``append`` is ``True``. 1266 1267 Returns 1268 ------- 1269 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]] 1270 A tuple of 1271 1. The control amplitude envolopes 1272 2. The initial state 1273 3. The integrator time step 1274 4. The frequencies to modulate the control amplitude envolopes with 1275 5. A list of the number of channels for each control Hamiltonian 1276 1277 Warning 1278 ------- 1279 The number of channels for each control Hamiltonian must be stored 1280 as a ``list`` and not an ``NDArray`` or a 1281 `TensorFlow <https://www.tensorflow.org>`__ tensor. 1282 1283 1284 .. _PulseForm_pre_processing_see_also: 1285 1286 See Also 1287 -------- 1288 * :meth:`propagate()` 1289 * :meth:`propagate_collection()` 1290 * :meth:`propagate_all()` 1291 * :meth:`evolved_expectation_value()` 1292 * :meth:`evolved_expectation_value_all()` 1293 * :meth:`get_driving_pulses()` 1294 * :meth:`gradient()` 1295 """ 1296 ...
[docs] 1297 def propagate(self, *args) -> np.ndarray[complex]: 1298 """ 1299 Evolves a state vector under the time-dependent Hamiltonian defined by 1300 the control amplitudes using 1301 :meth:`~py_ste.evolvers.DenseUnitaryEvolver.propagate()` 1302 from `PySTE <https://PySTE.readthedocs.io>`__. 1303 1304 Parameters 1305 ---------- 1306 *args 1307 The placeholder parameters. The actual parameters will be the same 1308 as :attr:`pulse_function` if ``append`` is ``False`` or 1309 ``original_system._pre_processing()`` if ``append`` is ``True``. 1310 1311 Returns 1312 ------- 1313 NDArray[Shape[:attr:`state_shape`], complex] 1314 The final state 1315 1316 See Also 1317 -------- 1318 * :meth:`propagate_collection()` 1319 * :meth:`propagate_all()` 1320 """ 1321 ...
[docs] 1322 def propagate_collection(self, *args) -> np.ndarray[complex]: 1323 """ 1324 Evolves a collection of state vectors under the time-dependent 1325 Hamiltonian defined by the control amplitudes using 1326 :meth:`~py_ste.evolvers.DenseUnitaryEvolver.propagate_collection()` 1327 from `PySTE <https://PySTE.readthedocs.io>`__. 1328 1329 Parameters 1330 ---------- 1331 *args 1332 The placeholder parameters. The actual parameters will be the same 1333 as :attr:`pulse_function` if ``append`` is ``False`` or 1334 ``original_system._pre_processing()`` if ``append`` is ``True``. 1335 1336 Returns 1337 ------- 1338 NDArray[Shape[n_states, :attr:`state_shape`], complex] 1339 The final state 1340 1341 See Also 1342 -------- 1343 * :meth:`propagate()` 1344 * :meth:`propagate_all()` 1345 """ 1346 ...
[docs] 1347 def propagate_all(self, *args) -> np.ndarray[complex]: 1348 """ 1349 Evolves a state vector under the time-dependent Hamiltonian defined by 1350 the control amplitudes using 1351 :meth:`~py_ste.evolvers.DenseUnitaryEvolver.propagate_all()` 1352 from `PySTE <https://PySTE.readthedocs.io>`__ and returns the state at 1353 each time-step. 1354 1355 Parameters 1356 ---------- 1357 *args 1358 The placeholder parameters. The actual parameters will be the same 1359 as :attr:`pulse_function` if ``append`` is ``False`` or 1360 ``original_system._pre_processing()`` if ``append`` is ``True``. 1361 1362 Returns 1363 ------- 1364 NDArray[Shape[n_time_steps+1, :attr:`state_shape`], complex] 1365 The state at each integrator time step (including the initial 1366 state). 1367 1368 See Also 1369 -------- 1370 * :meth:`propagate()` 1371 * :meth:`propagate_collection()` 1372 """ 1373 ...
[docs] 1374 def evolved_expectation_value(self, *args) -> complex: 1375 """ 1376 Evolves a state vector under the time-dependent Hamiltonian defined by 1377 the control amplitudes and computes the expectation value of a specified 1378 observable with respect to the final state using 1379 :meth:`~py_ste.evolvers.DenseUnitaryEvolver.evolved_expectation_value()` 1380 from `PySTE <https://PySTE.readthedocs.io>`__. 1381 1382 Parameters 1383 ---------- 1384 ``*args[:-1]`` 1385 The placeholder parameters. The actual parameters will be the same 1386 as :attr:`pulse_function` if ``append`` is ``False`` or 1387 ``original_system._pre_processing()`` if ``append`` is ``True``. 1388 ``args[-1]`` : NDArray[Shape[:attr:`dim`, :attr:`dim`], complex] 1389 The observable to take the expectation value of. 1390 1391 1392 Returns 1393 ------- 1394 complex 1395 The expectation value. 1396 1397 See Also 1398 -------- 1399 * :meth:`evolved_expectation_value_all()` 1400 * :meth:`gradient()` 1401 """ 1402 ...
[docs] 1403 def evolved_expectation_value_all(self, *args) -> np.ndarray[complex]: 1404 """ 1405 Evolves a state vector under the time-dependent Hamiltonian defined by 1406 the control amplitudes and computes the expectation value of a specified 1407 observable with respect to the state at each time-step using 1408 :meth:`~py_ste.evolvers.DenseUnitaryEvolver.evolved_expectation_value_all()` 1409 from `PySTE <https://PySTE.readthedocs.io>`__. 1410 1411 Parameters 1412 ---------- 1413 ``*args[:-1]`` 1414 The placeholder parameters. The actual parameters will be the same 1415 as :attr:`pulse_function` if ``append`` is ``False`` or 1416 ``original_system._pre_processing()`` if ``append`` is ``True``. 1417 ``args[-1]`` : NDArray[Shape[:attr:`dim`, :attr:`dim`], complex] 1418 The observable to take the expectation value of. 1419 1420 Returns 1421 ------- 1422 NDArray[Shape[n_time_steps+1], complex] 1423 The state at each integrator time step (including the initial 1424 state). 1425 1426 See Also 1427 -------- 1428 * :meth:`evolved_expectation_value()` 1429 * :meth:`gradient()` 1430 """ 1431 ...
[docs] 1432 def get_driving_pulses(self, *args) -> tuple[np.ndarray[complex], np.ndarray[complex], float]: 1433 """ 1434 When calling any evolution method (listed in the 1435 :ref:`See also section <get_driving_pulses_see_also>`) :meth:`get_driving_pulses()` 1436 is executed on the arguements before the evolution method. 1437 1438 Parameters 1439 ---------- 1440 *args 1441 The placeholder parameters. The actual parameters will be the same 1442 as :attr:`pulse_function` if ``append`` is ``False`` or 1443 ``original_system._pre_processing()`` if ``append`` is ``True``. 1444 1445 Returns 1446 ------- 1447 tuple[NDArray[Shape[n_time_steps, :attr:`n_ctrl`], complex], NDArray[Shape[:attr:`state_shape`], complex], float] 1448 A tuple of: 1449 1. Control amplitudes 1450 2. Initial state 1451 3. Integrator time step 1452 1453 1454 .. _get_driving_pulses_see_also: 1455 1456 See Also 1457 -------- 1458 * :meth:`propagate()` 1459 * :meth:`propagate_collection()` 1460 * :meth:`propagate_all()` 1461 * :meth:`evolved_expectation_value()` 1462 * :meth:`evolved_expectation_value_all()` 1463 * :meth:`gradient()` 1464 """ 1465 ...
[docs] 1466 def gradient(self, *args) -> tuple[float, np.ndarray[float]]: 1467 """ 1468 Evolves a state vector under the time-dependent Hamiltonian defined by 1469 the control amplitudes and computes the expectation value of a specified 1470 observable with respect to the final state and then computes the 1471 gradient of the final state with respect to the first argument 1472 (``args[0]``) using 1473 :meth:`~py_ste.evolvers.DenseUnitaryEvoler.switching_function()` 1474 from `PySTE <https://PySTE.readthedocs.io>`__. 1475 1476 Parameters 1477 ---------- 1478 ``*args[:-1]`` 1479 The placeholder parameters. The actual parameters will be the same 1480 as :attr:`pulse_function` if ``append`` is ``False`` or 1481 ``original_system._pre_processing()`` if ``append`` is ``True``. 1482 ``args[-1]`` : NDArray[Shape[:attr:`dim`, :attr:`dim`], complex] 1483 The observable to take the expectation value of. 1484 1485 Returns 1486 ------- 1487 tuple[complex, NDArray[Shape[n_parameters], float]] 1488 A tuple of the expectation value and the gradient. 1489 1490 See Also 1491 -------- 1492 * :meth:`evolved_expectation_value()` 1493 * :meth:`evolved_expectation_value_all()` 1494 """ 1495 ...