Source code for qugrad.systems._systems

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