@@ -283,6 +283,7 @@ def __init__(self, *args, **kwargs) -> None:
283
283
self ._filter_function_gen = None
284
284
self ._filter_function_pc = None
285
285
self ._filter_function_pc_gen = None
286
+ self ._filter_function_2 = None
286
287
self ._intermediates = dict ()
287
288
288
289
def __str__ (self ):
@@ -402,6 +403,7 @@ def is_cached(self, attr: str) -> bool:
402
403
'pulse correlation filter function' : '_filter_function_pc' ,
403
404
'fidelity pulse correlation filter function' : '_filter_function_pc' ,
404
405
'generalized pulse correlation filter function' : '_filter_function_pc_gen' ,
406
+ 'second order filter function' : '_filter_function_2' ,
405
407
'control matrix' : '_control_matrix' ,
406
408
'pulse correlation control matrix' : '_control_matrix_pc'
407
409
}
@@ -420,8 +422,9 @@ def diagonalize(self) -> None:
420
422
# Only calculate if not done so before
421
423
if not all (self .is_cached (attr ) for attr in ('eigvals' , 'eigvecs' , 'propagators' )):
422
424
# Control Hamiltonian as a (n_dt, d, d) array
423
- H = np .einsum ('ijk,il->ljk' , self .c_opers , self .c_coeffs )
424
- self .eigvals , self .eigvecs , self .propagators = numeric .diagonalize (H , self .dt )
425
+ hamiltonian = np .einsum ('ijk,il->ljk' , self .c_opers , self .c_coeffs )
426
+ self .eigvals , self .eigvecs , self .propagators = numeric .diagonalize (hamiltonian ,
427
+ self .dt )
425
428
426
429
# Set the total propagator
427
430
self .total_propagator = self .propagators [- 1 ]
@@ -530,11 +533,15 @@ def get_pulse_correlation_control_matrix(self) -> ndarray:
530
533
"True."
531
534
)
532
535
533
- @util .parse_which_FF_parameter
534
- def get_filter_function (self , omega : Coefficients , which : str = 'fidelity' ,
535
- show_progressbar : bool = False ,
536
- cache_intermediates : bool = False ) -> ndarray :
537
- r"""Get the first-order filter function.
536
+ @util .parse_optional_parameters ({'which' : ('fidelity' , 'generalized' ), 'order' : (1 , 2 )})
537
+ def get_filter_function (
538
+ self , omega : Coefficients ,
539
+ which : str = 'fidelity' ,
540
+ order : int = 1 ,
541
+ show_progressbar : bool = False ,
542
+ cache_intermediates : bool = False
543
+ ) -> ndarray :
544
+ r"""Get the first or second order filter function.
538
545
539
546
The filter function is cached so it doesn't need to be
540
547
calculated twice for the same frequencies.
@@ -545,7 +552,10 @@ def get_filter_function(self, omega: Coefficients, which: str = 'fidelity',
545
552
The frequencies at which to evaluate the filter function.
546
553
which: str, optional
547
554
Which filter function to return. Either 'fidelity' (default)
548
- or 'generalized' (see :ref:`Notes <notes>`).
555
+ or 'generalized' (see :ref:`Notes <notes>`). Only if
556
+ ``order == 1``.
557
+ order: int, optional
558
+ First or second order filter function.
549
559
show_progressbar: bool, optional
550
560
Show a progress bar for the calculation of the control
551
561
matrix.
@@ -563,7 +573,7 @@ def get_filter_function(self, omega: Coefficients, which: str = 'fidelity',
563
573
564
574
Notes
565
575
-----
566
- The generalized filter function is given by
576
+ The first-order generalized filter function is given by
567
577
568
578
.. math::
569
579
@@ -586,33 +596,50 @@ def get_filter_function(self, omega: Coefficients, which: str = 'fidelity',
586
596
"""
587
597
# Only calculate if not calculated before for the same frequencies
588
598
if np .array_equal (self .omega , omega ):
589
- if which == 'fidelity' :
590
- if self .is_cached ('filter_function' ):
591
- return self ._filter_function
599
+ if order == 1 :
600
+ if which == 'fidelity' :
601
+ if self .is_cached ('filter function' ):
602
+ return self ._filter_function
603
+ else :
604
+ # which == 'generalized'
605
+ if self .is_cached ('filter_function_gen' ):
606
+ return self ._filter_function_gen
592
607
else :
593
- # which == 'generalized'
594
- if self .is_cached ('filter_function_gen ' ):
595
- return self ._filter_function_gen
608
+ # order == 2
609
+ if self .is_cached ('filter_function_2 ' ):
610
+ return self ._filter_function_2
596
611
else :
597
612
# Getting with different frequencies. Remove all cached attributes
598
613
# that are frequency-dependent
599
614
self .cleanup ('frequency dependent' )
600
615
601
- control_matrix = self .get_control_matrix (omega , show_progressbar , cache_intermediates )
602
- self .cache_filter_function (omega , control_matrix = control_matrix , which = which )
616
+ if order == 1 :
617
+ control_matrix = self .get_control_matrix (omega , show_progressbar , cache_intermediates )
618
+ else :
619
+ # order == 2
620
+ control_matrix = None
621
+
622
+ self .cache_filter_function (omega , control_matrix = control_matrix , which = which ,
623
+ order = order , show_progressbar = show_progressbar ,
624
+ cache_intermediates = cache_intermediates )
603
625
604
- if which == 'fidelity' :
605
- return self ._filter_function
626
+ if order == 1 :
627
+ if which == 'fidelity' :
628
+ return self ._filter_function
629
+ else :
630
+ # which == 'generalized'
631
+ return self ._filter_function_gen
606
632
else :
607
- # which == 'generalized'
608
- return self ._filter_function_gen
633
+ # order == 2
634
+ return self ._filter_function_2
609
635
610
- @util .parse_which_FF_parameter
636
+ @util .parse_optional_parameters ({ 'which' : ( 'fidelity' , 'generalized' ), 'order' : ( 1 , 2 )})
611
637
def cache_filter_function (
612
638
self , omega : Coefficients ,
613
639
control_matrix : Optional [ndarray ] = None ,
614
640
filter_function : Optional [ndarray ] = None ,
615
641
which : str = 'fidelity' ,
642
+ order : int = 1 ,
616
643
show_progressbar : bool = False ,
617
644
cache_intermediates : bool = False
618
645
) -> None :
@@ -633,11 +660,14 @@ def cache_filter_function(
633
660
it is computed and the filter function derived from it.
634
661
filter_function: array_like, shape (n_nops, n_nops, [d**2, d**2,] n_omega), optional
635
662
The filter function for the frequencies *omega*. If
636
- ``None``, it is computed from control_matrix.
663
+ ``None``, it is computed from R in the case ``order == 1``
664
+ and from scratch else.
637
665
which: str, optional
638
666
Which filter function to cache. Either 'fidelity' (default)
639
667
or 'generalized'.
640
- show_progressbar: bool
668
+ order: int, optional
669
+ First or second order filter function.
670
+ show_progressbar: bool, optional
641
671
Show a progress bar for the calculation of the control
642
672
matrix.
643
673
cache_intermediates: bool, optional
@@ -649,31 +679,45 @@ def cache_filter_function(
649
679
PulseSequence.get_filter_function : Getter method
650
680
"""
651
681
if filter_function is None :
652
- if control_matrix is None :
653
- control_matrix = self .get_control_matrix (omega , show_progressbar , cache_intermediates )
654
-
655
- self .cache_control_matrix (omega , control_matrix )
656
- if control_matrix .ndim == 4 :
657
- # Calculate pulse correlation FF and derive canonical FF from it
658
- F_pc = numeric .calculate_pulse_correlation_filter_function (control_matrix , which )
659
-
660
- if which == 'fidelity' :
661
- self ._filter_function_pc = F_pc
682
+ if order == 1 :
683
+ if control_matrix is None :
684
+ control_matrix = self .get_control_matrix (omega , show_progressbar ,
685
+ cache_intermediates )
686
+
687
+ self .cache_control_matrix (omega , control_matrix )
688
+ if control_matrix .ndim == 4 :
689
+ # Calculate pulse correlation FF and derive canonical FF
690
+ # from it
691
+ F_pc = numeric .calculate_pulse_correlation_filter_function (control_matrix ,
692
+ which )
693
+
694
+ if which == 'fidelity' :
695
+ self ._filter_function_pc = F_pc
696
+ else :
697
+ # which == 'generalized'
698
+ self ._filter_function_pc_gen = F_pc
699
+
700
+ filter_function = F_pc .sum (axis = (0 , 1 ))
662
701
else :
663
- # which == 'generalized'
664
- self ._filter_function_pc_gen = F_pc
665
-
666
- filter_function = F_pc .sum (axis = (0 , 1 ))
702
+ # Regular case
703
+ filter_function = numeric .calculate_filter_function (control_matrix , which )
667
704
else :
668
- # Regular case
669
- filter_function = numeric .calculate_filter_function (control_matrix , which )
705
+ # order == 2
706
+ filter_function = numeric .calculate_second_order_filter_function (
707
+ self .eigvals , self .eigvecs , self .propagators , omega , self .basis ,
708
+ self .n_opers , self .n_coeffs , self .dt , self ._intermediates , show_progressbar
709
+ )
670
710
671
711
self .omega = omega
672
- if which == 'fidelity' :
673
- self ._filter_function = filter_function
712
+ if order == 1 :
713
+ if which == 'fidelity' :
714
+ self ._filter_function = filter_function
715
+ else :
716
+ # which == 'generalized'
717
+ self ._filter_function_gen = filter_function
674
718
else :
675
- # which == 'generalized'
676
- self ._filter_function_gen = filter_function
719
+ # order == 2
720
+ self ._filter_function_2 = filter_function
677
721
678
722
@util .parse_which_FF_parameter
679
723
def get_pulse_correlation_filter_function (self , which : str = 'fidelity' ) -> ndarray :
@@ -947,7 +991,6 @@ def cleanup(self, method: str = 'conservative') -> None:
947
991
- _total_phases
948
992
- _control_matrix
949
993
- _control_matrix_pc
950
- - _intermediates
951
994
952
995
If set to 'all', all of the above as well as the following
953
996
attributes are deleted:
@@ -957,6 +1000,7 @@ def cleanup(self, method: str = 'conservative') -> None:
957
1000
- _filter_function_gen
958
1001
- _filter_function_pc
959
1002
- _filter_function_pc_gen
1003
+ - _filter_function_2
960
1004
- _intermediates['control_matrix_step']
961
1005
962
1006
If set to 'frequency dependent' only attributes that are
@@ -970,16 +1014,15 @@ def cleanup(self, method: str = 'conservative') -> None:
970
1014
default_attrs = {'_eigvals' , '_eigvecs' , '_propagators' }
971
1015
concatenation_attrs = {'_total_propagator' , '_total_phases' , '_total_propagator_liouville' ,
972
1016
'_control_matrix' , '_control_matrix_pc' , '_intermediates' }
973
- filter_function_attrs = {'omega ' , '_filter_function ' , '_filter_function_gen' ,
974
- '_filter_function_pc' , '_filter_function_pc_gen' }
1017
+ filter_function_attrs = {'_filter_function ' , '_filter_function_2 ' , '_filter_function_gen' ,
1018
+ '_filter_function_pc' , '_filter_function_pc_gen' , 'omega' }
975
1019
976
1020
if method == 'conservative' :
977
1021
attrs = default_attrs
978
1022
elif method == 'greedy' :
979
1023
attrs = default_attrs .union (concatenation_attrs )
980
1024
elif method == 'frequency dependent' :
981
- attrs = filter_function_attrs .union ({'_control_matrix' ,
982
- '_control_matrix_pc' ,
1025
+ attrs = filter_function_attrs .union ({'_control_matrix' , '_control_matrix_pc' ,
983
1026
'_total_phases' })
984
1027
# Remove frequency dependent control_matrix_step from intermediates
985
1028
self ._intermediates .pop ('control_matrix_step' , None )
0 commit comments