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