def test_exceptions(self): X = util.paulis[1] n_dt = 10 omega = np.linspace(0, 1, 50) pulse_1 = testutil.rand_pulse_sequence(2, n_dt, btype='Pauli') pulse_2 = testutil.rand_pulse_sequence(2, n_dt, btype='GGM') pulse_1.cache_filter_function(omega) pulse_11 = ff.extend([[pulse_1, 0], [pulse_1, 1]]) pulse_11.cache_filter_function(omega+1) with self.assertRaises(ValueError): # qubit indices don't match on pulse that is remapped ff.extend([(pulse_11, (2, 1, 0))]) with self.assertRaises(ValueError): # wrong dimensions ff.extend([(pulse_1, (0, 1))]) with self.assertRaises(ValueError): # wrong dimensions ff.extend([(pulse_1, (0,))], d_per_qubit=3) with self.assertRaises(ValueError): # wrong dimensions ff.extend([(pulse_11, (0,))]) with self.assertRaises(ValueError): # different dt ff.extend([(pulse_1, 0), [pulse_2, 1]]) with self.assertRaises(ValueError): # Multiple pulses mapped to same qubit ff.extend([(pulse_1, 0), [pulse_1, 0]]) with self.assertRaises(ValueError): # N < max(qubits) ff.extend([(pulse_1, 2)], N=2) with self.assertRaises(ValueError): # cache_filter_function == True and unequal omega ff.extend([(pulse_1, 0), (pulse_11, (1, 2))], cache_filter_function=True, omega=None) with self.assertRaises(ValueError): # cache_diagonalization == False and additional_noise_Hamiltonian # is not None additional_noise_Hamiltonian = [[util.tensor(X, X), np.ones(n_dt)]] ff.extend( [(pulse_1, 0), (pulse_1, 1)], cache_diagonalization=False, additional_noise_Hamiltonian=additional_noise_Hamiltonian ) with self.assertRaises(ValueError): # additional noise Hamiltonian defines existing identifier additional_noise_Hamiltonian = [ [util.tensor(X, X), np.ones(n_dt), 'foo'], [util.tensor(X, X), np.ones(n_dt), 'foo'], ] ff.extend( [(pulse_1, 0), (pulse_1, 1)], additional_noise_Hamiltonian=additional_noise_Hamiltonian ) with self.assertRaises(ValueError): # additional_noise_Hamiltonian has wrong dimensions additional_noise_Hamiltonian = [[util.tensor(X, X, X), np.ones(n_dt)]] ff.extend( [(pulse_1, 0), (pulse_1, 1)], additional_noise_Hamiltonian=additional_noise_Hamiltonian ) with self.assertWarns(UserWarning): # Non-pauli basis ff.extend([(pulse_2, 0)])
def test_caching(self): """Test caching""" pulse_1 = testutil.rand_pulse_sequence(2, 10, btype='Pauli') pulse_2 = testutil.rand_pulse_sequence(2, 10, btype='Pauli') pulse_2.dt = pulse_1.dt pulse_2.t = pulse_1.t omega = util.get_sample_frequencies(pulse_1, 50) # diagonalize one pulse pulse_1.diagonalize() extended_pulse = ff.extend([(pulse_1, 0), (pulse_2, 1)]) self.assertIsNone(extended_pulse._eigvals) self.assertIsNone(extended_pulse._eigvecs) self.assertIsNone(extended_pulse._propagators) self.assertIsNone(extended_pulse._total_propagator) self.assertIsNone(extended_pulse._total_propagator_liouville) self.assertIsNone(extended_pulse._total_phases) self.assertIsNone(extended_pulse._control_matrix) self.assertIsNone(extended_pulse._filter_function) # override extended_pulse = ff.extend([(pulse_1, 0), (pulse_2, 1)], cache_diagonalization=True) self.assertIsNotNone(extended_pulse._eigvals) self.assertIsNotNone(extended_pulse._eigvecs) self.assertIsNotNone(extended_pulse._propagators) self.assertIsNotNone(extended_pulse._total_propagator) self.assertIsNone(extended_pulse._total_propagator_liouville) self.assertIsNone(extended_pulse._total_phases) self.assertIsNone(extended_pulse._control_matrix) self.assertIsNone(extended_pulse._filter_function) # diagonalize both pulse_2.diagonalize() extended_pulse = ff.extend([(pulse_1, 0), (pulse_2, 1)]) self.assertIsNotNone(extended_pulse._eigvals) self.assertIsNotNone(extended_pulse._eigvecs) self.assertIsNotNone(extended_pulse._propagators) self.assertIsNotNone(extended_pulse._total_propagator) self.assertIsNone(extended_pulse._total_propagator_liouville) self.assertIsNone(extended_pulse._total_phases) self.assertIsNone(extended_pulse._control_matrix) self.assertIsNone(extended_pulse._filter_function) # override extended_pulse = ff.extend([(pulse_1, 0), (pulse_2, 1)], cache_diagonalization=False) self.assertIsNone(extended_pulse._eigvals) self.assertIsNone(extended_pulse._eigvecs) self.assertIsNone(extended_pulse._propagators) # Total_propagators is still cached self.assertIsNotNone(extended_pulse._total_propagator) self.assertIsNone(extended_pulse._total_propagator_liouville) self.assertIsNone(extended_pulse._total_phases) self.assertIsNone(extended_pulse._control_matrix) self.assertIsNone(extended_pulse._filter_function) # Get filter function for one pulse pulse_1.cache_filter_function(omega) extended_pulse = ff.extend([(pulse_1, 0), (pulse_2, 1)]) self.assertIsNone(extended_pulse._total_propagator_liouville) self.assertIsNone(extended_pulse._total_phases) self.assertIsNone(extended_pulse._control_matrix) self.assertIsNone(extended_pulse._filter_function) # override extended_pulse = ff.extend([(pulse_1, 0), (pulse_2, 1)], cache_filter_function=True, omega=omega) self.assertIsNotNone(extended_pulse._total_propagator_liouville) self.assertIsNotNone(extended_pulse._total_phases) self.assertIsNotNone(extended_pulse._control_matrix) self.assertIsNotNone(extended_pulse._filter_function) # Get filter function for both pulse_2.cache_filter_function(omega) extended_pulse = ff.extend([(pulse_1, 0), (pulse_2, 1)]) self.assertIsNotNone(extended_pulse._total_propagator_liouville) self.assertIsNotNone(extended_pulse._total_phases) self.assertIsNotNone(extended_pulse._control_matrix) self.assertIsNotNone(extended_pulse._filter_function) # override extended_pulse = ff.extend([(pulse_1, 0), (pulse_2, 1)], cache_filter_function=False) self.assertIsNone(extended_pulse._total_propagator_liouville) self.assertIsNone(extended_pulse._total_phases) self.assertIsNone(extended_pulse._control_matrix) self.assertIsNone(extended_pulse._filter_function)
def test_accuracy(self): ID, X, Y, Z = util.paulis XI = util.tensor(X, ID) IX = util.tensor(ID, X) XII = util.tensor(X, ID, ID) IXI = util.tensor(ID, X, ID) IIX = util.tensor(ID, ID, X) XIII = util.tensor(X, ID, ID, ID) IXII = util.tensor(ID, X, ID, ID) IIXI = util.tensor(ID, ID, X, ID) IIIX = util.tensor(ID, ID, ID, X) YI = util.tensor(Y, ID) IY = util.tensor(ID, Y) YII = util.tensor(Y, ID, ID) IYI = util.tensor(ID, Y, ID) IIY = util.tensor(ID, ID, Y) YIII = util.tensor(Y, ID, ID, ID) IYII = util.tensor(ID, Y, ID, ID) IIYI = util.tensor(ID, ID, Y, ID) IIIY = util.tensor(ID, ID, ID, Y) ZI = util.tensor(Z, ID) IZ = util.tensor(ID, Z) ZII = util.tensor(Z, ID, ID) IZI = util.tensor(ID, Z, ID) ZIII = util.tensor(Z, ID, ID, ID) IZII = util.tensor(ID, Z, ID, ID) IIZI = util.tensor(ID, ID, Z, ID) IIIZ = util.tensor(ID, ID, ID, Z) IIZ = util.tensor(ID, ID, Z) XXX = util.tensor(X, X, X) n_dt = 10 coeffs = rng.standard_normal((3, n_dt)) X_pulse = ff.PulseSequence( [[X, coeffs[0], 'X']], list(zip((X, Y, Z), np.ones((3, n_dt)), ('X', 'Y', 'Z'))), np.ones(n_dt), basis=ff.Basis.pauli(1) ) Y_pulse = ff.PulseSequence( [[Y, coeffs[1], 'Y']], list(zip((X, Y, Z), np.ones((3, n_dt)), ('X', 'Y', 'Z'))), np.ones(n_dt), basis=ff.Basis.pauli(1) ) Z_pulse = ff.PulseSequence( [[Z, coeffs[2], 'Z']], list(zip((X, Y, Z), np.ones((3, n_dt)), ('X', 'Y', 'Z'))), np.ones(n_dt), basis=ff.Basis.pauli(1) ) XZ_pulse = ff.PulseSequence( [[XI, coeffs[0], 'XI'], [IZ, coeffs[2], 'IZ']], list(zip((XI, YI, ZI, IX, IY, IZ), np.ones((6, n_dt)), ('XI', 'YI', 'ZI', 'IX', 'IY', 'IZ'))), np.ones(n_dt), basis=ff.Basis.pauli(2) ) XYZ_pulse = ff.PulseSequence( [[XII, coeffs[0], 'XII'], [IYI, coeffs[1], 'IYI'], [IIZ, coeffs[2], 'IIZ']], list(zip((XII, YII, ZII, IIX, IIY, IIZ, IXI, IYI, IZI, XXX), np.ones((10, n_dt)), ('XII', 'YII', 'ZII', 'IIX', 'IIY', 'IIZ', 'IXI', 'IYI', 'IZI', 'XXX'))), np.ones(n_dt), basis=ff.Basis.pauli(3) ) ZYX_pulse = ff.PulseSequence( [[IIX, coeffs[0], 'IIX'], [IYI, coeffs[1], 'IYI'], [ZII, coeffs[2], 'ZII']], list(zip((IIX, IIY, IIZ, XII, YII, ZII, IXI, IYI, IZI), np.ones((9, n_dt)), ('IIX', 'IIY', 'IIZ', 'XII', 'YII', 'ZII', 'IXI', 'IYI', 'IZI'))), np.ones(n_dt), basis=ff.Basis.pauli(3) ) XZXZ_pulse = ff.PulseSequence( [[XIII, coeffs[0], 'XIII'], [IZII, coeffs[2], 'IZII'], [IIXI, coeffs[0], 'IIXI'], [IIIZ, coeffs[2], 'IIIZ']], list(zip((XIII, YIII, ZIII, IXII, IYII, IZII, IIXI, IIYI, IIZI, IIIX, IIIY, IIIZ), np.ones((12, n_dt)), ('XIII', 'YIII', 'ZIII', 'IXII', 'IYII', 'IZII', 'IIXI', 'IIYI', 'IIZI', 'IIIX', 'IIIY', 'IIIZ'))), np.ones(n_dt), basis=ff.Basis.pauli(4) ) XXZZ_pulse = ff.PulseSequence( [[XIII, coeffs[0], 'XIII'], [IIZI, coeffs[2], 'IIZI'], [IXII, coeffs[0], 'IXII'], [IIIZ, coeffs[2], 'IIIZ']], list(zip((XIII, YIII, ZIII, IIXI, IIYI, IIZI, IXII, IYII, IZII, IIIX, IIIY, IIIZ), np.ones((12, n_dt)), ('XIII', 'YIII', 'ZIII', 'IIXI', 'IIYI', 'IIZI', 'IXII', 'IYII', 'IZII', 'IIIX', 'IIIY', 'IIIZ'))), np.ones(n_dt), basis=ff.Basis.pauli(4) ) # Cache omega = ff.util.get_sample_frequencies(XYZ_pulse, n_samples=50) X_pulse.cache_filter_function(omega) Y_pulse.cache_filter_function(omega) Z_pulse.cache_filter_function(omega) XZ_pulse.cache_filter_function(omega) XYZ_pulse.cache_filter_function(omega) ZYX_pulse.cache_filter_function(omega) XZXZ_pulse.cache_filter_function(omega) XXZZ_pulse.cache_filter_function(omega) # Test that mapping a pulse to itself returns the pulse itself and # issues a warning with self.assertWarns(UserWarning): pulse = ff.extend([(X_pulse, 0)]) self.assertIs(pulse, X_pulse) with self.assertWarns(UserWarning): pulse = ff.extend([(XZ_pulse, (0, 1))]) self.assertIs(pulse, XZ_pulse) # Test mapping two single-qubit pulses to a two-qubit pulse XZ_pulse_ext = ff.extend([ (X_pulse, 0, {'X': 'XI', 'Y': 'YI', 'Z': 'ZI'}), (Z_pulse, 1, {'X': 'IX', 'Y': 'IY', 'Z': 'IZ'}) ]) self.assertEqual(XZ_pulse, XZ_pulse_ext) self.assertCorrectDiagonalization(XZ_pulse_ext, atol=1e-14) self.assertArrayAlmostEqual(XZ_pulse._propagators, XZ_pulse_ext._propagators, atol=1e-10) self.assertArrayAlmostEqual(XZ_pulse._control_matrix, XZ_pulse_ext._control_matrix, atol=1e-9) self.assertArrayAlmostEqual(XZ_pulse._filter_function, XZ_pulse_ext._filter_function, atol=1e-9) # Test additional noise Hamiltonian add_H_n = list(zip((XXX,), np.ones((1, n_dt)), ['XXX'])) XYZ_pulse_ext = ff.extend( [(XZ_pulse, (0, 2), {i: i[0] + 'I' + i[1] for i in XZ_pulse.n_oper_identifiers}), (Y_pulse, 1, {i: 'I' + i[0] + 'I' for i in Y_pulse.n_oper_identifiers})], additional_noise_Hamiltonian=add_H_n ) self.assertEqual(XYZ_pulse, XYZ_pulse_ext) self.assertCorrectDiagonalization(XYZ_pulse_ext, atol=1e-14) self.assertArrayAlmostEqual(XYZ_pulse._propagators, XYZ_pulse_ext._propagators, atol=1e-10) self.assertArrayAlmostEqual(XYZ_pulse._control_matrix, XYZ_pulse_ext._control_matrix, atol=1e-9) self.assertArrayAlmostEqual(XYZ_pulse._filter_function, XYZ_pulse_ext._filter_function, atol=1e-9) # Test remapping a two-qubit pulse ZYX_pulse_ext = ff.extend( [(XZ_pulse, (2, 0), {i: i[1] + 'I' + i[0] for i in XZ_pulse.n_oper_identifiers}), (Y_pulse, 1, {i: 'I' + i[0] + 'I' for i in Y_pulse.n_oper_identifiers})], ) self.assertEqual(ZYX_pulse, ZYX_pulse_ext) self.assertCorrectDiagonalization(ZYX_pulse_ext, atol=1e-14) self.assertArrayAlmostEqual(ZYX_pulse._propagators, ZYX_pulse_ext._propagators, atol=1e-10) self.assertArrayAlmostEqual(ZYX_pulse._control_matrix, ZYX_pulse_ext._control_matrix, atol=1e-9) self.assertArrayAlmostEqual(ZYX_pulse._filter_function, ZYX_pulse_ext._filter_function, atol=1e-9) XZXZ_pulse_ext = ff.extend([ (XZ_pulse, (0, 1), {i: i + 'II' for i in XZ_pulse.n_oper_identifiers}), (XZ_pulse, (2, 3), {i: 'II' + i for i in XZ_pulse.n_oper_identifiers}) ], cache_diagonalization=True) self.assertEqual(XZXZ_pulse, XZXZ_pulse_ext) self.assertCorrectDiagonalization(XZXZ_pulse_ext, atol=1e-14) self.assertArrayAlmostEqual(XZXZ_pulse._propagators, XZXZ_pulse_ext._propagators, atol=1e-10) self.assertArrayAlmostEqual(XZXZ_pulse._control_matrix, XZXZ_pulse_ext._control_matrix, atol=1e-9) self.assertArrayAlmostEqual(XZXZ_pulse._filter_function, XZXZ_pulse_ext._filter_function, atol=1e-8) XZXZ_pulse_ext = ff.extend([ (XZ_pulse, (0, 1), {i: i + 'II' for i in XZ_pulse.n_oper_identifiers}), (XZ_pulse, (2, 3), {i: 'II' + i for i in XZ_pulse.n_oper_identifiers}) ], cache_diagonalization=False) self.assertEqual(XZXZ_pulse, XZXZ_pulse_ext) self.assertArrayAlmostEqual(XZXZ_pulse._total_propagator, XZXZ_pulse_ext._total_propagator, atol=1e-10) # Test merging with overlapping qubit ranges XXZZ_pulse_ext = ff.extend([ (XZ_pulse, (0, 2), {i: i[0] + 'I' + i[1] + 'I' for i in XZ_pulse.n_oper_identifiers}), (XZ_pulse, (1, 3), {i: 'I' + i[0] + 'I' + i[1] for i in XZ_pulse.n_oper_identifiers}), ]) self.assertEqual(XXZZ_pulse, XXZZ_pulse_ext) self.assertCorrectDiagonalization(XXZZ_pulse_ext, atol=1e-14) self.assertArrayAlmostEqual(XXZZ_pulse._propagators, XXZZ_pulse_ext._propagators, atol=1e-10) self.assertArrayAlmostEqual(XXZZ_pulse._control_matrix, XXZZ_pulse_ext._control_matrix, atol=1e-10) self.assertArrayAlmostEqual(XXZZ_pulse._filter_function, XXZZ_pulse_ext._filter_function, atol=1e-8)
def test_extend_with_identity(self): """Test extending a pulse to more qubits""" ID, X, Y, Z = util.paulis n_dt = 10 coeffs = rng.standard_normal((3, n_dt)) ids = ['X', 'Y', 'Z'] pulse = ff.PulseSequence( list(zip((X, Y, Z), coeffs, ids)), list(zip((X, Y, Z), np.ones((3, n_dt)), ids)), np.ones(n_dt), basis=ff.Basis.pauli(1) ) omega = util.get_sample_frequencies(pulse, spacing='log', n_samples=50) for N in rng.randint(2, 5, 4): for target in rng.randint(0, N-1, 2): pulse.cleanup('all') ext_opers = util.tensor(*np.insert(np.tile(ID, (N-1, 3, 1, 1)), target, (X, Y, Z), axis=0)) # By default, extend should add the target qubit as suffix to # identifiers ext_ids = [i + f'_{target}' for i in ids] ext_pulse = ff.PulseSequence( list(zip(ext_opers, coeffs, ext_ids)), list(zip(ext_opers, np.ones((3, n_dt)), ext_ids)), np.ones(n_dt), basis=ff.Basis.pauli(N) ) # Use custom mapping for identifiers and or labels letters = rng.choice(list(string.ascii_letters), size=(3, 5)) mapped_ids = np.array([''.join(l) for l in letters]) mapping = {i: new_id for i, new_id in zip(ids, mapped_ids)} ext_pulse_mapped_identifiers = ff.PulseSequence( list(zip(ext_opers, coeffs, mapped_ids, ext_ids)), list(zip(ext_opers, np.ones((3, n_dt)), mapped_ids, ext_ids)), np.ones(n_dt), basis=ff.Basis.pauli(N) ) ext_pulse_mapped_labels = ff.PulseSequence( list(zip(ext_opers, coeffs, ext_ids, mapped_ids)), list(zip(ext_opers, np.ones((3, n_dt)), ext_ids, mapped_ids)), np.ones(n_dt), basis=ff.Basis.pauli(N) ) ext_pulse_mapped_identifiers_labels = ff.PulseSequence( list(zip(ext_opers, coeffs, mapped_ids)), list(zip(ext_opers, np.ones((3, n_dt)), mapped_ids)), np.ones(n_dt), basis=ff.Basis.pauli(N) ) calc_filter_functionF = rng.randint(0, 2) if calc_filter_functionF: # Expect things to be cached in extended pulse if original # also was cached pulse.cache_filter_function(omega) ext_pulse.cache_filter_function(omega) test_ext_pulse = ff.extend([(pulse, target)], N, d_per_qubit=2) test_ext_pulse_mapped_identifiers = ff.extend( [(pulse, target, mapping)], N, d_per_qubit=2 ) test_ext_pulse_mapped_labels = ff.extend( [(pulse, target, None, mapping)], N, d_per_qubit=2 ) test_ext_pulse_mapped_identifiers_labels = ff.extend( [(pulse, target, mapping, mapping)], N, d_per_qubit=2 ) self.assertEqual(ext_pulse, test_ext_pulse) self.assertEqual(ext_pulse_mapped_identifiers, test_ext_pulse_mapped_identifiers) self.assertEqual(ext_pulse_mapped_labels, test_ext_pulse_mapped_labels) self.assertEqual(ext_pulse_mapped_identifiers_labels, test_ext_pulse_mapped_identifiers_labels) if calc_filter_functionF: self.assertCorrectDiagonalization(test_ext_pulse, atol=1e-14) self.assertArrayAlmostEqual(test_ext_pulse._propagators, ext_pulse._propagators, atol=1e-14) self.assertArrayAlmostEqual( test_ext_pulse._total_propagator_liouville, ext_pulse._total_propagator_liouville, atol=1e-14 ) self.assertArrayAlmostEqual( test_ext_pulse._total_propagator, ext_pulse._total_propagator, atol=1e-14 ) self.assertArrayAlmostEqual(test_ext_pulse._total_phases, ext_pulse._total_phases) self.assertArrayAlmostEqual(test_ext_pulse._control_matrix, ext_pulse._control_matrix, atol=1e-12) self.assertArrayAlmostEqual( test_ext_pulse._filter_function, ext_pulse._filter_function, atol=1e-12 ) else: self.assertIsNone(test_ext_pulse._eigvals) self.assertIsNone(test_ext_pulse._eigvecs) self.assertIsNone(test_ext_pulse._propagators) self.assertIsNone( test_ext_pulse._total_propagator_liouville) self.assertIsNone(test_ext_pulse._total_propagator) self.assertIsNone(test_ext_pulse._total_phases) self.assertIsNone(test_ext_pulse._control_matrix) self.assertIsNone(test_ext_pulse._filter_function) pulse.cleanup('all') ext_pulse.cleanup('all')