From 276a1ef441157d4b8e59947a0ed3bbda269fdf2a Mon Sep 17 00:00:00 2001 From: Li Li Date: Mon, 27 Jul 2020 18:27:17 +1000 Subject: [PATCH 1/5] Add type hint --- .../driven_controls/predefined.py | 144 +++++++++++------- 1 file changed, 93 insertions(+), 51 deletions(-) diff --git a/qctrlopencontrols/driven_controls/predefined.py b/qctrlopencontrols/driven_controls/predefined.py index a36dff0c..18b60b25 100644 --- a/qctrlopencontrols/driven_controls/predefined.py +++ b/qctrlopencontrols/driven_controls/predefined.py @@ -19,6 +19,12 @@ can be found at https://docs.q-ctrl.com/wiki/control-library """ +from typing import ( + List, + Optional, + Tuple, +) + import numpy as np from ..driven_controls import ( @@ -36,7 +42,7 @@ from .driven_control import DrivenControl -def new_predefined_driven_control(scheme=PRIMITIVE, **kwargs): +def new_predefined_driven_control(scheme: str = PRIMITIVE, **kwargs): """ Create a new driven control @@ -104,20 +110,24 @@ def new_predefined_driven_control(scheme=PRIMITIVE, **kwargs): return driven_control -def _predefined_common_attributes(maximum_rabi_rate, rabi_rotation, azimuthal_angle): +def _predefined_common_attributes( + maximum_rabi_rate: float, + azimuthal_angle: float, + rabi_rotation: Optional[float] = None, +) -> Tuple[float, float, Optional[float]]: """ Adds some checks etc for all the predefined pulses Parameters ---------- - rabi_rotation : float - The total polar angle to be performed by the pulse. - Defined in polar coordinates. maximum_rabi_rate : float Defaults to 2.*np.pi The maximum rabi frequency for the pulse. azimuthal_angle : float The azimuthal position of the pulse. + rabi_rotation : float, optional + The total polar angle to be performed by the pulse. + Defined in polar coordinates. Defaults to None. Returns ------- @@ -138,18 +148,19 @@ def _predefined_common_attributes(maximum_rabi_rate, rabi_rotation, azimuthal_an {"maximum_rabi_rate": maximum_rabi_rate}, ) - rabi_rotation = float(rabi_rotation) - if rabi_rotation == 0: - raise ArgumentsValueError( - "The rabi rotation must be non zero.", {"rabi_rotation": rabi_rotation} - ) + if rabi_rotation is not None: + rabi_rotation = float(rabi_rotation) + if rabi_rotation == 0: + raise ArgumentsValueError( + "The rabi rotation must be non zero.", {"rabi_rotation": rabi_rotation} + ) azimuthal_angle = float(azimuthal_angle) - return (maximum_rabi_rate, rabi_rotation, azimuthal_angle) + return (maximum_rabi_rate, azimuthal_angle, rabi_rotation) -def _get_transformed_rabi_rotation_wimperis(rabi_rotation): +def _get_transformed_rabi_rotation_wimperis(rabi_rotation: float) -> float: """ Calculates the Rabi rotation angle as required by Wimperis 1 (BB1) and Solovay-Kitaev driven controls. @@ -178,7 +189,9 @@ def _get_transformed_rabi_rotation_wimperis(rabi_rotation): return np.arccos(-rabi_rotation / (4 * np.pi)) -def _derive_segments(angles, amplitude=2.0 * np.pi): +def _derive_segments( + angles: np.ndarray, amplitude: float = 2.0 * np.pi +) -> List[List[float]]: """ Derive the driven control segments from a set of rabi_rotations defined in terms of the spherical polar angles @@ -208,8 +221,11 @@ def _derive_segments(angles, amplitude=2.0 * np.pi): def _new_primitive_control( - rabi_rotation=None, azimuthal_angle=0.0, maximum_rabi_rate=2.0 * np.pi, **kwargs -): + rabi_rotation: Optional[float] = None, + azimuthal_angle: float = 0.0, + maximum_rabi_rate: float = 2.0 * np.pi, + **kwargs +) -> DrivenControl: """ Primitive driven control. @@ -230,8 +246,8 @@ def _new_primitive_control( qctrlopencontrols.DrivenControl The driven control. """ - (maximum_rabi_rate, rabi_rotation, azimuthal_angle) = _predefined_common_attributes( - maximum_rabi_rate, rabi_rotation, azimuthal_angle + (maximum_rabi_rate, azimuthal_angle, rabi_rotation) = _predefined_common_attributes( + maximum_rabi_rate, azimuthal_angle, rabi_rotation ) return DrivenControl( @@ -244,8 +260,11 @@ def _new_primitive_control( def _new_wimperis_1_control( - rabi_rotation=None, azimuthal_angle=0.0, maximum_rabi_rate=2.0 * np.pi, **kwargs -): + rabi_rotation: Optional[float] = None, + azimuthal_angle: float = 0.0, + maximum_rabi_rate: float = 2.0 * np.pi, + **kwargs +) -> DrivenControl: """ Wimperis or BB1 control. @@ -266,8 +285,8 @@ def _new_wimperis_1_control( qctrlopencontrols.DrivenControl The driven control. """ - (maximum_rabi_rate, rabi_rotation, azimuthal_angle) = _predefined_common_attributes( - maximum_rabi_rate, rabi_rotation, azimuthal_angle + (maximum_rabi_rate, azimuthal_angle, rabi_rotation) = _predefined_common_attributes( + maximum_rabi_rate, azimuthal_angle, rabi_rotation ) phi_p = _get_transformed_rabi_rotation_wimperis(rabi_rotation) @@ -296,8 +315,11 @@ def _new_wimperis_1_control( def _new_solovay_kitaev_1_control( - rabi_rotation=None, azimuthal_angle=0.0, maximum_rabi_rate=2.0 * np.pi, **kwargs -): + rabi_rotation: Optional[float] = None, + azimuthal_angle: float = 0.0, + maximum_rabi_rate: float = 2.0 * np.pi, + **kwargs +) -> DrivenControl: """ First-order Solovay-Kitaev control, also known as SK1 @@ -318,8 +340,8 @@ def _new_solovay_kitaev_1_control( qctrlopencontrols.DrivenControl The driven control. """ - (maximum_rabi_rate, rabi_rotation, azimuthal_angle) = _predefined_common_attributes( - maximum_rabi_rate, rabi_rotation, azimuthal_angle + (maximum_rabi_rate, azimuthal_angle, rabi_rotation) = _predefined_common_attributes( + maximum_rabi_rate, azimuthal_angle, rabi_rotation ) phi_p = _get_transformed_rabi_rotation_wimperis(rabi_rotation) @@ -347,10 +369,13 @@ def _new_solovay_kitaev_1_control( def _short_composite_rotation_for_undoing_length_over_under_shoot_control( - rabi_rotation=None, azimuthal_angle=0.0, maximum_rabi_rate=2.0 * np.pi, **kwargs -): + rabi_rotation: Optional[float] = None, + azimuthal_angle: float = 0.0, + maximum_rabi_rate: float = 2.0 * np.pi, + **kwargs +) -> DrivenControl: """ - SCROFULOUS control to compensate for pulse length errors + SCROFULOUS control to compensate for pulse length errors. Parameters ---------- @@ -374,8 +399,8 @@ def _short_composite_rotation_for_undoing_length_over_under_shoot_control( ArgumentsValueError Raised when an argument is invalid. """ - (maximum_rabi_rate, rabi_rotation, azimuthal_angle) = _predefined_common_attributes( - maximum_rabi_rate, rabi_rotation, azimuthal_angle + (maximum_rabi_rate, azimuthal_angle, rabi_rotation) = _predefined_common_attributes( + maximum_rabi_rate, azimuthal_angle, rabi_rotation ) # Create a lookup table for rabi rotation and phase angles, taken from the official paper. @@ -434,8 +459,11 @@ def degrees_to_radians(angle_in_degrees): def _new_compensating_for_off_resonance_with_a_pulse_sequence_control( - rabi_rotation=None, azimuthal_angle=0.0, maximum_rabi_rate=2.0 * np.pi, **kwargs -): + rabi_rotation: Optional[float] = None, + azimuthal_angle: float = 0.0, + maximum_rabi_rate: float = 2.0 * np.pi, + **kwargs +) -> DrivenControl: """ Compensating for off resonance with a pulse sequence, often abbreviated as CORPSE. @@ -456,9 +484,11 @@ def _new_compensating_for_off_resonance_with_a_pulse_sequence_control( qctrlopencontrols.DrivenControl The driven control. """ - (maximum_rabi_rate, rabi_rotation, azimuthal_angle) = _predefined_common_attributes( - maximum_rabi_rate, rabi_rotation, azimuthal_angle - ) + ( + maximum_rabi_rate, + azimuthal_angle, + rabi_rotation, + ) = _predefined_common_attributes(maximum_rabi_rate, azimuthal_angle, rabi_rotation) k = np.arcsin(np.sin(rabi_rotation / 2.0) / 2.0) @@ -485,8 +515,11 @@ def _new_compensating_for_off_resonance_with_a_pulse_sequence_control( def _new_compensating_for_off_resonance_with_a_sequence_with_wimperis_control( - rabi_rotation=None, azimuthal_angle=0.0, maximum_rabi_rate=2.0 * np.pi, **kwargs -): + rabi_rotation: Optional[float] = None, + azimuthal_angle: float = 0.0, + maximum_rabi_rate: float = 2.0 * np.pi, + **kwargs +) -> DrivenControl: """ Compensating for off resonance with a pulse sequence with an embedded Wimperis (or BB1) control, also known as CinBB. @@ -508,8 +541,8 @@ def _new_compensating_for_off_resonance_with_a_sequence_with_wimperis_control( qctrlopencontrols.DrivenControl The driven control. """ - (maximum_rabi_rate, rabi_rotation, azimuthal_angle) = _predefined_common_attributes( - maximum_rabi_rate, rabi_rotation, azimuthal_angle + (maximum_rabi_rate, azimuthal_angle, rabi_rotation) = _predefined_common_attributes( + maximum_rabi_rate, azimuthal_angle, rabi_rotation ) phi_p = _get_transformed_rabi_rotation_wimperis(rabi_rotation) @@ -548,8 +581,11 @@ def _new_compensating_for_off_resonance_with_a_sequence_with_wimperis_control( def _new_compensating_for_off_resonance_with_a_sequence_with_sk_control( - rabi_rotation=None, azimuthal_angle=0.0, maximum_rabi_rate=2.0 * np.pi, **kwargs -): + rabi_rotation: Optional[float] = None, + azimuthal_angle: float = 0.0, + maximum_rabi_rate: float = 2.0 * np.pi, + **kwargs +) -> DrivenControl: """ Compensating for off resonance with a pulse sequence with an embedded Solovay Kitaev (or SK1) control, also knowns as CinSK. @@ -571,8 +607,8 @@ def _new_compensating_for_off_resonance_with_a_sequence_with_sk_control( qctrlopencontrols.DrivenControl The driven control. """ - (maximum_rabi_rate, rabi_rotation, azimuthal_angle) = _predefined_common_attributes( - maximum_rabi_rate, rabi_rotation, azimuthal_angle + (maximum_rabi_rate, azimuthal_angle, rabi_rotation) = _predefined_common_attributes( + maximum_rabi_rate, azimuthal_angle, rabi_rotation ) phi_p = _get_transformed_rabi_rotation_wimperis(rabi_rotation) @@ -609,8 +645,11 @@ def _new_compensating_for_off_resonance_with_a_sequence_with_sk_control( def _new_corpse_in_scrofulous_control( - rabi_rotation=None, azimuthal_angle=0.0, maximum_rabi_rate=2.0 * np.pi, **kwargs -): + rabi_rotation: Optional[float] = None, + azimuthal_angle: float = 0.0, + maximum_rabi_rate: float = 2.0 * np.pi, + **kwargs +) -> DrivenControl: """ CORPSE (Compensating for Off Resonance with a Pulse SEquence) embedded within a SCROFULOUS (Short Composite ROtation For Undoing Length Over and Under Shoot) control, @@ -638,8 +677,8 @@ def _new_corpse_in_scrofulous_control( ArgumentsValueError Raised when an argument is invalid. """ - (maximum_rabi_rate, rabi_rotation, azimuthal_angle) = _predefined_common_attributes( - maximum_rabi_rate, rabi_rotation, azimuthal_angle + (maximum_rabi_rate, azimuthal_angle, rabi_rotation) = _predefined_common_attributes( + maximum_rabi_rate, azimuthal_angle, rabi_rotation ) # Create a lookup table for rabi rotation and phase angles, taken from @@ -708,8 +747,11 @@ def degrees_to_radians(angle_in_degrees): def _new_walsh_amplitude_modulated_filter_1_control( - rabi_rotation=None, azimuthal_angle=0.0, maximum_rabi_rate=2.0 * np.pi, **kwargs -): + rabi_rotation: Optional[float] = None, + azimuthal_angle: float = 0.0, + maximum_rabi_rate: float = 2.0 * np.pi, + **kwargs +) -> DrivenControl: """ First order Walsh control with amplitude modulation. @@ -735,8 +777,8 @@ def _new_walsh_amplitude_modulated_filter_1_control( ArgumentsValueError Raised when an argument is invalid. """ - (maximum_rabi_rate, rabi_rotation, azimuthal_angle) = _predefined_common_attributes( - maximum_rabi_rate, rabi_rotation, azimuthal_angle + (maximum_rabi_rate, azimuthal_angle, rabi_rotation) = _predefined_common_attributes( + maximum_rabi_rate, azimuthal_angle, rabi_rotation ) if np.isclose(rabi_rotation, np.pi): From 7ac763e4e78843a61d9877c895893ba8e1caa0f3 Mon Sep 17 00:00:00 2001 From: Li Li Date: Mon, 27 Jul 2020 18:57:27 +1000 Subject: [PATCH 2/5] Refactor due to type issue --- .../driven_controls/predefined.py | 199 +++++++++--------- 1 file changed, 101 insertions(+), 98 deletions(-) diff --git a/qctrlopencontrols/driven_controls/predefined.py b/qctrlopencontrols/driven_controls/predefined.py index 18b60b25..18119476 100644 --- a/qctrlopencontrols/driven_controls/predefined.py +++ b/qctrlopencontrols/driven_controls/predefined.py @@ -2,9 +2,7 @@ # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 +# You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, @@ -249,13 +247,17 @@ def _new_primitive_control( (maximum_rabi_rate, azimuthal_angle, rabi_rotation) = _predefined_common_attributes( maximum_rabi_rate, azimuthal_angle, rabi_rotation ) + if rabi_rotation is None: + durations = None + else: + durations = ([rabi_rotation / maximum_rabi_rate],) return DrivenControl( rabi_rates=[maximum_rabi_rate], azimuthal_angles=[azimuthal_angle], detunings=[0], - durations=[rabi_rotation / maximum_rabi_rate], - **kwargs + durations=durations, + **kwargs, ) @@ -288,10 +290,9 @@ def _new_wimperis_1_control( (maximum_rabi_rate, azimuthal_angle, rabi_rotation) = _predefined_common_attributes( maximum_rabi_rate, azimuthal_angle, rabi_rotation ) - - phi_p = _get_transformed_rabi_rotation_wimperis(rabi_rotation) - - rabi_rotations = [rabi_rotation, np.pi, 2 * np.pi, np.pi] + if rabi_rotation is not None: + phi_p = _get_transformed_rabi_rotation_wimperis(rabi_rotation) + rabi_rotations = [rabi_rotation, np.pi, 2 * np.pi, np.pi] rabi_rates = [maximum_rabi_rate] * 4 azimuthal_angles = [ @@ -310,7 +311,7 @@ def _new_wimperis_1_control( azimuthal_angles=azimuthal_angles, detunings=detunings, durations=durations, - **kwargs + **kwargs, ) @@ -344,9 +345,9 @@ def _new_solovay_kitaev_1_control( maximum_rabi_rate, azimuthal_angle, rabi_rotation ) - phi_p = _get_transformed_rabi_rotation_wimperis(rabi_rotation) - - rabi_rotations = [rabi_rotation, 2 * np.pi, 2 * np.pi] + if rabi_rotation is not None: + phi_p = _get_transformed_rabi_rotation_wimperis(rabi_rotation) + rabi_rotations = [rabi_rotation, 2 * np.pi, 2 * np.pi] rabi_rates = [maximum_rabi_rate] * 3 azimuthal_angles = [ @@ -364,7 +365,7 @@ def _new_solovay_kitaev_1_control( azimuthal_angles=azimuthal_angles, detunings=detunings, durations=durations, - **kwargs + **kwargs, ) @@ -408,29 +409,30 @@ def _short_composite_rotation_for_undoing_length_over_under_shoot_control( def degrees_to_radians(angle_in_degrees): return angle_in_degrees / 180 * np.pi - if np.isclose(rabi_rotation, np.pi): - theta_1 = degrees_to_radians(180.0) - phi_1 = np.arccos( - -np.pi * np.cos(theta_1) / 2 / theta_1 / np.sin(rabi_rotation / 2) - ) - phi_2 = phi_1 - np.arccos(-np.pi / 2 / theta_1) - elif np.isclose(rabi_rotation, 0.5 * np.pi): - theta_1 = degrees_to_radians(115.2) - phi_1 = np.arccos( - -np.pi * np.cos(theta_1) / 2 / theta_1 / np.sin(rabi_rotation / 2) - ) - phi_2 = phi_1 - np.arccos(-np.pi / 2 / theta_1) - elif np.isclose(rabi_rotation, 0.25 * np.pi): - theta_1 = degrees_to_radians(96.7) - phi_1 = np.arccos( - -np.pi * np.cos(theta_1) / 2 / theta_1 / np.sin(rabi_rotation / 2) - ) - phi_2 = phi_1 - np.arccos(-np.pi / 2 / theta_1) - else: - raise ArgumentsValueError( - "rabi_rotation angle must be either pi, pi/2 or pi/4", - {"rabi_rotation": rabi_rotation}, - ) + if rabi_rotation is not None: + if np.isclose(rabi_rotation, np.pi): + theta_1 = degrees_to_radians(180.0) + phi_1 = np.arccos( + -np.pi * np.cos(theta_1) / 2 / theta_1 / np.sin(rabi_rotation / 2) + ) + phi_2 = phi_1 - np.arccos(-np.pi / 2 / theta_1) + elif np.isclose(rabi_rotation, 0.5 * np.pi): + theta_1 = degrees_to_radians(115.2) + phi_1 = np.arccos( + -np.pi * np.cos(theta_1) / 2 / theta_1 / np.sin(rabi_rotation / 2) + ) + phi_2 = phi_1 - np.arccos(-np.pi / 2 / theta_1) + elif np.isclose(rabi_rotation, 0.25 * np.pi): + theta_1 = degrees_to_radians(96.7) + phi_1 = np.arccos( + -np.pi * np.cos(theta_1) / 2 / theta_1 / np.sin(rabi_rotation / 2) + ) + phi_2 = phi_1 - np.arccos(-np.pi / 2 / theta_1) + else: + raise ArgumentsValueError( + "rabi_rotation angle must be either pi, pi/2 or pi/4", + {"rabi_rotation": rabi_rotation}, + ) theta_3 = theta_1 phi_3 = phi_1 @@ -454,7 +456,7 @@ def degrees_to_radians(angle_in_degrees): azimuthal_angles=azimuthal_angles, detunings=detunings, durations=durations, - **kwargs + **kwargs, ) @@ -490,13 +492,13 @@ def _new_compensating_for_off_resonance_with_a_pulse_sequence_control( rabi_rotation, ) = _predefined_common_attributes(maximum_rabi_rate, azimuthal_angle, rabi_rotation) - k = np.arcsin(np.sin(rabi_rotation / 2.0) / 2.0) - - rabi_rotations = [ - rabi_rotation / 2.0 + 2 * np.pi - k, - 2 * np.pi - 2 * k, - rabi_rotation / 2.0 - k, - ] + if rabi_rotation is not None: + k = np.arcsin(np.sin(rabi_rotation / 2.0) / 2.0) + rabi_rotations = [ + rabi_rotation / 2.0 + 2 * np.pi - k, + 2 * np.pi - 2 * k, + rabi_rotation / 2.0 - k, + ] rabi_rates = [maximum_rabi_rate] * 3 azimuthal_angles = [azimuthal_angle, azimuthal_angle + np.pi, azimuthal_angle] @@ -510,7 +512,7 @@ def _new_compensating_for_off_resonance_with_a_pulse_sequence_control( azimuthal_angles=azimuthal_angles, detunings=detunings, durations=durations, - **kwargs + **kwargs, ) @@ -545,17 +547,18 @@ def _new_compensating_for_off_resonance_with_a_sequence_with_wimperis_control( maximum_rabi_rate, azimuthal_angle, rabi_rotation ) - phi_p = _get_transformed_rabi_rotation_wimperis(rabi_rotation) - k = np.arcsin(np.sin(rabi_rotation / 2.0) / 2.0) - - rabi_rotations = [ - 2 * np.pi + rabi_rotation / 2.0 - k, - 2 * np.pi - 2 * k, - rabi_rotation / 2.0 - k, - np.pi, - 2 * np.pi, - np.pi, - ] + if rabi_rotation is not None: + phi_p = _get_transformed_rabi_rotation_wimperis(rabi_rotation) + k = np.arcsin(np.sin(rabi_rotation / 2.0) / 2.0) + + rabi_rotations = [ + 2 * np.pi + rabi_rotation / 2.0 - k, + 2 * np.pi - 2 * k, + rabi_rotation / 2.0 - k, + np.pi, + 2 * np.pi, + np.pi, + ] rabi_rates = [maximum_rabi_rate] * 6 azimuthal_angles = [ @@ -576,7 +579,7 @@ def _new_compensating_for_off_resonance_with_a_sequence_with_wimperis_control( azimuthal_angles=azimuthal_angles, detunings=detunings, durations=durations, - **kwargs + **kwargs, ) @@ -610,17 +613,17 @@ def _new_compensating_for_off_resonance_with_a_sequence_with_sk_control( (maximum_rabi_rate, azimuthal_angle, rabi_rotation) = _predefined_common_attributes( maximum_rabi_rate, azimuthal_angle, rabi_rotation ) + if rabi_rotation is not None: + phi_p = _get_transformed_rabi_rotation_wimperis(rabi_rotation) + k = np.arcsin(np.sin(rabi_rotation / 2.0) / 2.0) - phi_p = _get_transformed_rabi_rotation_wimperis(rabi_rotation) - k = np.arcsin(np.sin(rabi_rotation / 2.0) / 2.0) - - rabi_rotations = [ - 2 * np.pi + rabi_rotation / 2.0 - k, - 2 * np.pi - 2 * k, - rabi_rotation / 2.0 - k, - 2 * np.pi, - 2 * np.pi, - ] + rabi_rotations = [ + 2 * np.pi + rabi_rotation / 2.0 - k, + 2 * np.pi - 2 * k, + rabi_rotation / 2.0 - k, + 2 * np.pi, + 2 * np.pi, + ] rabi_rates = [maximum_rabi_rate] * 5 azimuthal_angles = [ @@ -640,7 +643,7 @@ def _new_compensating_for_off_resonance_with_a_sequence_with_sk_control( azimuthal_angles=azimuthal_angles, detunings=detunings, durations=durations, - **kwargs + **kwargs, ) @@ -686,33 +689,34 @@ def _new_corpse_in_scrofulous_control( def degrees_to_radians(angle_in_degrees): return angle_in_degrees / 180 * np.pi - if np.isclose(rabi_rotation, np.pi): - theta_1 = theta_3 = degrees_to_radians(180.0) - phi_1 = phi_3 = np.arccos( - -np.pi * np.cos(theta_1) / 2 / theta_1 / np.sin(rabi_rotation / 2) - ) - phi_2 = phi_1 - np.arccos(-np.pi / 2 / theta_1) - elif np.isclose(rabi_rotation, 0.5 * np.pi): - theta_1 = theta_3 = degrees_to_radians(115.2) - phi_1 = phi_3 = np.arccos( - -np.pi * np.cos(theta_1) / 2 / theta_1 / np.sin(rabi_rotation / 2) - ) - phi_2 = phi_1 - np.arccos(-np.pi / 2 / theta_1) - elif np.isclose(rabi_rotation, 0.25 * np.pi): - theta_1 = theta_3 = degrees_to_radians(96.7) - phi_1 = phi_3 = np.arccos( - -np.pi * np.cos(theta_1) / 2 / theta_1 / np.sin(rabi_rotation / 2) - ) - phi_2 = phi_1 - np.arccos(-np.pi / 2 / theta_1) - else: - raise ArgumentsValueError( - "rabi_rotation angle must be either pi, pi/2 or pi/4", - {"rabi_rotation": rabi_rotation}, - ) + if rabi_rotation is not None: + if np.isclose(rabi_rotation, np.pi): + theta_1 = theta_3 = degrees_to_radians(180.0) + phi_1 = phi_3 = np.arccos( + -np.pi * np.cos(theta_1) / 2 / theta_1 / np.sin(rabi_rotation / 2) + ) + phi_2 = phi_1 - np.arccos(-np.pi / 2 / theta_1) + elif np.isclose(rabi_rotation, 0.5 * np.pi): + theta_1 = theta_3 = degrees_to_radians(115.2) + phi_1 = phi_3 = np.arccos( + -np.pi * np.cos(theta_1) / 2 / theta_1 / np.sin(rabi_rotation / 2) + ) + phi_2 = phi_1 - np.arccos(-np.pi / 2 / theta_1) + elif np.isclose(rabi_rotation, 0.25 * np.pi): + theta_1 = theta_3 = degrees_to_radians(96.7) + phi_1 = phi_3 = np.arccos( + -np.pi * np.cos(theta_1) / 2 / theta_1 / np.sin(rabi_rotation / 2) + ) + phi_2 = phi_1 - np.arccos(-np.pi / 2 / theta_1) + else: + raise ArgumentsValueError( + "rabi_rotation angle must be either pi, pi/2 or pi/4", + {"rabi_rotation": rabi_rotation}, + ) theta_2 = np.pi - total_angles = [] + _total_angles = [] # Loop over all SCROFULOUS Rabi rotations (theta) and azimuthal angles (phi) # And make CORPSEs with those. for theta, phi in zip([theta_1, theta_2, theta_3], [phi_1, phi_2, phi_3]): @@ -724,10 +728,9 @@ def degrees_to_radians(angle_in_degrees): [theta / 2.0 - k, phi + azimuthal_angle], ] ) - total_angles.append(angles) - - total_angles = np.vstack(total_angles) + _total_angles.append(angles) + total_angles = np.vstack(_total_angles) rabi_rotations = total_angles[:, 0] rabi_rates = [maximum_rabi_rate] * 9 @@ -742,7 +745,7 @@ def degrees_to_radians(angle_in_degrees): azimuthal_angles=azimuthal_angles, detunings=detunings, durations=durations, - **kwargs + **kwargs, ) @@ -811,5 +814,5 @@ def _new_walsh_amplitude_modulated_filter_1_control( azimuthal_angles=azimuthal_angles, detunings=detunings, durations=durations, - **kwargs + **kwargs, ) From 8ef2868189c4280a22c6d0b2a4a4478fed1cc432 Mon Sep 17 00:00:00 2001 From: Li Li Date: Mon, 27 Jul 2020 19:12:04 +1000 Subject: [PATCH 3/5] Fix docstring --- qctrlopencontrols/driven_controls/predefined.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/qctrlopencontrols/driven_controls/predefined.py b/qctrlopencontrols/driven_controls/predefined.py index 18119476..0357af01 100644 --- a/qctrlopencontrols/driven_controls/predefined.py +++ b/qctrlopencontrols/driven_controls/predefined.py @@ -2,7 +2,9 @@ # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. -# You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, @@ -192,7 +194,7 @@ def _derive_segments( ) -> List[List[float]]: """ Derive the driven control segments from a set of rabi_rotations defined in terms of the - spherical polar angles + spherical polar angles. Parameters ---------- @@ -322,7 +324,7 @@ def _new_solovay_kitaev_1_control( **kwargs ) -> DrivenControl: """ - First-order Solovay-Kitaev control, also known as SK1 + First-order Solovay-Kitaev control, also known as SK1. Parameters ---------- From c07621d8dd8a56bc76fe62bac7e23bb0e85c7a1e Mon Sep 17 00:00:00 2001 From: Li Li Date: Tue, 28 Jul 2020 10:01:15 +1000 Subject: [PATCH 4/5] Make `rabi_rotation` required --- .../driven_controls/predefined.py | 286 +++++++++--------- 1 file changed, 140 insertions(+), 146 deletions(-) diff --git a/qctrlopencontrols/driven_controls/predefined.py b/qctrlopencontrols/driven_controls/predefined.py index 0357af01..3ac40bda 100644 --- a/qctrlopencontrols/driven_controls/predefined.py +++ b/qctrlopencontrols/driven_controls/predefined.py @@ -21,7 +21,6 @@ from typing import ( List, - Optional, Tuple, ) @@ -111,29 +110,27 @@ def new_predefined_driven_control(scheme: str = PRIMITIVE, **kwargs): def _predefined_common_attributes( - maximum_rabi_rate: float, - azimuthal_angle: float, - rabi_rotation: Optional[float] = None, -) -> Tuple[float, float, Optional[float]]: + azimuthal_angle: float, rabi_rotation: float, maximum_rabi_rate: float = 2 * np.pi, +) -> Tuple[float, float, float]: """ Adds some checks etc for all the predefined pulses Parameters ---------- - maximum_rabi_rate : float - Defaults to 2.*np.pi - The maximum rabi frequency for the pulse. azimuthal_angle : float The azimuthal position of the pulse. - rabi_rotation : float, optional + rabi_rotation : float The total polar angle to be performed by the pulse. Defined in polar coordinates. Defaults to None. + maximum_rabi_rate : float, optional + Defaults to 2.*np.pi + The maximum rabi frequency for the pulse. Returns ------- tuple Tuple of floats made of: - (rabi_rate, rabi_rotation, azimuthal) + (azimuthal, rabi_rotation, maximum_rabi_rate) Raises ------ @@ -148,16 +145,15 @@ def _predefined_common_attributes( {"maximum_rabi_rate": maximum_rabi_rate}, ) - if rabi_rotation is not None: - rabi_rotation = float(rabi_rotation) - if rabi_rotation == 0: - raise ArgumentsValueError( - "The rabi rotation must be non zero.", {"rabi_rotation": rabi_rotation} - ) + rabi_rotation = float(rabi_rotation) + if rabi_rotation == 0: + raise ArgumentsValueError( + "The rabi rotation must be non zero.", {"rabi_rotation": rabi_rotation} + ) azimuthal_angle = float(azimuthal_angle) - return (maximum_rabi_rate, azimuthal_angle, rabi_rotation) + return (azimuthal_angle, rabi_rotation, maximum_rabi_rate) def _get_transformed_rabi_rotation_wimperis(rabi_rotation: float) -> float: @@ -168,12 +164,12 @@ def _get_transformed_rabi_rotation_wimperis(rabi_rotation: float) -> float: Parameters ---------- rabi_rotation : float - Rotation angle of the operation + Rotation angle of the operation. Returns ------- float - The transformed angle as per definition for the Wimperis 1 (BB1) control + The transformed angle as per definition for the Wimperis 1 (BB1) control. Raises ------ @@ -221,7 +217,7 @@ def _derive_segments( def _new_primitive_control( - rabi_rotation: Optional[float] = None, + rabi_rotation: float, azimuthal_angle: float = 0.0, maximum_rabi_rate: float = 2.0 * np.pi, **kwargs @@ -231,13 +227,13 @@ def _new_primitive_control( Parameters ---------- - rabi_rotation : float, optional + rabi_rotation : float The total rabi rotation to be performed by the driven control. maximum_rabi_rate : float, optional Defaults to 2.*np.pi The maximum rabi frequency for the driven control. azimuthal_angle : float, optional - The azimuthal position of the driven control. + The azimuthal position of the driven control. Defaults to 0. kwargs : dict Other keywords required to make a qctrlopencontrols.DrivenControls. @@ -246,25 +242,22 @@ def _new_primitive_control( qctrlopencontrols.DrivenControl The driven control. """ - (maximum_rabi_rate, azimuthal_angle, rabi_rotation) = _predefined_common_attributes( - maximum_rabi_rate, azimuthal_angle, rabi_rotation + + (azimuthal_angle, rabi_rotation, maximum_rabi_rate) = _predefined_common_attributes( + azimuthal_angle, rabi_rotation, maximum_rabi_rate ) - if rabi_rotation is None: - durations = None - else: - durations = ([rabi_rotation / maximum_rabi_rate],) return DrivenControl( rabi_rates=[maximum_rabi_rate], azimuthal_angles=[azimuthal_angle], detunings=[0], - durations=durations, + durations=[rabi_rotation / maximum_rabi_rate], **kwargs, ) def _new_wimperis_1_control( - rabi_rotation: Optional[float] = None, + rabi_rotation: float, azimuthal_angle: float = 0.0, maximum_rabi_rate: float = 2.0 * np.pi, **kwargs @@ -280,6 +273,7 @@ def _new_wimperis_1_control( Defaults to 2.*np.pi The maximum rabi frequency for the control. azimuthal_angle : float, optional + Defaults to 0. The azimuthal position of the control. kwargs : dict Other keywords required to make a qctrlopencontrols.DrivenControls. @@ -289,12 +283,12 @@ def _new_wimperis_1_control( qctrlopencontrols.DrivenControl The driven control. """ - (maximum_rabi_rate, azimuthal_angle, rabi_rotation) = _predefined_common_attributes( - maximum_rabi_rate, azimuthal_angle, rabi_rotation + (azimuthal_angle, rabi_rotation, maximum_rabi_rate) = _predefined_common_attributes( + azimuthal_angle, rabi_rotation, maximum_rabi_rate ) - if rabi_rotation is not None: - phi_p = _get_transformed_rabi_rotation_wimperis(rabi_rotation) - rabi_rotations = [rabi_rotation, np.pi, 2 * np.pi, np.pi] + + phi_p = _get_transformed_rabi_rotation_wimperis(rabi_rotation) + rabi_rotations = [rabi_rotation, np.pi, 2 * np.pi, np.pi] rabi_rates = [maximum_rabi_rate] * 4 azimuthal_angles = [ @@ -318,7 +312,7 @@ def _new_wimperis_1_control( def _new_solovay_kitaev_1_control( - rabi_rotation: Optional[float] = None, + rabi_rotation: float, azimuthal_angle: float = 0.0, maximum_rabi_rate: float = 2.0 * np.pi, **kwargs @@ -334,6 +328,7 @@ def _new_solovay_kitaev_1_control( Defaults to 2.*np.pi The maximum rabi frequency for the control. azimuthal_angle : float, optional + Defaults to 0. The azimuthal position of the control. kwargs : dict Other keywords required to make a qctrlopencontrols.DrivenControls. @@ -343,13 +338,12 @@ def _new_solovay_kitaev_1_control( qctrlopencontrols.DrivenControl The driven control. """ - (maximum_rabi_rate, azimuthal_angle, rabi_rotation) = _predefined_common_attributes( - maximum_rabi_rate, azimuthal_angle, rabi_rotation + (azimuthal_angle, rabi_rotation, maximum_rabi_rate) = _predefined_common_attributes( + azimuthal_angle, rabi_rotation, maximum_rabi_rate ) - if rabi_rotation is not None: - phi_p = _get_transformed_rabi_rotation_wimperis(rabi_rotation) - rabi_rotations = [rabi_rotation, 2 * np.pi, 2 * np.pi] + phi_p = _get_transformed_rabi_rotation_wimperis(rabi_rotation) + rabi_rotations = [rabi_rotation, 2 * np.pi, 2 * np.pi] rabi_rates = [maximum_rabi_rate] * 3 azimuthal_angles = [ @@ -372,7 +366,7 @@ def _new_solovay_kitaev_1_control( def _short_composite_rotation_for_undoing_length_over_under_shoot_control( - rabi_rotation: Optional[float] = None, + rabi_rotation: float, azimuthal_angle: float = 0.0, maximum_rabi_rate: float = 2.0 * np.pi, **kwargs @@ -382,12 +376,13 @@ def _short_composite_rotation_for_undoing_length_over_under_shoot_control( Parameters ---------- - rabi_rotation : float, optional + rabi_rotation : float The total rabi rotation to be performed by the control. maximum_rabi_rate : float, optional Defaults to 2.*np.pi The maximum rabi frequency for the control. azimuthal_angle : float, optional + Defaults to 0. The azimuthal position of the control. kwargs : dict Other keywords required to make a qctrlopencontrols.DrivenControls. @@ -402,8 +397,8 @@ def _short_composite_rotation_for_undoing_length_over_under_shoot_control( ArgumentsValueError Raised when an argument is invalid. """ - (maximum_rabi_rate, azimuthal_angle, rabi_rotation) = _predefined_common_attributes( - maximum_rabi_rate, azimuthal_angle, rabi_rotation + (azimuthal_angle, rabi_rotation, maximum_rabi_rate) = _predefined_common_attributes( + azimuthal_angle, rabi_rotation, maximum_rabi_rate ) # Create a lookup table for rabi rotation and phase angles, taken from the official paper. @@ -411,30 +406,29 @@ def _short_composite_rotation_for_undoing_length_over_under_shoot_control( def degrees_to_radians(angle_in_degrees): return angle_in_degrees / 180 * np.pi - if rabi_rotation is not None: - if np.isclose(rabi_rotation, np.pi): - theta_1 = degrees_to_radians(180.0) - phi_1 = np.arccos( - -np.pi * np.cos(theta_1) / 2 / theta_1 / np.sin(rabi_rotation / 2) - ) - phi_2 = phi_1 - np.arccos(-np.pi / 2 / theta_1) - elif np.isclose(rabi_rotation, 0.5 * np.pi): - theta_1 = degrees_to_radians(115.2) - phi_1 = np.arccos( - -np.pi * np.cos(theta_1) / 2 / theta_1 / np.sin(rabi_rotation / 2) - ) - phi_2 = phi_1 - np.arccos(-np.pi / 2 / theta_1) - elif np.isclose(rabi_rotation, 0.25 * np.pi): - theta_1 = degrees_to_radians(96.7) - phi_1 = np.arccos( - -np.pi * np.cos(theta_1) / 2 / theta_1 / np.sin(rabi_rotation / 2) - ) - phi_2 = phi_1 - np.arccos(-np.pi / 2 / theta_1) - else: - raise ArgumentsValueError( - "rabi_rotation angle must be either pi, pi/2 or pi/4", - {"rabi_rotation": rabi_rotation}, - ) + if np.isclose(rabi_rotation, np.pi): + theta_1 = degrees_to_radians(180.0) + phi_1 = np.arccos( + -np.pi * np.cos(theta_1) / 2 / theta_1 / np.sin(rabi_rotation / 2) + ) + phi_2 = phi_1 - np.arccos(-np.pi / 2 / theta_1) + elif np.isclose(rabi_rotation, 0.5 * np.pi): + theta_1 = degrees_to_radians(115.2) + phi_1 = np.arccos( + -np.pi * np.cos(theta_1) / 2 / theta_1 / np.sin(rabi_rotation / 2) + ) + phi_2 = phi_1 - np.arccos(-np.pi / 2 / theta_1) + elif np.isclose(rabi_rotation, 0.25 * np.pi): + theta_1 = degrees_to_radians(96.7) + phi_1 = np.arccos( + -np.pi * np.cos(theta_1) / 2 / theta_1 / np.sin(rabi_rotation / 2) + ) + phi_2 = phi_1 - np.arccos(-np.pi / 2 / theta_1) + else: + raise ArgumentsValueError( + "rabi_rotation angle must be either pi, pi/2 or pi/4", + {"rabi_rotation": rabi_rotation}, + ) theta_3 = theta_1 phi_3 = phi_1 @@ -463,7 +457,7 @@ def degrees_to_radians(angle_in_degrees): def _new_compensating_for_off_resonance_with_a_pulse_sequence_control( - rabi_rotation: Optional[float] = None, + rabi_rotation: float, azimuthal_angle: float = 0.0, maximum_rabi_rate: float = 2.0 * np.pi, **kwargs @@ -473,12 +467,13 @@ def _new_compensating_for_off_resonance_with_a_pulse_sequence_control( Parameters ---------- - rabi_rotation : float, optional + rabi_rotation : float The total rabi rotation to be performed by the control. maximum_rabi_rate : float, optional - Defaults to 2.*np.pi + Defaults to 2*np.pi. The maximum rabi frequency for the control. azimuthal_angle : float, optional + Defaults to 0. The azimuthal position of the control. kwargs : dict Other keywords required to make a qctrlopencontrols.DrivenControls. @@ -488,19 +483,16 @@ def _new_compensating_for_off_resonance_with_a_pulse_sequence_control( qctrlopencontrols.DrivenControl The driven control. """ - ( - maximum_rabi_rate, - azimuthal_angle, - rabi_rotation, - ) = _predefined_common_attributes(maximum_rabi_rate, azimuthal_angle, rabi_rotation) + (azimuthal_angle, rabi_rotation, maximum_rabi_rate) = _predefined_common_attributes( + azimuthal_angle, rabi_rotation, maximum_rabi_rate + ) - if rabi_rotation is not None: - k = np.arcsin(np.sin(rabi_rotation / 2.0) / 2.0) - rabi_rotations = [ - rabi_rotation / 2.0 + 2 * np.pi - k, - 2 * np.pi - 2 * k, - rabi_rotation / 2.0 - k, - ] + k = np.arcsin(np.sin(rabi_rotation / 2.0) / 2.0) + rabi_rotations = [ + rabi_rotation / 2.0 + 2 * np.pi - k, + 2 * np.pi - 2 * k, + rabi_rotation / 2.0 - k, + ] rabi_rates = [maximum_rabi_rate] * 3 azimuthal_angles = [azimuthal_angle, azimuthal_angle + np.pi, azimuthal_angle] @@ -519,7 +511,7 @@ def _new_compensating_for_off_resonance_with_a_pulse_sequence_control( def _new_compensating_for_off_resonance_with_a_sequence_with_wimperis_control( - rabi_rotation: Optional[float] = None, + rabi_rotation: float, azimuthal_angle: float = 0.0, maximum_rabi_rate: float = 2.0 * np.pi, **kwargs @@ -530,12 +522,13 @@ def _new_compensating_for_off_resonance_with_a_sequence_with_wimperis_control( Parameters ---------- - rabi_rotation : float, optional + rabi_rotation : float The total rabi rotation to be performed by the control. maximum_rabi_rate : float, optional Defaults to 2.*np.pi The maximum rabi frequency for the control. azimuthal_angle : float, optional + Defaults to 0. The azimuthal position of the control. kwargs : dict Other keywords required to make a qctrlopencontrols.DrivenControls. @@ -545,22 +538,22 @@ def _new_compensating_for_off_resonance_with_a_sequence_with_wimperis_control( qctrlopencontrols.DrivenControl The driven control. """ - (maximum_rabi_rate, azimuthal_angle, rabi_rotation) = _predefined_common_attributes( - maximum_rabi_rate, azimuthal_angle, rabi_rotation + + (azimuthal_angle, rabi_rotation, maximum_rabi_rate) = _predefined_common_attributes( + azimuthal_angle, rabi_rotation, maximum_rabi_rate ) - if rabi_rotation is not None: - phi_p = _get_transformed_rabi_rotation_wimperis(rabi_rotation) - k = np.arcsin(np.sin(rabi_rotation / 2.0) / 2.0) + phi_p = _get_transformed_rabi_rotation_wimperis(rabi_rotation) + k = np.arcsin(np.sin(rabi_rotation / 2.0) / 2.0) - rabi_rotations = [ - 2 * np.pi + rabi_rotation / 2.0 - k, - 2 * np.pi - 2 * k, - rabi_rotation / 2.0 - k, - np.pi, - 2 * np.pi, - np.pi, - ] + rabi_rotations = [ + 2 * np.pi + rabi_rotation / 2.0 - k, + 2 * np.pi - 2 * k, + rabi_rotation / 2.0 - k, + np.pi, + 2 * np.pi, + np.pi, + ] rabi_rates = [maximum_rabi_rate] * 6 azimuthal_angles = [ @@ -586,7 +579,7 @@ def _new_compensating_for_off_resonance_with_a_sequence_with_wimperis_control( def _new_compensating_for_off_resonance_with_a_sequence_with_sk_control( - rabi_rotation: Optional[float] = None, + rabi_rotation: float, azimuthal_angle: float = 0.0, maximum_rabi_rate: float = 2.0 * np.pi, **kwargs @@ -597,12 +590,13 @@ def _new_compensating_for_off_resonance_with_a_sequence_with_sk_control( Parameters ---------- - rabi_rotation : float, optional + rabi_rotation : float The total rabi rotation to be performed by the control. maximum_rabi_rate : float, optional Defaults to 2.*np.pi The maximum rabi frequency for the control. azimuthal_angle : float, optional + Defaults to 0. The azimuthal position of the control. kwargs : dict Other keywords required to make a qctrlopencontrols.DrivenControls. @@ -612,20 +606,19 @@ def _new_compensating_for_off_resonance_with_a_sequence_with_sk_control( qctrlopencontrols.DrivenControl The driven control. """ - (maximum_rabi_rate, azimuthal_angle, rabi_rotation) = _predefined_common_attributes( - maximum_rabi_rate, azimuthal_angle, rabi_rotation + (azimuthal_angle, rabi_rotation, maximum_rabi_rate) = _predefined_common_attributes( + azimuthal_angle, rabi_rotation, maximum_rabi_rate ) - if rabi_rotation is not None: - phi_p = _get_transformed_rabi_rotation_wimperis(rabi_rotation) - k = np.arcsin(np.sin(rabi_rotation / 2.0) / 2.0) - - rabi_rotations = [ - 2 * np.pi + rabi_rotation / 2.0 - k, - 2 * np.pi - 2 * k, - rabi_rotation / 2.0 - k, - 2 * np.pi, - 2 * np.pi, - ] + phi_p = _get_transformed_rabi_rotation_wimperis(rabi_rotation) + k = np.arcsin(np.sin(rabi_rotation / 2.0) / 2.0) + + rabi_rotations = [ + 2 * np.pi + rabi_rotation / 2.0 - k, + 2 * np.pi - 2 * k, + rabi_rotation / 2.0 - k, + 2 * np.pi, + 2 * np.pi, + ] rabi_rates = [maximum_rabi_rate] * 5 azimuthal_angles = [ @@ -650,7 +643,7 @@ def _new_compensating_for_off_resonance_with_a_sequence_with_sk_control( def _new_corpse_in_scrofulous_control( - rabi_rotation: Optional[float] = None, + rabi_rotation: float, azimuthal_angle: float = 0.0, maximum_rabi_rate: float = 2.0 * np.pi, **kwargs @@ -662,12 +655,13 @@ def _new_corpse_in_scrofulous_control( Parameters ---------- - rabi_rotation : float, optional + rabi_rotation : float The total rabi rotation to be performed by the control. maximum_rabi_rate : float, optional Defaults to 2.*np.pi The maximum rabi frequency for the control. azimuthal_angle : float, optional + Defaults to 0. The azimuthal position of the control. kwargs : dict Other keywords required to make a qctrlopencontrols.DrivenControls. @@ -682,8 +676,8 @@ def _new_corpse_in_scrofulous_control( ArgumentsValueError Raised when an argument is invalid. """ - (maximum_rabi_rate, azimuthal_angle, rabi_rotation) = _predefined_common_attributes( - maximum_rabi_rate, azimuthal_angle, rabi_rotation + (azimuthal_angle, rabi_rotation, maximum_rabi_rate) = _predefined_common_attributes( + azimuthal_angle, rabi_rotation, maximum_rabi_rate ) # Create a lookup table for rabi rotation and phase angles, taken from @@ -691,30 +685,29 @@ def _new_corpse_in_scrofulous_control( def degrees_to_radians(angle_in_degrees): return angle_in_degrees / 180 * np.pi - if rabi_rotation is not None: - if np.isclose(rabi_rotation, np.pi): - theta_1 = theta_3 = degrees_to_radians(180.0) - phi_1 = phi_3 = np.arccos( - -np.pi * np.cos(theta_1) / 2 / theta_1 / np.sin(rabi_rotation / 2) - ) - phi_2 = phi_1 - np.arccos(-np.pi / 2 / theta_1) - elif np.isclose(rabi_rotation, 0.5 * np.pi): - theta_1 = theta_3 = degrees_to_radians(115.2) - phi_1 = phi_3 = np.arccos( - -np.pi * np.cos(theta_1) / 2 / theta_1 / np.sin(rabi_rotation / 2) - ) - phi_2 = phi_1 - np.arccos(-np.pi / 2 / theta_1) - elif np.isclose(rabi_rotation, 0.25 * np.pi): - theta_1 = theta_3 = degrees_to_radians(96.7) - phi_1 = phi_3 = np.arccos( - -np.pi * np.cos(theta_1) / 2 / theta_1 / np.sin(rabi_rotation / 2) - ) - phi_2 = phi_1 - np.arccos(-np.pi / 2 / theta_1) - else: - raise ArgumentsValueError( - "rabi_rotation angle must be either pi, pi/2 or pi/4", - {"rabi_rotation": rabi_rotation}, - ) + if np.isclose(rabi_rotation, np.pi): + theta_1 = theta_3 = degrees_to_radians(180.0) + phi_1 = phi_3 = np.arccos( + -np.pi * np.cos(theta_1) / 2 / theta_1 / np.sin(rabi_rotation / 2) + ) + phi_2 = phi_1 - np.arccos(-np.pi / 2 / theta_1) + elif np.isclose(rabi_rotation, 0.5 * np.pi): + theta_1 = theta_3 = degrees_to_radians(115.2) + phi_1 = phi_3 = np.arccos( + -np.pi * np.cos(theta_1) / 2 / theta_1 / np.sin(rabi_rotation / 2) + ) + phi_2 = phi_1 - np.arccos(-np.pi / 2 / theta_1) + elif np.isclose(rabi_rotation, 0.25 * np.pi): + theta_1 = theta_3 = degrees_to_radians(96.7) + phi_1 = phi_3 = np.arccos( + -np.pi * np.cos(theta_1) / 2 / theta_1 / np.sin(rabi_rotation / 2) + ) + phi_2 = phi_1 - np.arccos(-np.pi / 2 / theta_1) + else: + raise ArgumentsValueError( + "rabi_rotation angle must be either pi, pi/2 or pi/4", + {"rabi_rotation": rabi_rotation}, + ) theta_2 = np.pi @@ -752,7 +745,7 @@ def degrees_to_radians(angle_in_degrees): def _new_walsh_amplitude_modulated_filter_1_control( - rabi_rotation: Optional[float] = None, + rabi_rotation: float, azimuthal_angle: float = 0.0, maximum_rabi_rate: float = 2.0 * np.pi, **kwargs @@ -762,12 +755,13 @@ def _new_walsh_amplitude_modulated_filter_1_control( Parameters ---------- - rabi_rotation : float, optional + rabi_rotation : float The total rabi rotation to be performed by the control. maximum_rabi_rate : float, optional Defaults to 2.*np.pi The maximum rabi frequency for the control. azimuthal_angle : float, optional + Defaults to 0. The azimuthal position of the control. kwargs : dict Other keywords required to make a qctrlopencontrols.DrivenControls. @@ -782,8 +776,8 @@ def _new_walsh_amplitude_modulated_filter_1_control( ArgumentsValueError Raised when an argument is invalid. """ - (maximum_rabi_rate, azimuthal_angle, rabi_rotation) = _predefined_common_attributes( - maximum_rabi_rate, azimuthal_angle, rabi_rotation + (azimuthal_angle, rabi_rotation, maximum_rabi_rate) = _predefined_common_attributes( + azimuthal_angle, rabi_rotation, maximum_rabi_rate ) if np.isclose(rabi_rotation, np.pi): From b9338c30f0590ef4464662f37f0388bbbdd92942 Mon Sep 17 00:00:00 2001 From: Li Li Date: Tue, 28 Jul 2020 10:13:23 +1000 Subject: [PATCH 5/5] Fix docstring --- qctrlopencontrols/driven_controls/predefined.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qctrlopencontrols/driven_controls/predefined.py b/qctrlopencontrols/driven_controls/predefined.py index 3ac40bda..cf3f1373 100644 --- a/qctrlopencontrols/driven_controls/predefined.py +++ b/qctrlopencontrols/driven_controls/predefined.py @@ -121,7 +121,7 @@ def _predefined_common_attributes( The azimuthal position of the pulse. rabi_rotation : float The total polar angle to be performed by the pulse. - Defined in polar coordinates. Defaults to None. + Defined in polar coordinates. maximum_rabi_rate : float, optional Defaults to 2.*np.pi The maximum rabi frequency for the pulse.