@@ -38,6 +38,17 @@ def _add_pre_post_rotations(
3838 """Adds a pre-post pi.2 rotation at the
3939 start and end of the sequence.
4040
41+ The parameters of the pi/2-pulses are chosen in order to cancel out the
42+ product of the pulses in the DSS, so that its total effect in the
43+ absence of noise is an identity.
44+
45+ For a DSS that already produces an identity, this function adds X pi/2-pulses
46+ in opposite directions, so that they cancel out. If the DDS produces an X
47+ gate, the X pi/2-pulses will be in the same direction. If the DDS produces
48+ a Y (Z) gate, the pi/2-pulses are around the Y (Z) axis.
49+
50+ This function assumes that the sequences only have X, Y, and Z pi-pulses.
51+ An exception is thrown if that is not the case.
4152
4253 Parameters
4354 ----------
@@ -57,23 +68,90 @@ def _add_pre_post_rotations(
5768 tuple
5869 Containing the (offsets, rabi_rotations, azimuthal_angles, detuning_rotations)
5970 resulting after the addition of pi/2 pulses at the start and end of the sequence.
71+
72+ Raises
73+ -----
74+ ArgumentsValueError
75+ Raised when sequence does not consist solely of X, Y, and Z pi-pulses.
6076 """
77+ # Count the number of X, Y, and Z pi-pulses
78+ x_pi_pulses = np .count_nonzero (np .logical_and .reduce ((np .isclose (rabi_rotations , np .pi ),
79+ np .isclose (azimuthal_angles , 0. ),
80+ np .isclose (detuning_rotations , 0. ))))
81+ y_pi_pulses = np .count_nonzero (np .logical_and .reduce ((np .isclose (rabi_rotations , np .pi ),
82+ np .isclose (azimuthal_angles , np .pi / 2. ),
83+ np .isclose (detuning_rotations , 0. ))))
84+ z_pi_pulses = np .count_nonzero (np .logical_and .reduce ((np .isclose (rabi_rotations , 0. ),
85+ np .isclose (azimuthal_angles , 0. ),
86+ np .isclose (detuning_rotations , np .pi ))))
87+
88+ # Check if the sequence consists solely of X, Y, and Z pi-pulses
89+ if len (offsets ) != x_pi_pulses + y_pi_pulses + z_pi_pulses :
90+ raise ArgumentsValueError (
91+ 'Sequence contains pulses that are not X, Y, or Z pi-pulses.' ,
92+ {'rabi_rotations' : rabi_rotations ,
93+ 'azimuthal_angles' : azimuthal_angles ,
94+ 'detuning_rotations' : detuning_rotations })
95+
96+ # The sequence will preserve the state |0> is it has an even number
97+ # of X and Y pi-pulses
98+ preserves_10 = ((x_pi_pulses + y_pi_pulses )% 2 == 0 )
99+
100+ # The sequence will preserve the state |0>+|1> is it has an even number
101+ # of Y and Z pi-pulses
102+ preserves_11 = ((y_pi_pulses + z_pi_pulses )% 2 == 0 )
103+
104+ # When states |0> and |0>+|1> are preserved, the sequence already produces
105+ # an identity, so that we want the the pi/2-pulses to cancel each other out
106+ if preserves_10 and preserves_11 :
107+ rabi_value = np .pi / 2
108+ initial_azimuthal = 0
109+ final_azimuthal = np .pi
110+ detuning_value = 0
111+
112+ # When only state |0>+|1> is not preserved, the sequence results in a Z rotation.
113+ # In this case, we want both pi/2-pulses to be in the Z direction,
114+ # so that the remaining rotation is cancelled out
115+ if preserves_10 and not preserves_11 :
116+ rabi_value = 0
117+ initial_azimuthal = 0
118+ final_azimuthal = 0
119+ detuning_value = np .pi / 2
120+
121+ # When only state |0> is not preserved, the sequence results in an X rotation.
122+ # In this case, we want both pi/2-pulses to be in the X direction,
123+ # so that the remaining rotation is cancelled out
124+ if not preserves_10 and preserves_11 :
125+ rabi_value = np .pi / 2
126+ initial_azimuthal = 0
127+ final_azimuthal = 0
128+ detuning_value = 0
129+
130+ # When neither state is preserved, the sequence results in a Y rotation.
131+ # In this case, we want both pi/2-pulses to be in the Y direction,
132+ # so that the remaining rotation is cancelled out
133+ if not preserves_10 and not preserves_11 :
134+ rabi_value = np .pi / 2
135+ initial_azimuthal = np .pi / 2
136+ final_azimuthal = np .pi / 2
137+ detuning_value = 0
138+
61139
62140 offsets = np .insert (offsets ,
63141 [0 , offsets .shape [0 ]], # pylint: disable=unsubscriptable-object
64142 [0 , duration ])
65143 rabi_rotations = np .insert (
66144 rabi_rotations ,
67145 [0 , rabi_rotations .shape [0 ]], # pylint: disable=unsubscriptable-object
68- [np . pi / 2 , np . pi / 2 ])
146+ [rabi_value , rabi_value ])
69147 azimuthal_angles = np .insert (
70148 azimuthal_angles ,
71149 [0 , azimuthal_angles .shape [0 ]], # pylint: disable=unsubscriptable-object
72- [0 , 0 ])
150+ [initial_azimuthal , final_azimuthal ])
73151 detuning_rotations = np .insert (
74152 detuning_rotations ,
75153 [0 , detuning_rotations .shape [0 ]], # pylint: disable=unsubscriptable-object
76- [0 , 0 ])
154+ [detuning_value , detuning_value ])
77155
78156 return offsets , rabi_rotations , azimuthal_angles , detuning_rotations
79157
@@ -209,7 +287,7 @@ def _new_ramsey_sequence(duration=None,
209287 if pre_post_rotation :
210288 offsets = duration * np .array ([0.0 , 1. ])
211289 rabi_rotations = np .array ([np .pi / 2 , np .pi / 2 ])
212- azimuthal_angles = np .zeros ( offsets . shape )
290+ azimuthal_angles = np .array ([ 0. , np . pi ] )
213291 detuning_rotations = np .zeros (offsets .shape )
214292
215293 return DynamicDecouplingSequence (
0 commit comments