diff --git a/qctrlopencontrols/__init__.py b/qctrlopencontrols/__init__.py index 5cecd05..33b608c 100644 --- a/qctrlopencontrols/__init__.py +++ b/qctrlopencontrols/__init__.py @@ -48,6 +48,7 @@ new_walsh_sequence, new_x_concatenated_sequence, new_xy_concatenated_sequence, + new_platonic_sequence, ) __all__ = [ @@ -76,4 +77,5 @@ "new_wamf1_control", "new_x_concatenated_sequence", "new_xy_concatenated_sequence", + "new_platonic_sequence", ] diff --git a/qctrlopencontrols/dynamic_decoupling_sequences/predefined.py b/qctrlopencontrols/dynamic_decoupling_sequences/predefined.py index caaf0c2..e0330d5 100644 --- a/qctrlopencontrols/dynamic_decoupling_sequences/predefined.py +++ b/qctrlopencontrols/dynamic_decoupling_sequences/predefined.py @@ -1228,3 +1228,168 @@ def _concatenation_xy(concatenation_sequence) -> np.ndarray: if cumulations[-1] == -2 and cumulations[-2] == -2: cumulations = cumulations[0:-2] return cumulations + + +def new_platonic_sequence( + duration, sequence="Octahedral", pre_post_rotation=False, name=None +) -> DynamicDecouplingSequence: + r""" + Creates a platonic sequence. + + Parameters + ---------- + duration : float + Total duration of the sequence :math:`\tau` (in seconds). + sequence : string, optional. + Sequence to follow, one of ``"Dihedral"``, ``"Tetrahedral"``, + ``"Octahedral"``, ``"Icosahedral"``. Defaults to ``"Octahedral"``. + pre_post_rotation : bool, optional + If ``True``, a :math:`X_{\pi/2}` rotation is added at the + start and end of the sequence. Defaults to ``False``. + name : string, optional + Name of the sequence. Defaults to ``None``. + + Returns + ------- + DynamicDecouplingSequence + The platonic sequence. + + Notes + ----- + The platonic dynamic decoupling sequences use the symmetry of the point + groups associated with certain platonic solids in order to decouple spin-j + (:math:`j \le \frac{5}{2}`) systems from higher-order noise. The pulses are + equally spaced in time, and their number is set by the specific sequence as + illustrated below. + + .. list-table:: + :widths: 25 25 + :header-rows: 1 + + * - Sequence + - Number of pulses + * - Dihedral + - 8 + * - Tetrahedral + - 24 + * - Octahedral + - 48 + * - Icosahedral + - 120 + + For each sequence there are two generators, applied in a specific order so + as to traverse every edge of the associated point group which can be found + in [#]_ Appendix B. These generators are the rotations listed below, + + .. list-table:: + :widths: 25 25 25 + :header-rows: 1 + + * - Sequence + - Generator :math:`a` + - Generator :math:`b` + * - Dihedral + - :math:`\left(\left(1,0,0\right),\pi\right)` + - :math:`\left(\left(0,1,0\right),\pi\right)` + * - Tetrahedral + - :math:`\left(\left(0,0,1\right),\frac{2\pi}{3}\right)` + - :math:`\left(\left(\frac{\sqrt{2}}{3},\sqrt{\frac{2}{3}},\frac{1}{3}\right),\frac{2\pi}{3}\right)` + * - Octahedral + - :math:`\left(\left(0,0,1\right),\frac{2\pi}{4}\right)` + - :math:`\left(\frac{1}{\sqrt{3}}\left(1,1,1\right),\frac{2\pi}{3}\right)` + * - Icosahedral + - :math:`\left(\frac{\left(0,-1,\phi\right)}{\sqrt{\phi+2}},\frac{2\pi}{5}\right)` + - :math:`\left(\frac{\left(1-\phi,0,\phi\right)}{\sqrt{3}},\frac{2\pi}{3}\right)` + + where the rotations are given in axis-angle notation and + :math:`\phi=\frac{\sqrt{5}+1}{2}` is the golden ratio. + + References + ---------- + .. [#] `C. Read, E. Serrano-Ensástiga, and J. Martin, Quantum 9, 1661 (2025). + `_ + """ + check_arguments( + duration > 0, "Sequence duration must be positive.", {"duration": duration} + ) + check_arguments( + sequence in ["Dihedral", "Tetrahedral", "Octahedral", "Icosahedral"], + 'Sequence must be one of "Dihedral", "Tetrahedral", "Octahedral", or "Icosahedral".', + {"sequence": sequence}, + ) + + rabi_rotations, azimuthal_angles, detuning_rotations = None, None, None + + if sequence == "Dihedral": + eulerian_path = np.array([0, 1, 0, 1, 1, 0, 1, 0]) + + rabi_rotations = np.ones(eulerian_path.shape[0]) * np.pi + azimuthal_angles = eulerian_path * np.pi / 2 + detuning_rotations = np.zeros(eulerian_path.shape[0]) + elif sequence == "Tetrahedral": + eulerian_path = np.array( + [0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0] + ) + + rabi_rotations = eulerian_path * 4 * np.sqrt(2) * np.pi / 9 + azimuthal_angles = eulerian_path * np.pi / 3 + detuning_rotations = ( + 1 ^ eulerian_path + ) * 2 * np.pi / 3 + eulerian_path * 2 * np.pi / 9 + elif sequence == "Octahedral": + # fmt:off + eulerian_path = np.array( + [ 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1 ] + ) + # fmt:on + + rabi_rotations = eulerian_path * 2 * np.sqrt(2 / 3) * np.pi / 3 + azimuthal_angles = eulerian_path * np.pi / 4 + detuning_rotations = ( + 1 ^ eulerian_path + ) * np.pi / 2 + eulerian_path * 2 * np.pi / 3 / np.sqrt(3) + else: + # fmt:off + eulerian_path = np.array( + [ 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0 ] + ) + # fmt:on + + phi = (np.sqrt(5) + 1) / 2 # golden ratio + rabi_rotations = (1 ^ eulerian_path) * 2 * np.pi / 5 / np.sqrt( + phi + 2 + ) + eulerian_path * 2 * np.pi * (phi - 1) / 3 / np.sqrt(3) + azimuthal_angles = (1 ^ eulerian_path) * 3 * np.pi / 2 + eulerian_path * np.pi + detuning_rotations = (1 ^ eulerian_path) * 2 * np.pi * phi / 5 / np.sqrt( + phi + 2 + ) + eulerian_path * 2 * np.pi * phi / 3 / np.sqrt(3) + + # Re-use the CPMG offset function to obtain equally spaced pulses along a certain duration. + offsets = _carr_purcell_meiboom_gill_offsets(duration, rabi_rotations.shape[0]) + + if pre_post_rotation: + # Use a pi/2 followed by a -pi/2 X rotation as all the sequences + # correspond with an effective identity gate. + offsets = np.insert(offsets, [0, offsets.shape[0]], [0, duration]) + rabi_rotations = np.insert( + rabi_rotations, [0, rabi_rotations.shape[0]], [np.pi / 2, np.pi / 2] + ) + azimuthal_angles = np.insert( + azimuthal_angles, + [0, azimuthal_angles.shape[0]], + [0, np.pi], + ) + detuning_rotations = np.insert( + detuning_rotations, + [0, detuning_rotations.shape[0]], + [0, 0], + ) + + return DynamicDecouplingSequence( + duration=duration, + offsets=offsets, + rabi_rotations=rabi_rotations, + azimuthal_angles=azimuthal_angles, + detuning_rotations=detuning_rotations, + name=name, + ) diff --git a/tests/test_predefined_dynamical_decoupling.py b/tests/test_predefined_dynamical_decoupling.py index 32e8abf..33df83a 100644 --- a/tests/test_predefined_dynamical_decoupling.py +++ b/tests/test_predefined_dynamical_decoupling.py @@ -29,6 +29,7 @@ new_walsh_sequence, new_x_concatenated_sequence, new_xy_concatenated_sequence, + new_platonic_sequence, ) from qctrlopencontrols.constants import ( SIGMA_X, @@ -843,3 +844,999 @@ def test_if_xy_concatenated_sequence_is_identity(): ) assert _pulses_produce_identity(xy_concat_sequence) + + +def test_dihedral_platonic_sequence(): + """ + Tests the Dihedral order of the platonic sequence. + """ + duration = 10.0 + sequence = new_platonic_sequence(duration=duration, sequence="Dihedral") + count = 8 + + _spacing = duration / count + + _offsets = np.array( + [ + _spacing * 0.5, + _spacing * 0.5 + _spacing, + _spacing * 0.5 + 2 * _spacing, + _spacing * 0.5 + 3 * _spacing, + _spacing * 0.5 + 4 * _spacing, + _spacing * 0.5 + 5 * _spacing, + _spacing * 0.5 + 6 * _spacing, + _spacing * 0.5 + 7 * _spacing, + ] + ) + + _rabi_rotations = np.ones(_offsets.shape) * np.pi + + _azimuthal_angles = np.array( + [0, np.pi / 2, 0, np.pi / 2, np.pi / 2, 0, np.pi / 2, 0] + ) + + _detuning_rotations = np.zeros(_offsets.shape) + + assert np.allclose(_offsets, sequence.offsets) + assert np.allclose(_rabi_rotations, sequence.rabi_rotations) + assert np.allclose(_azimuthal_angles, sequence.azimuthal_angles) + assert np.allclose(_detuning_rotations, sequence.detuning_rotations) + + sequence = new_platonic_sequence( + duration=duration, sequence="Dihedral", pre_post_rotation=True + ) + + _offsets = np.insert(_offsets, [0, _offsets.shape[0]], [0, duration]) + _rabi_rotations = np.insert( + _rabi_rotations, [0, _rabi_rotations.shape[0]], [np.pi / 2, np.pi / 2] + ) + _azimuthal_angles = np.insert( + _azimuthal_angles, [0, _azimuthal_angles.shape[0]], [0, np.pi] + ) + _detuning_rotations = np.insert( + _detuning_rotations, [0, _detuning_rotations.shape[0]], [0, 0] + ) + + assert np.allclose(_offsets, sequence.offsets) + assert np.allclose(_rabi_rotations, sequence.rabi_rotations) + assert np.allclose(_azimuthal_angles, sequence.azimuthal_angles) + assert np.allclose(_detuning_rotations, sequence.detuning_rotations) + + +def test_tetrahedral_platonic_sequence(): + """ + Tests the Tetrahedral order of the platonic sequence. + """ + duration = 10.0 + sequence = new_platonic_sequence(duration=duration, sequence="Tetrahedral") + + count = 24 + _spacing = duration / count + + _offsets = np.array( + [ + _spacing * 0.5, + _spacing * 0.5 + _spacing, + _spacing * 0.5 + 2 * _spacing, + _spacing * 0.5 + 3 * _spacing, + _spacing * 0.5 + 4 * _spacing, + _spacing * 0.5 + 5 * _spacing, + _spacing * 0.5 + 6 * _spacing, + _spacing * 0.5 + 7 * _spacing, + _spacing * 0.5 + 8 * _spacing, + _spacing * 0.5 + 9 * _spacing, + _spacing * 0.5 + 10 * _spacing, + _spacing * 0.5 + 11 * _spacing, + _spacing * 0.5 + 12 * _spacing, + _spacing * 0.5 + 13 * _spacing, + _spacing * 0.5 + 14 * _spacing, + _spacing * 0.5 + 15 * _spacing, + _spacing * 0.5 + 16 * _spacing, + _spacing * 0.5 + 17 * _spacing, + _spacing * 0.5 + 18 * _spacing, + _spacing * 0.5 + 19 * _spacing, + _spacing * 0.5 + 20 * _spacing, + _spacing * 0.5 + 21 * _spacing, + _spacing * 0.5 + 22 * _spacing, + _spacing * 0.5 + 23 * _spacing, + ] + ) + + _rabi_rotations = np.array( + [ + 0, + 4 * np.sqrt(2) * np.pi / 9, + 0, + 0, + 4 * np.sqrt(2) * np.pi / 9, + 0, + 4 * np.sqrt(2) * np.pi / 9, + 4 * np.sqrt(2) * np.pi / 9, + 4 * np.sqrt(2) * np.pi / 9, + 0, + 0, + 4 * np.sqrt(2) * np.pi / 9, + 0, + 4 * np.sqrt(2) * np.pi / 9, + 4 * np.sqrt(2) * np.pi / 9, + 4 * np.sqrt(2) * np.pi / 9, + 0, + 0, + 4 * np.sqrt(2) * np.pi / 9, + 0, + 4 * np.sqrt(2) * np.pi / 9, + 4 * np.sqrt(2) * np.pi / 9, + 0, + 0, + ] + ) + + _azimuthal_angles = np.array( + [ + 0, + np.pi / 3, + 0, + 0, + np.pi / 3, + 0, + np.pi / 3, + np.pi / 3, + np.pi / 3, + 0, + 0, + np.pi / 3, + 0, + np.pi / 3, + np.pi / 3, + np.pi / 3, + 0, + 0, + np.pi / 3, + 0, + np.pi / 3, + np.pi / 3, + 0, + 0, + ] + ) + + _detuning_rotations = np.array( + [ + 2 * np.pi / 3, + 2 * np.pi / 9, + 2 * np.pi / 3, + 2 * np.pi / 3, + 2 * np.pi / 9, + 2 * np.pi / 3, + 2 * np.pi / 9, + 2 * np.pi / 9, + 2 * np.pi / 9, + 2 * np.pi / 3, + 2 * np.pi / 3, + 2 * np.pi / 9, + 2 * np.pi / 3, + 2 * np.pi / 9, + 2 * np.pi / 9, + 2 * np.pi / 9, + 2 * np.pi / 3, + 2 * np.pi / 3, + 2 * np.pi / 9, + 2 * np.pi / 3, + 2 * np.pi / 9, + 2 * np.pi / 9, + 2 * np.pi / 3, + 2 * np.pi / 3, + ] + ) + + assert np.allclose(_offsets, sequence.offsets) + assert np.allclose(_rabi_rotations, sequence.rabi_rotations) + assert np.allclose(_azimuthal_angles, sequence.azimuthal_angles) + assert np.allclose(_detuning_rotations, sequence.detuning_rotations) + + sequence = new_platonic_sequence( + duration=duration, sequence="Tetrahedral", pre_post_rotation=True + ) + + _offsets = np.insert(_offsets, [0, _offsets.shape[0]], [0, duration]) + _rabi_rotations = np.insert( + _rabi_rotations, [0, _rabi_rotations.shape[0]], [np.pi / 2, np.pi / 2] + ) + _azimuthal_angles = np.insert( + _azimuthal_angles, [0, _azimuthal_angles.shape[0]], [0, np.pi] + ) + _detuning_rotations = np.insert( + _detuning_rotations, [0, _detuning_rotations.shape[0]], [0, 0] + ) + + assert np.allclose(_offsets, sequence.offsets) + assert np.allclose(_rabi_rotations, sequence.rabi_rotations) + assert np.allclose(_azimuthal_angles, sequence.azimuthal_angles) + assert np.allclose(_detuning_rotations, sequence.detuning_rotations) + + +def test_octahedral_platonic_sequence(): + """ + Tests the Octahedral order of the platonic sequence. + """ + duration = 10.0 + sequence = new_platonic_sequence(duration=duration, sequence="Octahedral") + + count = 48 + _spacing = duration / count + + _offsets = np.array( + [ + _spacing * 0.5, + _spacing * 0.5 + _spacing, + _spacing * 0.5 + 2 * _spacing, + _spacing * 0.5 + 3 * _spacing, + _spacing * 0.5 + 4 * _spacing, + _spacing * 0.5 + 5 * _spacing, + _spacing * 0.5 + 6 * _spacing, + _spacing * 0.5 + 7 * _spacing, + _spacing * 0.5 + 8 * _spacing, + _spacing * 0.5 + 9 * _spacing, + _spacing * 0.5 + 10 * _spacing, + _spacing * 0.5 + 11 * _spacing, + _spacing * 0.5 + 12 * _spacing, + _spacing * 0.5 + 13 * _spacing, + _spacing * 0.5 + 14 * _spacing, + _spacing * 0.5 + 15 * _spacing, + _spacing * 0.5 + 16 * _spacing, + _spacing * 0.5 + 17 * _spacing, + _spacing * 0.5 + 18 * _spacing, + _spacing * 0.5 + 19 * _spacing, + _spacing * 0.5 + 20 * _spacing, + _spacing * 0.5 + 21 * _spacing, + _spacing * 0.5 + 22 * _spacing, + _spacing * 0.5 + 23 * _spacing, + _spacing * 0.5 + 24 * _spacing, + _spacing * 0.5 + 25 * _spacing, + _spacing * 0.5 + 26 * _spacing, + _spacing * 0.5 + 27 * _spacing, + _spacing * 0.5 + 28 * _spacing, + _spacing * 0.5 + 29 * _spacing, + _spacing * 0.5 + 30 * _spacing, + _spacing * 0.5 + 31 * _spacing, + _spacing * 0.5 + 32 * _spacing, + _spacing * 0.5 + 33 * _spacing, + _spacing * 0.5 + 34 * _spacing, + _spacing * 0.5 + 35 * _spacing, + _spacing * 0.5 + 36 * _spacing, + _spacing * 0.5 + 37 * _spacing, + _spacing * 0.5 + 38 * _spacing, + _spacing * 0.5 + 39 * _spacing, + _spacing * 0.5 + 40 * _spacing, + _spacing * 0.5 + 41 * _spacing, + _spacing * 0.5 + 42 * _spacing, + _spacing * 0.5 + 43 * _spacing, + _spacing * 0.5 + 44 * _spacing, + _spacing * 0.5 + 45 * _spacing, + _spacing * 0.5 + 46 * _spacing, + _spacing * 0.5 + 47 * _spacing, + ] + ) + + _rabi_rotations = np.array( + [ + 0, + 2 * np.sqrt(2 / 3) * np.pi / 3, + 0, + 0, + 0, + 2 * np.sqrt(2 / 3) * np.pi / 3, + 2 * np.sqrt(2 / 3) * np.pi / 3, + 2 * np.sqrt(2 / 3) * np.pi / 3, + 0, + 2 * np.sqrt(2 / 3) * np.pi / 3, + 0, + 0, + 2 * np.sqrt(2 / 3) * np.pi / 3, + 2 * np.sqrt(2 / 3) * np.pi / 3, + 2 * np.sqrt(2 / 3) * np.pi / 3, + 0, + 0, + 2 * np.sqrt(2 / 3) * np.pi / 3, + 0, + 2 * np.sqrt(2 / 3) * np.pi / 3, + 2 * np.sqrt(2 / 3) * np.pi / 3, + 0, + 0, + 0, + 0, + 2 * np.sqrt(2 / 3) * np.pi / 3, + 0, + 2 * np.sqrt(2 / 3) * np.pi / 3, + 2 * np.sqrt(2 / 3) * np.pi / 3, + 2 * np.sqrt(2 / 3) * np.pi / 3, + 0, + 2 * np.sqrt(2 / 3) * np.pi / 3, + 0, + 0, + 2 * np.sqrt(2 / 3) * np.pi / 3, + 2 * np.sqrt(2 / 3) * np.pi / 3, + 0, + 0, + 0, + 0, + 2 * np.sqrt(2 / 3) * np.pi / 3, + 0, + 2 * np.sqrt(2 / 3) * np.pi / 3, + 2 * np.sqrt(2 / 3) * np.pi / 3, + 2 * np.sqrt(2 / 3) * np.pi / 3, + 0, + 2 * np.sqrt(2 / 3) * np.pi / 3, + 2 * np.sqrt(2 / 3) * np.pi / 3, + ] + ) + + _azimuthal_angles = np.array( + [ + 0, + np.pi / 4, + 0, + 0, + 0, + np.pi / 4, + np.pi / 4, + np.pi / 4, + 0, + np.pi / 4, + 0, + 0, + np.pi / 4, + np.pi / 4, + np.pi / 4, + 0, + 0, + np.pi / 4, + 0, + np.pi / 4, + np.pi / 4, + 0, + 0, + 0, + 0, + np.pi / 4, + 0, + np.pi / 4, + np.pi / 4, + np.pi / 4, + 0, + np.pi / 4, + 0, + 0, + np.pi / 4, + np.pi / 4, + 0, + 0, + 0, + 0, + np.pi / 4, + 0, + np.pi / 4, + np.pi / 4, + np.pi / 4, + 0, + np.pi / 4, + np.pi / 4, + ] + ) + + _detuning_rotations = np.array( + [ + np.pi / 2, + 2 * np.pi / 3 / np.sqrt(3), + np.pi / 2, + np.pi / 2, + np.pi / 2, + 2 * np.pi / 3 / np.sqrt(3), + 2 * np.pi / 3 / np.sqrt(3), + 2 * np.pi / 3 / np.sqrt(3), + np.pi / 2, + 2 * np.pi / 3 / np.sqrt(3), + np.pi / 2, + np.pi / 2, + 2 * np.pi / 3 / np.sqrt(3), + 2 * np.pi / 3 / np.sqrt(3), + 2 * np.pi / 3 / np.sqrt(3), + np.pi / 2, + np.pi / 2, + 2 * np.pi / 3 / np.sqrt(3), + np.pi / 2, + 2 * np.pi / 3 / np.sqrt(3), + 2 * np.pi / 3 / np.sqrt(3), + np.pi / 2, + np.pi / 2, + np.pi / 2, + np.pi / 2, + 2 * np.pi / 3 / np.sqrt(3), + np.pi / 2, + 2 * np.pi / 3 / np.sqrt(3), + 2 * np.pi / 3 / np.sqrt(3), + 2 * np.pi / 3 / np.sqrt(3), + np.pi / 2, + 2 * np.pi / 3 / np.sqrt(3), + np.pi / 2, + np.pi / 2, + 2 * np.pi / 3 / np.sqrt(3), + 2 * np.pi / 3 / np.sqrt(3), + np.pi / 2, + np.pi / 2, + np.pi / 2, + np.pi / 2, + 2 * np.pi / 3 / np.sqrt(3), + np.pi / 2, + 2 * np.pi / 3 / np.sqrt(3), + 2 * np.pi / 3 / np.sqrt(3), + 2 * np.pi / 3 / np.sqrt(3), + np.pi / 2, + 2 * np.pi / 3 / np.sqrt(3), + 2 * np.pi / 3 / np.sqrt(3), + ] + ) + + assert np.allclose(_offsets, sequence.offsets) + assert np.allclose(_rabi_rotations, sequence.rabi_rotations) + assert np.allclose(_azimuthal_angles, sequence.azimuthal_angles) + assert np.allclose(_detuning_rotations, sequence.detuning_rotations) + + sequence = new_platonic_sequence( + duration=duration, sequence="Octahedral", pre_post_rotation=True + ) + + _offsets = np.insert(_offsets, [0, _offsets.shape[0]], [0, duration]) + _rabi_rotations = np.insert( + _rabi_rotations, [0, _rabi_rotations.shape[0]], [np.pi / 2, np.pi / 2] + ) + _azimuthal_angles = np.insert( + _azimuthal_angles, [0, _azimuthal_angles.shape[0]], [0, np.pi] + ) + _detuning_rotations = np.insert( + _detuning_rotations, [0, _detuning_rotations.shape[0]], [0, 0] + ) + + assert np.allclose(_offsets, sequence.offsets) + assert np.allclose(_rabi_rotations, sequence.rabi_rotations) + assert np.allclose(_azimuthal_angles, sequence.azimuthal_angles) + assert np.allclose(_detuning_rotations, sequence.detuning_rotations) + + +def test_icosahedral_platonic_sequence(): + """ + Tests the Icosahedral order of the platonic sequence. + """ + duration = 10.0 + + sequence = new_platonic_sequence(duration=duration, sequence="Icosahedral") + + count = 120 + _spacing = duration / count + + _offsets = np.array( + [ + _spacing * 0.5, + _spacing * 0.5 + _spacing, + _spacing * 0.5 + 2 * _spacing, + _spacing * 0.5 + 3 * _spacing, + _spacing * 0.5 + 4 * _spacing, + _spacing * 0.5 + 5 * _spacing, + _spacing * 0.5 + 6 * _spacing, + _spacing * 0.5 + 7 * _spacing, + _spacing * 0.5 + 8 * _spacing, + _spacing * 0.5 + 9 * _spacing, + _spacing * 0.5 + 10 * _spacing, + _spacing * 0.5 + 11 * _spacing, + _spacing * 0.5 + 12 * _spacing, + _spacing * 0.5 + 13 * _spacing, + _spacing * 0.5 + 14 * _spacing, + _spacing * 0.5 + 15 * _spacing, + _spacing * 0.5 + 16 * _spacing, + _spacing * 0.5 + 17 * _spacing, + _spacing * 0.5 + 18 * _spacing, + _spacing * 0.5 + 19 * _spacing, + _spacing * 0.5 + 20 * _spacing, + _spacing * 0.5 + 21 * _spacing, + _spacing * 0.5 + 22 * _spacing, + _spacing * 0.5 + 23 * _spacing, + _spacing * 0.5 + 24 * _spacing, + _spacing * 0.5 + 25 * _spacing, + _spacing * 0.5 + 26 * _spacing, + _spacing * 0.5 + 27 * _spacing, + _spacing * 0.5 + 28 * _spacing, + _spacing * 0.5 + 29 * _spacing, + _spacing * 0.5 + 30 * _spacing, + _spacing * 0.5 + 31 * _spacing, + _spacing * 0.5 + 32 * _spacing, + _spacing * 0.5 + 33 * _spacing, + _spacing * 0.5 + 34 * _spacing, + _spacing * 0.5 + 35 * _spacing, + _spacing * 0.5 + 36 * _spacing, + _spacing * 0.5 + 37 * _spacing, + _spacing * 0.5 + 38 * _spacing, + _spacing * 0.5 + 39 * _spacing, + _spacing * 0.5 + 40 * _spacing, + _spacing * 0.5 + 41 * _spacing, + _spacing * 0.5 + 42 * _spacing, + _spacing * 0.5 + 43 * _spacing, + _spacing * 0.5 + 44 * _spacing, + _spacing * 0.5 + 45 * _spacing, + _spacing * 0.5 + 46 * _spacing, + _spacing * 0.5 + 47 * _spacing, + _spacing * 0.5 + 48 * _spacing, + _spacing * 0.5 + 49 * _spacing, + _spacing * 0.5 + 50 * _spacing, + _spacing * 0.5 + 51 * _spacing, + _spacing * 0.5 + 52 * _spacing, + _spacing * 0.5 + 53 * _spacing, + _spacing * 0.5 + 54 * _spacing, + _spacing * 0.5 + 55 * _spacing, + _spacing * 0.5 + 56 * _spacing, + _spacing * 0.5 + 57 * _spacing, + _spacing * 0.5 + 58 * _spacing, + _spacing * 0.5 + 59 * _spacing, + _spacing * 0.5 + 60 * _spacing, + _spacing * 0.5 + 61 * _spacing, + _spacing * 0.5 + 62 * _spacing, + _spacing * 0.5 + 63 * _spacing, + _spacing * 0.5 + 64 * _spacing, + _spacing * 0.5 + 65 * _spacing, + _spacing * 0.5 + 66 * _spacing, + _spacing * 0.5 + 67 * _spacing, + _spacing * 0.5 + 68 * _spacing, + _spacing * 0.5 + 69 * _spacing, + _spacing * 0.5 + 70 * _spacing, + _spacing * 0.5 + 71 * _spacing, + _spacing * 0.5 + 72 * _spacing, + _spacing * 0.5 + 73 * _spacing, + _spacing * 0.5 + 74 * _spacing, + _spacing * 0.5 + 75 * _spacing, + _spacing * 0.5 + 76 * _spacing, + _spacing * 0.5 + 77 * _spacing, + _spacing * 0.5 + 78 * _spacing, + _spacing * 0.5 + 79 * _spacing, + _spacing * 0.5 + 80 * _spacing, + _spacing * 0.5 + 81 * _spacing, + _spacing * 0.5 + 82 * _spacing, + _spacing * 0.5 + 83 * _spacing, + _spacing * 0.5 + 84 * _spacing, + _spacing * 0.5 + 85 * _spacing, + _spacing * 0.5 + 86 * _spacing, + _spacing * 0.5 + 87 * _spacing, + _spacing * 0.5 + 88 * _spacing, + _spacing * 0.5 + 89 * _spacing, + _spacing * 0.5 + 90 * _spacing, + _spacing * 0.5 + 91 * _spacing, + _spacing * 0.5 + 92 * _spacing, + _spacing * 0.5 + 93 * _spacing, + _spacing * 0.5 + 94 * _spacing, + _spacing * 0.5 + 95 * _spacing, + _spacing * 0.5 + 96 * _spacing, + _spacing * 0.5 + 97 * _spacing, + _spacing * 0.5 + 98 * _spacing, + _spacing * 0.5 + 99 * _spacing, + _spacing * 0.5 + 100 * _spacing, + _spacing * 0.5 + 101 * _spacing, + _spacing * 0.5 + 102 * _spacing, + _spacing * 0.5 + 103 * _spacing, + _spacing * 0.5 + 104 * _spacing, + _spacing * 0.5 + 105 * _spacing, + _spacing * 0.5 + 106 * _spacing, + _spacing * 0.5 + 107 * _spacing, + _spacing * 0.5 + 108 * _spacing, + _spacing * 0.5 + 109 * _spacing, + _spacing * 0.5 + 110 * _spacing, + _spacing * 0.5 + 111 * _spacing, + _spacing * 0.5 + 112 * _spacing, + _spacing * 0.5 + 113 * _spacing, + _spacing * 0.5 + 114 * _spacing, + _spacing * 0.5 + 115 * _spacing, + _spacing * 0.5 + 116 * _spacing, + _spacing * 0.5 + 117 * _spacing, + _spacing * 0.5 + 118 * _spacing, + _spacing * 0.5 + 119 * _spacing, + ] + ) + + phi = (np.sqrt(5) + 1) / 2 # golden ratio + + _rabi_rotations = np.array( + [ + 2 * np.pi * (phi - 1) / 3 / np.sqrt(3), + 2 * np.pi / 5 / np.sqrt(phi + 2), + 2 * np.pi / 5 / np.sqrt(phi + 2), + 2 * np.pi / 5 / np.sqrt(phi + 2), + 2 * np.pi * (phi - 1) / 3 / np.sqrt(3), + 2 * np.pi * (phi - 1) / 3 / np.sqrt(3), + 2 * np.pi / 5 / np.sqrt(phi + 2), + 2 * np.pi / 5 / np.sqrt(phi + 2), + 2 * np.pi * (phi - 1) / 3 / np.sqrt(3), + 2 * np.pi / 5 / np.sqrt(phi + 2), + 2 * np.pi / 5 / np.sqrt(phi + 2), + 2 * np.pi / 5 / np.sqrt(phi + 2), + 2 * np.pi / 5 / np.sqrt(phi + 2), + 2 * np.pi / 5 / np.sqrt(phi + 2), + 2 * np.pi * (phi - 1) / 3 / np.sqrt(3), + 2 * np.pi * (phi - 1) / 3 / np.sqrt(3), + 2 * np.pi / 5 / np.sqrt(phi + 2), + 2 * np.pi / 5 / np.sqrt(phi + 2), + 2 * np.pi / 5 / np.sqrt(phi + 2), + 2 * np.pi * (phi - 1) / 3 / np.sqrt(3), + 2 * np.pi / 5 / np.sqrt(phi + 2), + 2 * np.pi * (phi - 1) / 3 / np.sqrt(3), + 2 * np.pi * (phi - 1) / 3 / np.sqrt(3), + 2 * np.pi * (phi - 1) / 3 / np.sqrt(3), + 2 * np.pi / 5 / np.sqrt(phi + 2), + 2 * np.pi * (phi - 1) / 3 / np.sqrt(3), + 2 * np.pi / 5 / np.sqrt(phi + 2), + 2 * np.pi / 5 / np.sqrt(phi + 2), + 2 * np.pi * (phi - 1) / 3 / np.sqrt(3), + 2 * np.pi * (phi - 1) / 3 / np.sqrt(3), + 2 * np.pi / 5 / np.sqrt(phi + 2), + 2 * np.pi / 5 / np.sqrt(phi + 2), + 2 * np.pi * (phi - 1) / 3 / np.sqrt(3), + 2 * np.pi * (phi - 1) / 3 / np.sqrt(3), + 2 * np.pi / 5 / np.sqrt(phi + 2), + 2 * np.pi * (phi - 1) / 3 / np.sqrt(3), + 2 * np.pi * (phi - 1) / 3 / np.sqrt(3), + 2 * np.pi / 5 / np.sqrt(phi + 2), + 2 * np.pi * (phi - 1) / 3 / np.sqrt(3), + 2 * np.pi * (phi - 1) / 3 / np.sqrt(3), + 2 * np.pi / 5 / np.sqrt(phi + 2), + 2 * np.pi * (phi - 1) / 3 / np.sqrt(3), + 2 * np.pi * (phi - 1) / 3 / np.sqrt(3), + 2 * np.pi * (phi - 1) / 3 / np.sqrt(3), + 2 * np.pi / 5 / np.sqrt(phi + 2), + 2 * np.pi / 5 / np.sqrt(phi + 2), + 2 * np.pi / 5 / np.sqrt(phi + 2), + 2 * np.pi / 5 / np.sqrt(phi + 2), + 2 * np.pi * (phi - 1) / 3 / np.sqrt(3), + 2 * np.pi / 5 / np.sqrt(phi + 2), + 2 * np.pi * (phi - 1) / 3 / np.sqrt(3), + 2 * np.pi * (phi - 1) / 3 / np.sqrt(3), + 2 * np.pi * (phi - 1) / 3 / np.sqrt(3), + 2 * np.pi / 5 / np.sqrt(phi + 2), + 2 * np.pi / 5 / np.sqrt(phi + 2), + 2 * np.pi / 5 / np.sqrt(phi + 2), + 2 * np.pi * (phi - 1) / 3 / np.sqrt(3), + 2 * np.pi / 5 / np.sqrt(phi + 2), + 2 * np.pi * (phi - 1) / 3 / np.sqrt(3), + 2 * np.pi * (phi - 1) / 3 / np.sqrt(3), + 2 * np.pi * (phi - 1) / 3 / np.sqrt(3), + 2 * np.pi / 5 / np.sqrt(phi + 2), + 2 * np.pi / 5 / np.sqrt(phi + 2), + 2 * np.pi / 5 / np.sqrt(phi + 2), + 2 * np.pi * (phi - 1) / 3 / np.sqrt(3), + 2 * np.pi / 5 / np.sqrt(phi + 2), + 2 * np.pi * (phi - 1) / 3 / np.sqrt(3), + 2 * np.pi * (phi - 1) / 3 / np.sqrt(3), + 2 * np.pi * (phi - 1) / 3 / np.sqrt(3), + 2 * np.pi / 5 / np.sqrt(phi + 2), + 2 * np.pi / 5 / np.sqrt(phi + 2), + 2 * np.pi * (phi - 1) / 3 / np.sqrt(3), + 2 * np.pi / 5 / np.sqrt(phi + 2), + 2 * np.pi * (phi - 1) / 3 / np.sqrt(3), + 2 * np.pi * (phi - 1) / 3 / np.sqrt(3), + 2 * np.pi / 5 / np.sqrt(phi + 2), + 2 * np.pi / 5 / np.sqrt(phi + 2), + 2 * np.pi * (phi - 1) / 3 / np.sqrt(3), + 2 * np.pi * (phi - 1) / 3 / np.sqrt(3), + 2 * np.pi / 5 / np.sqrt(phi + 2), + 2 * np.pi / 5 / np.sqrt(phi + 2), + 2 * np.pi * (phi - 1) / 3 / np.sqrt(3), + 2 * np.pi * (phi - 1) / 3 / np.sqrt(3), + 2 * np.pi / 5 / np.sqrt(phi + 2), + 2 * np.pi / 5 / np.sqrt(phi + 2), + 2 * np.pi * (phi - 1) / 3 / np.sqrt(3), + 2 * np.pi * (phi - 1) / 3 / np.sqrt(3), + 2 * np.pi * (phi - 1) / 3 / np.sqrt(3), + 2 * np.pi / 5 / np.sqrt(phi + 2), + 2 * np.pi * (phi - 1) / 3 / np.sqrt(3), + 2 * np.pi * (phi - 1) / 3 / np.sqrt(3), + 2 * np.pi * (phi - 1) / 3 / np.sqrt(3), + 2 * np.pi / 5 / np.sqrt(phi + 2), + 2 * np.pi / 5 / np.sqrt(phi + 2), + 2 * np.pi * (phi - 1) / 3 / np.sqrt(3), + 2 * np.pi / 5 / np.sqrt(phi + 2), + 2 * np.pi * (phi - 1) / 3 / np.sqrt(3), + 2 * np.pi * (phi - 1) / 3 / np.sqrt(3), + 2 * np.pi * (phi - 1) / 3 / np.sqrt(3), + 2 * np.pi / 5 / np.sqrt(phi + 2), + 2 * np.pi / 5 / np.sqrt(phi + 2), + 2 * np.pi * (phi - 1) / 3 / np.sqrt(3), + 2 * np.pi / 5 / np.sqrt(phi + 2), + 2 * np.pi * (phi - 1) / 3 / np.sqrt(3), + 2 * np.pi * (phi - 1) / 3 / np.sqrt(3), + 2 * np.pi * (phi - 1) / 3 / np.sqrt(3), + 2 * np.pi / 5 / np.sqrt(phi + 2), + 2 * np.pi / 5 / np.sqrt(phi + 2), + 2 * np.pi * (phi - 1) / 3 / np.sqrt(3), + 2 * np.pi / 5 / np.sqrt(phi + 2), + 2 * np.pi * (phi - 1) / 3 / np.sqrt(3), + 2 * np.pi * (phi - 1) / 3 / np.sqrt(3), + 2 * np.pi * (phi - 1) / 3 / np.sqrt(3), + 2 * np.pi / 5 / np.sqrt(phi + 2), + 2 * np.pi * (phi - 1) / 3 / np.sqrt(3), + 2 * np.pi / 5 / np.sqrt(phi + 2), + 2 * np.pi / 5 / np.sqrt(phi + 2), + 2 * np.pi / 5 / np.sqrt(phi + 2), + 2 * np.pi / 5 / np.sqrt(phi + 2), + 2 * np.pi / 5 / np.sqrt(phi + 2), + ] + ) + + _azimuthal_angles = np.array( + [ + np.pi, + 3 * np.pi / 2, + 3 * np.pi / 2, + 3 * np.pi / 2, + np.pi, + np.pi, + 3 * np.pi / 2, + 3 * np.pi / 2, + np.pi, + 3 * np.pi / 2, + 3 * np.pi / 2, + 3 * np.pi / 2, + 3 * np.pi / 2, + 3 * np.pi / 2, + np.pi, + np.pi, + 3 * np.pi / 2, + 3 * np.pi / 2, + 3 * np.pi / 2, + np.pi, + 3 * np.pi / 2, + np.pi, + np.pi, + np.pi, + 3 * np.pi / 2, + np.pi, + 3 * np.pi / 2, + 3 * np.pi / 2, + np.pi, + np.pi, + 3 * np.pi / 2, + 3 * np.pi / 2, + np.pi, + np.pi, + 3 * np.pi / 2, + np.pi, + np.pi, + 3 * np.pi / 2, + np.pi, + np.pi, + 3 * np.pi / 2, + np.pi, + np.pi, + np.pi, + 3 * np.pi / 2, + 3 * np.pi / 2, + 3 * np.pi / 2, + 3 * np.pi / 2, + np.pi, + 3 * np.pi / 2, + np.pi, + np.pi, + np.pi, + 3 * np.pi / 2, + 3 * np.pi / 2, + 3 * np.pi / 2, + np.pi, + 3 * np.pi / 2, + np.pi, + np.pi, + np.pi, + 3 * np.pi / 2, + 3 * np.pi / 2, + 3 * np.pi / 2, + np.pi, + 3 * np.pi / 2, + np.pi, + np.pi, + np.pi, + 3 * np.pi / 2, + 3 * np.pi / 2, + np.pi, + 3 * np.pi / 2, + np.pi, + np.pi, + 3 * np.pi / 2, + 3 * np.pi / 2, + np.pi, + np.pi, + 3 * np.pi / 2, + 3 * np.pi / 2, + np.pi, + np.pi, + 3 * np.pi / 2, + 3 * np.pi / 2, + np.pi, + np.pi, + np.pi, + 3 * np.pi / 2, + np.pi, + np.pi, + np.pi, + 3 * np.pi / 2, + 3 * np.pi / 2, + np.pi, + 3 * np.pi / 2, + np.pi, + np.pi, + np.pi, + 3 * np.pi / 2, + 3 * np.pi / 2, + np.pi, + 3 * np.pi / 2, + np.pi, + np.pi, + np.pi, + 3 * np.pi / 2, + 3 * np.pi / 2, + np.pi, + 3 * np.pi / 2, + np.pi, + np.pi, + np.pi, + 3 * np.pi / 2, + np.pi, + 3 * np.pi / 2, + 3 * np.pi / 2, + 3 * np.pi / 2, + 3 * np.pi / 2, + 3 * np.pi / 2, + ] + ) + + _detuning_rotations = np.array( + [ + 2 * np.pi * phi / 3 / np.sqrt(3), + 2 * np.pi * phi / 5 / np.sqrt(phi + 2), + 2 * np.pi * phi / 5 / np.sqrt(phi + 2), + 2 * np.pi * phi / 5 / np.sqrt(phi + 2), + 2 * np.pi * phi / 3 / np.sqrt(3), + 2 * np.pi * phi / 3 / np.sqrt(3), + 2 * np.pi * phi / 5 / np.sqrt(phi + 2), + 2 * np.pi * phi / 5 / np.sqrt(phi + 2), + 2 * np.pi * phi / 3 / np.sqrt(3), + 2 * np.pi * phi / 5 / np.sqrt(phi + 2), + 2 * np.pi * phi / 5 / np.sqrt(phi + 2), + 2 * np.pi * phi / 5 / np.sqrt(phi + 2), + 2 * np.pi * phi / 5 / np.sqrt(phi + 2), + 2 * np.pi * phi / 5 / np.sqrt(phi + 2), + 2 * np.pi * phi / 3 / np.sqrt(3), + 2 * np.pi * phi / 3 / np.sqrt(3), + 2 * np.pi * phi / 5 / np.sqrt(phi + 2), + 2 * np.pi * phi / 5 / np.sqrt(phi + 2), + 2 * np.pi * phi / 5 / np.sqrt(phi + 2), + 2 * np.pi * phi / 3 / np.sqrt(3), + 2 * np.pi * phi / 5 / np.sqrt(phi + 2), + 2 * np.pi * phi / 3 / np.sqrt(3), + 2 * np.pi * phi / 3 / np.sqrt(3), + 2 * np.pi * phi / 3 / np.sqrt(3), + 2 * np.pi * phi / 5 / np.sqrt(phi + 2), + 2 * np.pi * phi / 3 / np.sqrt(3), + 2 * np.pi * phi / 5 / np.sqrt(phi + 2), + 2 * np.pi * phi / 5 / np.sqrt(phi + 2), + 2 * np.pi * phi / 3 / np.sqrt(3), + 2 * np.pi * phi / 3 / np.sqrt(3), + 2 * np.pi * phi / 5 / np.sqrt(phi + 2), + 2 * np.pi * phi / 5 / np.sqrt(phi + 2), + 2 * np.pi * phi / 3 / np.sqrt(3), + 2 * np.pi * phi / 3 / np.sqrt(3), + 2 * np.pi * phi / 5 / np.sqrt(phi + 2), + 2 * np.pi * phi / 3 / np.sqrt(3), + 2 * np.pi * phi / 3 / np.sqrt(3), + 2 * np.pi * phi / 5 / np.sqrt(phi + 2), + 2 * np.pi * phi / 3 / np.sqrt(3), + 2 * np.pi * phi / 3 / np.sqrt(3), + 2 * np.pi * phi / 5 / np.sqrt(phi + 2), + 2 * np.pi * phi / 3 / np.sqrt(3), + 2 * np.pi * phi / 3 / np.sqrt(3), + 2 * np.pi * phi / 3 / np.sqrt(3), + 2 * np.pi * phi / 5 / np.sqrt(phi + 2), + 2 * np.pi * phi / 5 / np.sqrt(phi + 2), + 2 * np.pi * phi / 5 / np.sqrt(phi + 2), + 2 * np.pi * phi / 5 / np.sqrt(phi + 2), + 2 * np.pi * phi / 3 / np.sqrt(3), + 2 * np.pi * phi / 5 / np.sqrt(phi + 2), + 2 * np.pi * phi / 3 / np.sqrt(3), + 2 * np.pi * phi / 3 / np.sqrt(3), + 2 * np.pi * phi / 3 / np.sqrt(3), + 2 * np.pi * phi / 5 / np.sqrt(phi + 2), + 2 * np.pi * phi / 5 / np.sqrt(phi + 2), + 2 * np.pi * phi / 5 / np.sqrt(phi + 2), + 2 * np.pi * phi / 3 / np.sqrt(3), + 2 * np.pi * phi / 5 / np.sqrt(phi + 2), + 2 * np.pi * phi / 3 / np.sqrt(3), + 2 * np.pi * phi / 3 / np.sqrt(3), + 2 * np.pi * phi / 3 / np.sqrt(3), + 2 * np.pi * phi / 5 / np.sqrt(phi + 2), + 2 * np.pi * phi / 5 / np.sqrt(phi + 2), + 2 * np.pi * phi / 5 / np.sqrt(phi + 2), + 2 * np.pi * phi / 3 / np.sqrt(3), + 2 * np.pi * phi / 5 / np.sqrt(phi + 2), + 2 * np.pi * phi / 3 / np.sqrt(3), + 2 * np.pi * phi / 3 / np.sqrt(3), + 2 * np.pi * phi / 3 / np.sqrt(3), + 2 * np.pi * phi / 5 / np.sqrt(phi + 2), + 2 * np.pi * phi / 5 / np.sqrt(phi + 2), + 2 * np.pi * phi / 3 / np.sqrt(3), + 2 * np.pi * phi / 5 / np.sqrt(phi + 2), + 2 * np.pi * phi / 3 / np.sqrt(3), + 2 * np.pi * phi / 3 / np.sqrt(3), + 2 * np.pi * phi / 5 / np.sqrt(phi + 2), + 2 * np.pi * phi / 5 / np.sqrt(phi + 2), + 2 * np.pi * phi / 3 / np.sqrt(3), + 2 * np.pi * phi / 3 / np.sqrt(3), + 2 * np.pi * phi / 5 / np.sqrt(phi + 2), + 2 * np.pi * phi / 5 / np.sqrt(phi + 2), + 2 * np.pi * phi / 3 / np.sqrt(3), + 2 * np.pi * phi / 3 / np.sqrt(3), + 2 * np.pi * phi / 5 / np.sqrt(phi + 2), + 2 * np.pi * phi / 5 / np.sqrt(phi + 2), + 2 * np.pi * phi / 3 / np.sqrt(3), + 2 * np.pi * phi / 3 / np.sqrt(3), + 2 * np.pi * phi / 3 / np.sqrt(3), + 2 * np.pi * phi / 5 / np.sqrt(phi + 2), + 2 * np.pi * phi / 3 / np.sqrt(3), + 2 * np.pi * phi / 3 / np.sqrt(3), + 2 * np.pi * phi / 3 / np.sqrt(3), + 2 * np.pi * phi / 5 / np.sqrt(phi + 2), + 2 * np.pi * phi / 5 / np.sqrt(phi + 2), + 2 * np.pi * phi / 3 / np.sqrt(3), + 2 * np.pi * phi / 5 / np.sqrt(phi + 2), + 2 * np.pi * phi / 3 / np.sqrt(3), + 2 * np.pi * phi / 3 / np.sqrt(3), + 2 * np.pi * phi / 3 / np.sqrt(3), + 2 * np.pi * phi / 5 / np.sqrt(phi + 2), + 2 * np.pi * phi / 5 / np.sqrt(phi + 2), + 2 * np.pi * phi / 3 / np.sqrt(3), + 2 * np.pi * phi / 5 / np.sqrt(phi + 2), + 2 * np.pi * phi / 3 / np.sqrt(3), + 2 * np.pi * phi / 3 / np.sqrt(3), + 2 * np.pi * phi / 3 / np.sqrt(3), + 2 * np.pi * phi / 5 / np.sqrt(phi + 2), + 2 * np.pi * phi / 5 / np.sqrt(phi + 2), + 2 * np.pi * phi / 3 / np.sqrt(3), + 2 * np.pi * phi / 5 / np.sqrt(phi + 2), + 2 * np.pi * phi / 3 / np.sqrt(3), + 2 * np.pi * phi / 3 / np.sqrt(3), + 2 * np.pi * phi / 3 / np.sqrt(3), + 2 * np.pi * phi / 5 / np.sqrt(phi + 2), + 2 * np.pi * phi / 3 / np.sqrt(3), + 2 * np.pi * phi / 5 / np.sqrt(phi + 2), + 2 * np.pi * phi / 5 / np.sqrt(phi + 2), + 2 * np.pi * phi / 5 / np.sqrt(phi + 2), + 2 * np.pi * phi / 5 / np.sqrt(phi + 2), + 2 * np.pi * phi / 5 / np.sqrt(phi + 2), + ] + ) + + assert np.allclose(_offsets, sequence.offsets) + assert np.allclose(_rabi_rotations, sequence.rabi_rotations) + assert np.allclose(_azimuthal_angles, sequence.azimuthal_angles) + assert np.allclose(_detuning_rotations, sequence.detuning_rotations) + + sequence = new_platonic_sequence( + duration=duration, sequence="Icosahedral", pre_post_rotation=True + ) + + _offsets = np.insert(_offsets, [0, _offsets.shape[0]], [0, duration]) + _rabi_rotations = np.insert( + _rabi_rotations, [0, _rabi_rotations.shape[0]], [np.pi / 2, np.pi / 2] + ) + _azimuthal_angles = np.insert( + _azimuthal_angles, [0, _azimuthal_angles.shape[0]], [0, np.pi] + ) + _detuning_rotations = np.insert( + _detuning_rotations, [0, _detuning_rotations.shape[0]], [0, 0] + ) + + assert np.allclose(_offsets, sequence.offsets) + assert np.allclose(_rabi_rotations, sequence.rabi_rotations) + assert np.allclose(_azimuthal_angles, sequence.azimuthal_angles) + assert np.allclose(_detuning_rotations, sequence.detuning_rotations)