From 895b7245c6f6ac21f91e70c327af1a4a2b5b13c3 Mon Sep 17 00:00:00 2001 From: Leonardo Andreta de Castro Date: Wed, 1 Apr 2020 13:46:23 +1100 Subject: [PATCH 1/9] Eliminating the need to test for end times > start times in each pulse --- .../driven_controls.py | 30 +++++++------------ 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/qctrlopencontrols/dynamic_decoupling_sequences/driven_controls.py b/qctrlopencontrols/dynamic_decoupling_sequences/driven_controls.py index c4a37f87..6bb116d0 100644 --- a/qctrlopencontrols/dynamic_decoupling_sequences/driven_controls.py +++ b/qctrlopencontrols/dynamic_decoupling_sequences/driven_controls.py @@ -77,17 +77,17 @@ def _check_maximum_rotation_rate( """ # check against global parameters - if maximum_rabi_rate < 0. or maximum_rabi_rate > UPPER_BOUND_RABI_RATE: + if maximum_rabi_rate <= 0. or maximum_rabi_rate > UPPER_BOUND_RABI_RATE: raise ArgumentsValueError( - 'Maximum rabi rate must be between 0. and maximum value of {0}'.format( + 'Maximum rabi rate must be greater than 0. and less or equal to {0}'.format( UPPER_BOUND_RABI_RATE), {'maximum_rabi_rate': maximum_rabi_rate}, extras={'maximum_detuning_rate': maximum_detuning_rate, 'allowed_maximum_rabi_rate': UPPER_BOUND_RABI_RATE}) - if maximum_detuning_rate < 0. or maximum_detuning_rate > UPPER_BOUND_DETUNING_RATE: + if maximum_detuning_rate <= 0. or maximum_detuning_rate > UPPER_BOUND_DETUNING_RATE: raise ArgumentsValueError( - 'Maximum detuning rate must be between 0. and maximum value of {0}'.format( + 'Maximum detuning rate must be greater than 0. and less or equalt o {0}'.format( UPPER_BOUND_DETUNING_RATE), {'maximum_detuning_rate': maximum_detuning_rate, }, extras={'maximum_rabi_rate': maximum_rabi_rate, @@ -112,9 +112,9 @@ def convert_dds_to_driven_control( dynamic_decoupling_sequence : qctrlopencontrols.DynamicDecouplingSequence The base DDS maximum_rabi_rate : float, optional - Maximum Rabi Rate; Defaults to 2*pi + Maximum Rabi Rate. Defaults to 2*pi, and must be greater than 0 if set. maximum_detuning_rate : float, optional - Maximum Detuning Rate; Defaults to 2*pi + Maximum Detuning Rate; Defaults to 2*pi, and must be greater than 0 if set. minimum_segment_duration : float, optional If set, further restricts the duration of every segment of the Driven Controls. Defaults to 0, in which case it does not affect the duration of the pulses. @@ -182,15 +182,6 @@ def convert_dds_to_driven_control( extras={'maximum_rabi_rate': maximum_rabi_rate, 'maximum_detuning_rate': maximum_detuning_rate}) - # check if detuning rate is supplied if there is a detuning_rotation > 0 - if np.any(detuning_rotations > 0.) and maximum_detuning_rate is None: - raise ArgumentsValueError( - 'Sequence operation includes detuning rotations. Please supply a valid ' - 'maximum_detuning_rate.', - {'detuning_rotations': dynamic_decoupling_sequence.detuning_rotations, - 'maximum_detuning_rate': maximum_detuning_rate}, - extras={'maximum_rabi_rate': maximum_rabi_rate}) - if offsets.size == 0: offsets = np.array([0, sequence_duration]) rabi_rotations = np.array([0, 0]) @@ -227,7 +218,7 @@ def convert_dds_to_driven_control( half_pulse_duration = 0. if not np.isclose(operations[1, op_idx], 0.): # Rabi rotation - half_pulse_duration = 0.5 * max(operations[1, op_idx] / maximum_rabi_rate, + half_pulse_duration = 0.5 * max(np.abs(operations[1, op_idx]) / maximum_rabi_rate, minimum_segment_duration) elif not np.isclose(operations[3, op_idx], 0.): # Detuning rotation half_pulse_duration = 0.5 * max(np.abs(operations[3, op_idx]) / maximum_detuning_rate, @@ -257,11 +248,9 @@ def convert_dds_to_driven_control( # four conditions to check # 1. Control segment start times should be monotonically increasing # 2. Control segment end times should be monotonically increasing - # 3. Control segment start time must be less than its end time - # 4. Adjacent segments should not be overlapping + # 3. Adjacent segments should not be overlapping if (np.any(pulse_start_ends[0:-1, 0] - pulse_start_ends[1:, 0] > 0.) or np.any(pulse_start_ends[0:-1, 1] - pulse_start_ends[1:, 1] > 0.) or - np.any(pulse_start_ends[:, 0] - pulse_start_ends[:, 1] > 0.) or np.any(pulse_start_ends[1:, 0]-pulse_start_ends[0:-1, 1] < 0.)): raise ArgumentsValueError('Pulse timing could not be properly deduced from ' @@ -284,7 +273,8 @@ def convert_dds_to_driven_control( 'maximum_detuning_rate': maximum_detuning_rate, 'minimum_segment_duration': minimum_segment_duration}, extras={'deduced_pulse_start_timing': pulse_start_ends[:, 0], - 'deduced_pulse_end_timing': pulse_start_ends[:, 1]}) + 'deduced_pulse_end_timing': pulse_start_ends[:, 1], + 'gap_durations': gap_durations}) if np.allclose(pulse_start_ends, 0.0): From fc2aea4a41cd7322f0e0f6af381cf9588587a20b Mon Sep 17 00:00:00 2001 From: Leonardo Andreta de Castro Date: Wed, 1 Apr 2020 13:50:06 +1100 Subject: [PATCH 2/9] Typo fixes --- .../dynamic_decoupling_sequences/driven_controls.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/qctrlopencontrols/dynamic_decoupling_sequences/driven_controls.py b/qctrlopencontrols/dynamic_decoupling_sequences/driven_controls.py index 6bb116d0..f67e2a2e 100644 --- a/qctrlopencontrols/dynamic_decoupling_sequences/driven_controls.py +++ b/qctrlopencontrols/dynamic_decoupling_sequences/driven_controls.py @@ -79,7 +79,7 @@ def _check_maximum_rotation_rate( # check against global parameters if maximum_rabi_rate <= 0. or maximum_rabi_rate > UPPER_BOUND_RABI_RATE: raise ArgumentsValueError( - 'Maximum rabi rate must be greater than 0. and less or equal to {0}'.format( + 'Maximum rabi rate must be greater than 0 and less or equal to {0}'.format( UPPER_BOUND_RABI_RATE), {'maximum_rabi_rate': maximum_rabi_rate}, extras={'maximum_detuning_rate': maximum_detuning_rate, @@ -87,11 +87,10 @@ def _check_maximum_rotation_rate( if maximum_detuning_rate <= 0. or maximum_detuning_rate > UPPER_BOUND_DETUNING_RATE: raise ArgumentsValueError( - 'Maximum detuning rate must be greater than 0. and less or equalt o {0}'.format( + 'Maximum detuning rate must be greater than 0 and less or equal to {0}'.format( UPPER_BOUND_DETUNING_RATE), {'maximum_detuning_rate': maximum_detuning_rate, }, extras={'maximum_rabi_rate': maximum_rabi_rate, - 'allowed_maximum_rabi_rate': UPPER_BOUND_RABI_RATE, 'allowed_maximum_detuning_rate': UPPER_BOUND_DETUNING_RATE}) @@ -112,9 +111,11 @@ def convert_dds_to_driven_control( dynamic_decoupling_sequence : qctrlopencontrols.DynamicDecouplingSequence The base DDS maximum_rabi_rate : float, optional - Maximum Rabi Rate. Defaults to 2*pi, and must be greater than 0 if set. + Maximum Rabi Rate; Defaults to 2*pi. + Must be greater than 0 and less or equal to UPPER_BOUND_RABI_RATE, if set. maximum_detuning_rate : float, optional - Maximum Detuning Rate; Defaults to 2*pi, and must be greater than 0 if set. + Maximum Detuning Rate; Defaults to 2*pi. + Must be greater than 0 and less or equal to UPPER_BOUND_DETUNING_RATE, if set. minimum_segment_duration : float, optional If set, further restricts the duration of every segment of the Driven Controls. Defaults to 0, in which case it does not affect the duration of the pulses. From 69c64a71972d82d8bf869813061567656e7a1061 Mon Sep 17 00:00:00 2001 From: Leonardo Andreta de Castro Date: Wed, 1 Apr 2020 14:10:55 +1100 Subject: [PATCH 3/9] Removing unnecessary tests --- .../driven_controls.py | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/qctrlopencontrols/dynamic_decoupling_sequences/driven_controls.py b/qctrlopencontrols/dynamic_decoupling_sequences/driven_controls.py index f67e2a2e..a935a50d 100644 --- a/qctrlopencontrols/dynamic_decoupling_sequences/driven_controls.py +++ b/qctrlopencontrols/dynamic_decoupling_sequences/driven_controls.py @@ -231,20 +231,12 @@ def convert_dds_to_driven_control( # check if any of the pulses have gone outside the time limit [0, sequence_duration] # if yes, adjust the segment timing if pulse_start_ends[0, 0] < 0.: - - if np.sum(np.abs(pulse_start_ends[0, :])) == 0: - pulse_start_ends[0, 0] = 0 - else: - translation = 0. - (pulse_start_ends[0, 0]) - pulse_start_ends[0, :] = pulse_start_ends[0, :] + translation + translation = 0. - (pulse_start_ends[0, 0]) + pulse_start_ends[0, :] = pulse_start_ends[0, :] + translation if pulse_start_ends[-1, 1] > sequence_duration: - - if np.sum(np.abs(pulse_start_ends[0, :])) == 2 * sequence_duration: - pulse_start_ends[-1, 1] = sequence_duration - else: - translation = pulse_start_ends[-1, 1] - sequence_duration - pulse_start_ends[-1, :] = pulse_start_ends[-1, :] - translation + translation = pulse_start_ends[-1, 1] - sequence_duration + pulse_start_ends[-1, :] = pulse_start_ends[-1, :] - translation # four conditions to check # 1. Control segment start times should be monotonically increasing From 8107a593a94c346ad3a01432209da9d2e161d211 Mon Sep 17 00:00:00 2001 From: Leonardo Andreta de Castro Date: Wed, 1 Apr 2020 15:30:46 +1100 Subject: [PATCH 4/9] initial changes --- .../driven_controls.py | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/qctrlopencontrols/dynamic_decoupling_sequences/driven_controls.py b/qctrlopencontrols/dynamic_decoupling_sequences/driven_controls.py index a935a50d..066b4985 100644 --- a/qctrlopencontrols/dynamic_decoupling_sequences/driven_controls.py +++ b/qctrlopencontrols/dynamic_decoupling_sequences/driven_controls.py @@ -238,14 +238,11 @@ def convert_dds_to_driven_control( translation = pulse_start_ends[-1, 1] - sequence_duration pulse_start_ends[-1, :] = pulse_start_ends[-1, :] - translation - # four conditions to check + # two conditions to check # 1. Control segment start times should be monotonically increasing # 2. Control segment end times should be monotonically increasing - # 3. Adjacent segments should not be overlapping if (np.any(pulse_start_ends[0:-1, 0] - pulse_start_ends[1:, 0] > 0.) or - np.any(pulse_start_ends[0:-1, 1] - pulse_start_ends[1:, 1] > 0.) or - np.any(pulse_start_ends[1:, 0]-pulse_start_ends[0:-1, 1] < 0.)): - + np.any(pulse_start_ends[0:-1, 1] - pulse_start_ends[1:, 1] > 0.) raise ArgumentsValueError('Pulse timing could not be properly deduced from ' 'the sequence operation offsets. Try increasing the ' 'maximum rabi rate or maximum detuning rate.', @@ -255,8 +252,20 @@ def convert_dds_to_driven_control( extras={'deduced_pulse_start_timing': pulse_start_ends[:, 0], 'deduced_pulse_end_timing': pulse_start_ends[:, 1]}) - # check if the minimum_segment_duration is respected in the gaps between the pulses + # check that no adjacent pulses overlap gap_durations = pulse_start_ends[1:, 0] - pulse_start_ends[:-1, 1] + if not np.all(np.logical_or(np.greater(gap_durations, 0.), + np.isclose(gap_durations, 0.))): + raise ArgumentsValueError('There is overlap between pulses in the sequecence. ' + ' Try increasing the maximum rabi rate or maximum detuning rate.', + {'dynamic_decoupling_sequence': dynamic_decoupling_sequence, + 'maximum_rabi_rate': maximum_rabi_rate, + 'maximum_detuning_rate': maximum_detuning_rate}, + extras={'deduced_pulse_start_timing': pulse_start_ends[:, 0], + 'deduced_pulse_end_timing': pulse_start_ends[:, 1], + 'gap_durations': gap_durations}) + + # check if the minimum_segment_duration is respected in the gaps between the pulses if not np.all(np.logical_or(np.greater(gap_durations, minimum_segment_duration), np.isclose(gap_durations, minimum_segment_duration))): raise ArgumentsValueError("Distance between pulses does not respect minimum_segment_duration. " From a24365e5edd9d759e37f7cfc7464f9e71e904174 Mon Sep 17 00:00:00 2001 From: Leonardo Andreta de Castro Date: Wed, 1 Apr 2020 16:27:44 +1100 Subject: [PATCH 5/9] Adding test of Luigi\'s sequence --- .../driven_controls.py | 26 ++++++-------- tests/test_dynamical_decoupling.py | 35 +++++++++++++++++++ 2 files changed, 46 insertions(+), 15 deletions(-) diff --git a/qctrlopencontrols/dynamic_decoupling_sequences/driven_controls.py b/qctrlopencontrols/dynamic_decoupling_sequences/driven_controls.py index 066b4985..83f08e6d 100644 --- a/qctrlopencontrols/dynamic_decoupling_sequences/driven_controls.py +++ b/qctrlopencontrols/dynamic_decoupling_sequences/driven_controls.py @@ -200,6 +200,16 @@ def convert_dds_to_driven_control( azimuthal_angles = np.append(azimuthal_angles, [0]) detuning_rotations = np.append(detuning_rotations, [0]) + # check that the offsets are correctly sorted in time + time_differences = np.diff(offsets) + if not np.all(np.logical_or(np.greater(time_differences, 0.), + np.isclose(time_differences, 0.))): + raise ArgumentsValueError("Pulse timing could not be properly deduced from " + "the sequence operation offsets. Make sure all pulse " + "offsets are correctly ordered in time.", + {'dynamic_decoupling_sequence': dynamic_decoupling_sequence}, + extras={'offsets': offsets}) + offsets = offsets[np.newaxis, :] rabi_rotations = rabi_rotations[np.newaxis, :] azimuthal_angles = azimuthal_angles[np.newaxis, :] @@ -238,26 +248,12 @@ def convert_dds_to_driven_control( translation = pulse_start_ends[-1, 1] - sequence_duration pulse_start_ends[-1, :] = pulse_start_ends[-1, :] - translation - # two conditions to check - # 1. Control segment start times should be monotonically increasing - # 2. Control segment end times should be monotonically increasing - if (np.any(pulse_start_ends[0:-1, 0] - pulse_start_ends[1:, 0] > 0.) or - np.any(pulse_start_ends[0:-1, 1] - pulse_start_ends[1:, 1] > 0.) - raise ArgumentsValueError('Pulse timing could not be properly deduced from ' - 'the sequence operation offsets. Try increasing the ' - 'maximum rabi rate or maximum detuning rate.', - {'dynamic_decoupling_sequence': dynamic_decoupling_sequence, - 'maximum_rabi_rate': maximum_rabi_rate, - 'maximum_detuning_rate': maximum_detuning_rate}, - extras={'deduced_pulse_start_timing': pulse_start_ends[:, 0], - 'deduced_pulse_end_timing': pulse_start_ends[:, 1]}) - # check that no adjacent pulses overlap gap_durations = pulse_start_ends[1:, 0] - pulse_start_ends[:-1, 1] if not np.all(np.logical_or(np.greater(gap_durations, 0.), np.isclose(gap_durations, 0.))): raise ArgumentsValueError('There is overlap between pulses in the sequecence. ' - ' Try increasing the maximum rabi rate or maximum detuning rate.', + 'Try increasing the maximum rabi rate or maximum detuning rate.', {'dynamic_decoupling_sequence': dynamic_decoupling_sequence, 'maximum_rabi_rate': maximum_rabi_rate, 'maximum_detuning_rate': maximum_detuning_rate}, diff --git a/tests/test_dynamical_decoupling.py b/tests/test_dynamical_decoupling.py index f2a04f8d..a8729076 100644 --- a/tests/test_dynamical_decoupling.py +++ b/tests/test_dynamical_decoupling.py @@ -575,6 +575,41 @@ def test_conversion_of_pulses_with_arbitrary_detuning_rotations(): assert _all_greater_or_close(driven_control.duration, minimum_segment_duration) +def test_conversion_of_tightly_packed_sequence(): + """ + Tests if the method to convert a DDS to driven controls handles properly + a sequence tightly packed with pulses. + """ + # create a sequence containing 30 pi-pulses and 2 pi/2-pulses at the extremities + dynamic_decoupling_sequence = DynamicDecouplingSequence( + duration=3.0, + offsets=np.array([0., 0.05, 0.15, 0.25, 0.35, 0.45, 0.55, 0.65, 0.75, 0.85, 0.95, + 1.05, 1.15, 1.25, 1.35, 1.45, 1.55, 1.65, 1.75, 1.85, 1.95, 2.05, + 2.15, 2.25, 2.35, 2.45, 2.55, 2.65, 2.75, 2.85, 2.95, 3.]), + rabi_rotations=np.array([1.57079633, 3.14159265, 3.14159265, 3.14159265, 3.14159265, + 3.14159265, 3.14159265, 3.14159265, 3.14159265, 3.14159265, + 3.14159265, 3.14159265, 3.14159265, 3.14159265, 3.14159265, + 3.14159265, 3.14159265, 3.14159265, 3.14159265, 3.14159265, + 3.14159265, 3.14159265, 3.14159265, 3.14159265, 3.14159265, + 3.14159265, 3.14159265, 3.14159265, 3.14159265, 3.14159265, + 3.14159265, 1.57079633]), + azimuthal_angles=np.array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., + 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]), + detuning_rotations=np.array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., + 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]), + name=None) + + driven_control = convert_dds_to_driven_control(dynamic_decoupling_sequence, + maximum_rabi_rate= 20. * np.pi, + minimum_segment_duration=0., + name=None) + + # There is no space for a gap between the pi/2-pulses and the adjacent pi-pulses, + # so the resulting sequence should have 32 pulses + 29 gaps = 61 segments + assert len(driven_control.durations) == 61 + + # ... of which 32 are X pulses (i.e. rabi_rotation > 0) + assert sum(np.greater(driven_control.rabi_rates, 0.)) == 32 def test_free_evolution_conversion(): From d21017f655dfdde0d6fbcd2e750e4dcd8f2659ca Mon Sep 17 00:00:00 2001 From: Leonardo Andreta de Castro Date: Wed, 1 Apr 2020 17:21:55 +1100 Subject: [PATCH 6/9] Fixing typos --- .../dynamic_decoupling_sequences/driven_controls.py | 8 ++++---- tests/test_dynamical_decoupling.py | 5 +++-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/qctrlopencontrols/dynamic_decoupling_sequences/driven_controls.py b/qctrlopencontrols/dynamic_decoupling_sequences/driven_controls.py index 620bdac2..e1efacac 100644 --- a/qctrlopencontrols/dynamic_decoupling_sequences/driven_controls.py +++ b/qctrlopencontrols/dynamic_decoupling_sequences/driven_controls.py @@ -109,7 +109,7 @@ def convert_dds_to_driven_control( Parameters ---------- dynamic_decoupling_sequence : qctrlopencontrols.DynamicDecouplingSequence - The base DDS. Its offsets should be ordered in ascending order in time. + The base DDS. Its offsets should be sorted in ascending order in time. maximum_rabi_rate : float, optional Maximum Rabi Rate; Defaults to 2*pi. Must be greater than 0 and less or equal to UPPER_BOUND_RABI_RATE, if set. @@ -235,7 +235,7 @@ def convert_dds_to_driven_control( half_pulse_duration = 0. if not np.isclose(operations[1, op_idx], 0.): # Rabi rotation - half_pulse_duration = 0.5 * max(np.abs(operations[1, op_idx]) / maximum_rabi_rate, + half_pulse_duration = 0.5 * max(operations[1, op_idx] / maximum_rabi_rate, minimum_segment_duration) elif not np.isclose(operations[3, op_idx], 0.): # Detuning rotation half_pulse_duration = 0.5 * max(np.abs(operations[3, op_idx]) / maximum_detuning_rate, @@ -258,8 +258,8 @@ def convert_dds_to_driven_control( gap_durations = pulse_start_ends[1:, 0] - pulse_start_ends[:-1, 1] if not np.all(np.logical_or(np.greater(gap_durations, 0.), np.isclose(gap_durations, 0.))): - raise ArgumentsValueError('There is overlap between pulses in the sequecence. ' - 'Try increasing the maximum rabi rate or maximum detuning rate.', + raise ArgumentsValueError("There is overlap between pulses in the sequence. " + "Try increasing the maximum rabi rate or maximum detuning rate.", {'dynamic_decoupling_sequence': dynamic_decoupling_sequence, 'maximum_rabi_rate': maximum_rabi_rate, 'maximum_detuning_rate': maximum_detuning_rate}, diff --git a/tests/test_dynamical_decoupling.py b/tests/test_dynamical_decoupling.py index 1de441fe..9323b1f4 100644 --- a/tests/test_dynamical_decoupling.py +++ b/tests/test_dynamical_decoupling.py @@ -578,7 +578,8 @@ def test_conversion_of_pulses_with_arbitrary_detuning_rotations(): def test_conversion_of_tightly_packed_sequence(): """ Tests if the method to convert a DDS to driven controls handles properly - a sequence tightly packed with pulses. + a sequence tightly packed with pulses, where there is no time for a gap between + the pi/2-pulses and the adjacent pi-pulses. """ # create a sequence containing 30 pi-pulses and 2 pi/2-pulses at the extremities dynamic_decoupling_sequence = DynamicDecouplingSequence( @@ -606,7 +607,7 @@ def test_conversion_of_tightly_packed_sequence(): # There is no space for a gap between the pi/2-pulses and the adjacent pi-pulses, # so the resulting sequence should have 32 pulses + 29 gaps = 61 segments with non-zero duration - assert len(np.greater(driven_control.durations, 0.)) == 61 + assert sum(np.greater(driven_control.durations, 0.)) == 61 # ... of which 32 are X pulses (i.e. rabi_rotation > 0) assert sum(np.greater(driven_control.rabi_rates, 0.)) == 32 From 5fb9acc8945dda63a1f34c82c0d94308694f945a Mon Sep 17 00:00:00 2001 From: Leonardo Andreta de Castro Date: Thu, 2 Apr 2020 10:19:54 +1100 Subject: [PATCH 7/9] Incorporating feedback --- .../driven_controls.py | 29 +++++++----------- tests/test_dynamical_decoupling.py | 30 +++++++------------ 2 files changed, 21 insertions(+), 38 deletions(-) diff --git a/qctrlopencontrols/dynamic_decoupling_sequences/driven_controls.py b/qctrlopencontrols/dynamic_decoupling_sequences/driven_controls.py index e1efacac..998c03d2 100644 --- a/qctrlopencontrols/dynamic_decoupling_sequences/driven_controls.py +++ b/qctrlopencontrols/dynamic_decoupling_sequences/driven_controls.py @@ -119,6 +119,7 @@ def convert_dds_to_driven_control( minimum_segment_duration : float, optional If set, further restricts the duration of every segment of the Driven Controls. Defaults to 0, in which case it does not affect the duration of the pulses. + Must be greater or equal to 0, if set. kwargs : dict, optional Options to make the corresponding filter type. I.e. the options for primitive are described in doc for the PrimitivePulse class. @@ -165,6 +166,10 @@ def convert_dds_to_driven_control( {'type(dynamic_decoupling_sequence': type(dynamic_decoupling_sequence)}) + if minimum_segment_duration < 0.: + raise ArgumentsValueError('Minimum segment duration must be greater or equal to 0.', + {'minimum_segment_duration': minimum_segment_duration}) + _check_maximum_rotation_rate(maximum_rabi_rate, maximum_detuning_rate) sequence_duration = dynamic_decoupling_sequence.duration @@ -207,12 +212,10 @@ def convert_dds_to_driven_control( detuning_rotations = np.append(detuning_rotations, [0]) # check that the offsets are correctly sorted in time - time_differences = np.diff(offsets) - if not np.all(np.logical_or(np.greater(time_differences, 0.), - np.isclose(time_differences, 0.))): + if any(np.diff(offsets) <= 0.): raise ArgumentsValueError("Pulse timing could not be properly deduced from " "the sequence offsets. Make sure all offset are " - "correctly ordered in time.", + "in increasing order.", {'dynamic_decoupling_sequence': dynamic_decoupling_sequence}, extras={'offsets': offsets}) @@ -254,24 +257,14 @@ def convert_dds_to_driven_control( translation = pulse_start_ends[-1, 1] - sequence_duration pulse_start_ends[-1, :] = pulse_start_ends[-1, :] - translation - # check that no adjacent pulses overlap - gap_durations = pulse_start_ends[1:, 0] - pulse_start_ends[:-1, 1] - if not np.all(np.logical_or(np.greater(gap_durations, 0.), - np.isclose(gap_durations, 0.))): - raise ArgumentsValueError("There is overlap between pulses in the sequence. " - "Try increasing the maximum rabi rate or maximum detuning rate.", - {'dynamic_decoupling_sequence': dynamic_decoupling_sequence, - 'maximum_rabi_rate': maximum_rabi_rate, - 'maximum_detuning_rate': maximum_detuning_rate}, - extras={'deduced_pulse_start_timing': pulse_start_ends[:, 0], - 'deduced_pulse_end_timing': pulse_start_ends[:, 1], - 'gap_durations': gap_durations}) - # check if the minimum_segment_duration is respected in the gaps between the pulses + # as minimum_segment_duration >= 0, this also excludes overlaps + gap_durations = pulse_start_ends[1:, 0] - pulse_start_ends[:-1, 1] if not np.all(np.logical_or(np.greater(gap_durations, minimum_segment_duration), np.isclose(gap_durations, minimum_segment_duration))): raise ArgumentsValueError("Distance between pulses does not respect minimum_segment_duration. " - "Try decreasing the minimum_segment_duration.", + "Try decreasing the minimum_segment_duration or incresing " + "the maximum_rabi_rate or maximum_detuning_rate", {'dynamic_decoupling_sequence': dynamic_decoupling_sequence, 'maximum_rabi_rate': maximum_rabi_rate, 'maximum_detuning_rate': maximum_detuning_rate, diff --git a/tests/test_dynamical_decoupling.py b/tests/test_dynamical_decoupling.py index 9323b1f4..52ab85ff 100644 --- a/tests/test_dynamical_decoupling.py +++ b/tests/test_dynamical_decoupling.py @@ -581,23 +581,13 @@ def test_conversion_of_tightly_packed_sequence(): a sequence tightly packed with pulses, where there is no time for a gap between the pi/2-pulses and the adjacent pi-pulses. """ - # create a sequence containing 30 pi-pulses and 2 pi/2-pulses at the extremities + # create a sequence containing 2 pi-pulses and 2 pi/2-pulses at the extremities dynamic_decoupling_sequence = DynamicDecouplingSequence( - duration=3.0, - offsets=np.array([0., 0.05, 0.15, 0.25, 0.35, 0.45, 0.55, 0.65, 0.75, 0.85, 0.95, - 1.05, 1.15, 1.25, 1.35, 1.45, 1.55, 1.65, 1.75, 1.85, 1.95, 2.05, - 2.15, 2.25, 2.35, 2.45, 2.55, 2.65, 2.75, 2.85, 2.95, 3.]), - rabi_rotations=np.array([1.57079633, 3.14159265, 3.14159265, 3.14159265, 3.14159265, - 3.14159265, 3.14159265, 3.14159265, 3.14159265, 3.14159265, - 3.14159265, 3.14159265, 3.14159265, 3.14159265, 3.14159265, - 3.14159265, 3.14159265, 3.14159265, 3.14159265, 3.14159265, - 3.14159265, 3.14159265, 3.14159265, 3.14159265, 3.14159265, - 3.14159265, 3.14159265, 3.14159265, 3.14159265, 3.14159265, - 3.14159265, 1.57079633]), - azimuthal_angles=np.array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., - 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]), - detuning_rotations=np.array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., - 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]), + duration=0.2, + offsets=np.array([0., 0.05, 0.15, 0.2]), + rabi_rotations=np.array([1.57079633, 3.14159265, 3.14159265, 1.57079633]), + azimuthal_angles=np.array([0., 0., 0., 0.]), + detuning_rotations=np.array([0., 0., 0., 0.]), name=None) driven_control = convert_dds_to_driven_control(dynamic_decoupling_sequence, @@ -606,11 +596,11 @@ def test_conversion_of_tightly_packed_sequence(): name=None) # There is no space for a gap between the pi/2-pulses and the adjacent pi-pulses, - # so the resulting sequence should have 32 pulses + 29 gaps = 61 segments with non-zero duration - assert sum(np.greater(driven_control.durations, 0.)) == 61 + # so the resulting sequence should have 4 pulses + 1 gaps = 5 segments with non-zero duration + assert sum(np.greater(driven_control.durations, 0.)) == 5 - # ... of which 32 are X pulses (i.e. rabi_rotation > 0) - assert sum(np.greater(driven_control.rabi_rates, 0.)) == 32 + # ... of which 4 are X pulses (i.e. rabi_rotation > 0) + assert sum(np.greater(driven_control.rabi_rates, 0.)) == 4 def test_free_evolution_conversion(): From b6fb28c1e26893a049b95174118ac8c7722a67ea Mon Sep 17 00:00:00 2001 From: Leonardo Andreta de Castro Date: Thu, 2 Apr 2020 10:25:27 +1100 Subject: [PATCH 8/9] Fixing typos --- .../dynamic_decoupling_sequences/driven_controls.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qctrlopencontrols/dynamic_decoupling_sequences/driven_controls.py b/qctrlopencontrols/dynamic_decoupling_sequences/driven_controls.py index 998c03d2..318a1bde 100644 --- a/qctrlopencontrols/dynamic_decoupling_sequences/driven_controls.py +++ b/qctrlopencontrols/dynamic_decoupling_sequences/driven_controls.py @@ -263,8 +263,8 @@ def convert_dds_to_driven_control( if not np.all(np.logical_or(np.greater(gap_durations, minimum_segment_duration), np.isclose(gap_durations, minimum_segment_duration))): raise ArgumentsValueError("Distance between pulses does not respect minimum_segment_duration. " - "Try decreasing the minimum_segment_duration or incresing " - "the maximum_rabi_rate or maximum_detuning_rate", + "Try decreasing the minimum_segment_duration or increasing " + "the maximum_rabi_rate or the maximum_detuning_rate.", {'dynamic_decoupling_sequence': dynamic_decoupling_sequence, 'maximum_rabi_rate': maximum_rabi_rate, 'maximum_detuning_rate': maximum_detuning_rate, From fd9b65e6ca3f616f731ca9428d0927be7944552d Mon Sep 17 00:00:00 2001 From: Leonardo Andreta de Castro Date: Thu, 2 Apr 2020 10:27:27 +1100 Subject: [PATCH 9/9] Fixing another typo --- .../dynamic_decoupling_sequences/driven_controls.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qctrlopencontrols/dynamic_decoupling_sequences/driven_controls.py b/qctrlopencontrols/dynamic_decoupling_sequences/driven_controls.py index 318a1bde..9820d4c6 100644 --- a/qctrlopencontrols/dynamic_decoupling_sequences/driven_controls.py +++ b/qctrlopencontrols/dynamic_decoupling_sequences/driven_controls.py @@ -214,7 +214,7 @@ def convert_dds_to_driven_control( # check that the offsets are correctly sorted in time if any(np.diff(offsets) <= 0.): raise ArgumentsValueError("Pulse timing could not be properly deduced from " - "the sequence offsets. Make sure all offset are " + "the sequence offsets. Make sure all offsets are " "in increasing order.", {'dynamic_decoupling_sequence': dynamic_decoupling_sequence}, extras={'offsets': offsets})