def test_tensor_transpose(self): # Test basic functionality paulis = np.array(util.paulis) I, X, Y, Z = paulis arr = util.tensor(I, X, Y, Z) arr_dims = [[2] * 4] * 2 order = np.arange(4) for _ in range(20): order = rng.permutation(order) r = util.tensor_transpose(arr, order, arr_dims) self.assertArrayAlmostEqual(r, util.tensor(*paulis[order])) # Check exceptions with self.assertRaises(ValueError): # wrong arr_dims (too few dims) r = util.tensor_transpose(arr, order, [[2] * 3] * 2) with self.assertRaises(ValueError): # wrong arr_dims (too few dims) r = util.tensor_transpose(arr, order, [[2] * 4] * 1) with self.assertRaises(ValueError): # wrong arr_dims (dims too large) r = util.tensor_transpose(arr, order, [[3] * 4] * 2) with self.assertRaises(ValueError): # wrong order (too few axes) r = util.tensor_transpose(arr, (0, 1, 2), arr_dims) with self.assertRaises(ValueError): # wrong order (index 4 too large) r = util.tensor_transpose(arr, (1, 2, 3, 4), arr_dims) with self.assertRaises(ValueError): # wrong order (not unique axes) r = util.tensor_transpose(arr, (1, 1, 1, 1), arr_dims) with self.assertRaises(TypeError): # wrong order (floats instead of ints) r = util.tensor_transpose(arr, (0., 1., 2., 3.), arr_dims) # random tests for rank, n_args, n_broadcast in zip(rng.randint(1, 4, 10), rng.randint(3, 6, 10), rng.randint(1, 11, 10)): arrs = rng.standard_normal((n_args, n_broadcast, *[2] * rank)) order = rng.permutation(n_args) arr_dims = [[2] * n_args] * rank r = util.tensor_transpose(util.tensor(*arrs, rank=rank), order=order, arr_dims=arr_dims, rank=rank) self.assertArrayAlmostEqual(r, util.tensor(*arrs[order], rank=rank))
data_path = Path(__file__).parent.parent / 'examples/data' struct = io.loadmat(str(data_path / 'CNOT.mat')) eps = np.asarray(struct['eps'], order='C') dt = np.asarray(struct['t'].ravel(), order='C') B = np.asarray(struct['B'].ravel(), order='C') B_avg = struct['BAvg'].ravel() cnot_infid_fast = struct['infid_fast'].ravel() J = np.exp(eps) n_dt = len(dt) d = 16 H = np.empty((6, d, d), dtype=float) Id, Px, Py, Pz = util.paulis # Exchange Hamiltonians H[0] = 1 / 4 * sum(util.tensor(P, P, Id, Id) for P in (Px, Py, Pz)).real H[1] = 1 / 4 * sum(util.tensor(Id, P, P, Id) for P in (Px, Py, Pz)).real H[2] = 1 / 4 * sum(util.tensor(Id, Id, P, P) for P in (Px, Py, Pz)).real # Zeeman Hamiltonians H[3] = 1 / 8 * (util.tensor(Pz, Id, Id, Id) * (-3) + util.tensor(Id, Pz, Id, Id) + util.tensor(Id, Id, Pz, Id) + util.tensor(Id, Id, Id, Pz)).real H[4] = 1 / 4 * (util.tensor(Pz, Id, Id, Id) * (-1) + util.tensor(Id, Pz, Id, Id) * (-1) + util.tensor(Id, Id, Pz, Id) + util.tensor(Id, Id, Id, Pz)).real H[5] = 1 / 8 * (util.tensor(Pz, Id, Id, Id) * (-1) + util.tensor(Id, Pz, Id, Id) * (-1) + util.tensor(Id, Id, Pz, Id) * (-1) + util.tensor(Id, Id, Id, Pz) * 3).real # Mean Magnetic field H0 = B_avg / 2 * sum(
def test_tensor(self): shapes = [(1, 2, 3, 4, 5), (5, 4, 3, 2, 1)] A = rng.standard_normal(shapes[0]) B = rng.standard_normal(shapes[1]) with self.assertRaises(ValueError): util.tensor(A, B) shapes = [(3, 2, 1), (3, 4, 2)] A = rng.standard_normal(shapes[0]) B = rng.standard_normal(shapes[1]) with self.assertRaises(ValueError): util.tensor(A, B, rank=1) self.assertEqual(util.tensor(A, B, rank=2).shape, (3, 8, 2)) self.assertEqual(util.tensor(A, B, rank=3).shape, (9, 8, 2)) shapes = [(10, 1, 3, 2), (10, 1, 2, 3)] A = rng.standard_normal(shapes[0]) B = rng.standard_normal(shapes[1]) self.assertEqual(util.tensor(A, B).shape, (10, 1, 6, 6)) shapes = [(3, 5, 4, 4), (3, 5, 4, 4)] A = rng.standard_normal(shapes[0]) B = rng.standard_normal(shapes[1]) self.assertEqual(util.tensor(A, B).shape, (3, 5, 16, 16)) d = rng.randint(2, 9) eye = np.eye(d) for i in range(d): for j in range(d): A, B = eye[i:i + 1, :], eye[:, j:j + 1] self.assertArrayEqual(util.tensor(A, B, rank=1), np.kron(A, B)) i, j = rng.randint(0, 4, (2, )) A, B = util.paulis[i], util.paulis[j] self.assertArrayEqual(util.tensor(A, B), np.kron(A, B)) args = [ rng.standard_normal((4, 1, 2)), rng.standard_normal((3, 2)), rng.standard_normal((4, 3, 5)) ] self.assertEqual(util.tensor(*args, rank=1).shape, (4, 3, 20)) self.assertEqual(util.tensor(*args, rank=2).shape, (4, 9, 20)) self.assertEqual(util.tensor(*args, rank=3).shape, (16, 9, 20)) args = [rng.standard_normal((2, 3, 4)), rng.standard_normal((4, 3))] with self.assertRaises(ValueError) as err: util.tensor(*args, rank=1) msg = ('Incompatible shapes (2, 3, 4) and (4, 3) for tensor ' + 'product of rank 1.') self.assertEqual(msg, str(err.exception))
def test_tensor_merge(self): # Test basic functionality I, X, Y, Z = util.paulis arr = util.tensor(X, Y, Z) ins = util.tensor(I, I) r1 = util.tensor_merge(arr, ins, pos=[1, 2], arr_dims=[[2] * 3, [2] * 3], ins_dims=[[2] * 2, [2] * 2]) r2 = util.tensor_merge(ins, arr, pos=[0, 1, 2], arr_dims=[[2] * 2, [2] * 2], ins_dims=[[2] * 3, [2] * 3]) self.assertArrayAlmostEqual(r1, util.tensor(X, I, Y, I, Z)) self.assertArrayAlmostEqual(r1, r2) # Test if tensor_merge and tensor_insert produce same results arr = util.tensor(Y, Z) ins = util.tensor(I, X) r1 = util.tensor_merge(arr, ins, pos=[0, 0], arr_dims=[[2] * 2, [2] * 2], ins_dims=[[2] * 2, [2] * 2]) r2 = util.tensor_insert(arr, I, X, pos=[0, 0], arr_dims=[[2] * 2, [2] * 2]) self.assertArrayAlmostEqual(r1, r2) # Test pos being negative r = util.tensor_merge(arr, ins, arr_dims=[[2, 2], [2, 2]], ins_dims=[[2, 2], [2, 2]], pos=(-1, -2)) self.assertArrayAlmostEqual(r, util.tensor(X, Y, I, Z)) # Test exceptions # Wrong dims format with self.assertRaises(ValueError): util.tensor_merge(arr, ins, pos=(1, 2), arr_dims=[[2, 2], [2, 2], [2, 2]], ins_dims=[[2, 2], [2, 2]]) with self.assertRaises(ValueError): util.tensor_merge(arr, ins, pos=(1, 2), arr_dims=[[2, 2], [2, 2]], ins_dims=[[2, 2], [2, 2], [2, 2]]) with self.assertRaises(ValueError): util.tensor_merge(arr, ins, pos=(1, 2), arr_dims=[[2, 2], [2, 2, 2]], ins_dims=[[2, 2], [2, 2]]) with self.assertRaises(ValueError): util.tensor_merge(arr, ins, pos=(1, 2), arr_dims=[[2, 2], [2, 2]], ins_dims=[[2, 2], [2, 2, 2]]) # Wrong pos with self.assertRaises(IndexError): util.tensor_merge(arr, ins, pos=(1, 3), arr_dims=[[2, 2], [2, 2]], ins_dims=[[2, 2], [2, 2]]) # Wrong dimensions given with self.assertRaises(ValueError): util.tensor_merge(arr, ins, pos=(1, 2), arr_dims=[[2, 3], [2, 2]], ins_dims=[[2, 2], [2, 2]]) with self.assertRaises(ValueError): util.tensor_merge(arr, ins, pos=(1, 2), arr_dims=[[2, 2], [2, 2]], ins_dims=[[2, 3], [2, 2]]) # Incompatible shapes arrs, args = (rng.standard_normal( (2, 4, 3, 2)), rng.standard_normal((2, 2, 3, 4))) with self.assertRaises(ValueError) as err: util.tensor_merge(util.tensor(*arrs), util.tensor(*args), pos=(1, 2), arr_dims=[[3, 3], [2, 2]], ins_dims=[[3, 3], [4, 4]]) msg = ('Incompatible shapes (2, 9, 16) and (4, 9, 4) for tensor ' + 'product of rank 2.') self.assertEqual(msg, str(err.exception)) # Test rank 1 and broadcasting arr = rng.standard_normal((2, 10, 3, 4)) ins = rng.standard_normal((2, 10, 3, 2)) r = util.tensor_merge(util.tensor(*arr, rank=1), util.tensor(*ins, rank=1), pos=[0, 1], arr_dims=[[4, 4]], ins_dims=[[2, 2]], rank=1) self.assertArrayAlmostEqual( r, util.tensor(ins[0], arr[0], ins[1], arr[1], rank=1)) # Do some random tests for rank, n_args, n_broadcast in zip(rng.randint(1, 4, 10), rng.randint(3, 6, 10), rng.randint(1, 11, 10)): arrs = rng.standard_normal((n_args, n_broadcast, *[2] * rank)) split_idx = rng.randint(1, n_args - 1) arr = util.tensor(*arrs[split_idx:], rank=rank) ins = util.tensor(*arrs[:split_idx], rank=rank) pos = rng.randint(0, split_idx, split_idx) sorted_arrs = np.insert(arrs[split_idx:], pos, arrs[:split_idx], axis=0) arr_dims = [[2] * (n_args - split_idx)] * rank ins_dims = [[2] * split_idx] * rank r = util.tensor_merge(arr, ins, pos=pos, rank=rank, arr_dims=arr_dims, ins_dims=ins_dims) self.assertArrayAlmostEqual(r, util.tensor(*sorted_arrs, rank=rank))
def test_tensor_insert(self): I, X, Y, Z = util.paulis arr = util.tensor(X, I) with self.assertRaises(ValueError): # Test exception for empty args util.tensor_insert(arr, np.array([[]]), pos=0, arr_dims=[]) r = util.tensor_insert(arr, Y, Z, arr_dims=[[2, 2], [2, 2]], pos=0) self.assertArrayAlmostEqual(r, util.tensor(Y, Z, X, I)) r = util.tensor_insert(arr, Y, Z, arr_dims=[[2, 2], [2, 2]], pos=1) self.assertArrayAlmostEqual(r, util.tensor(X, Y, Z, I)) r = util.tensor_insert(arr, Y, Z, arr_dims=[[2, 2], [2, 2]], pos=2) self.assertArrayAlmostEqual(r, util.tensor(X, I, Y, Z)) # Test pos being negative r = util.tensor_insert(arr, Y, Z, arr_dims=[[2, 2], [2, 2]], pos=-1) self.assertArrayAlmostEqual(r, util.tensor(X, Y, Z, I)) # Test pos exception with self.assertRaises(IndexError) as err: util.tensor_insert(arr, Y, Z, arr_dims=[[2, 2], [2, 2]], pos=3) msg = 'Invalid position 3 specified. Must be between -2 and 2.' self.assertEqual(msg, str(err.exception)) # Test broadcasting and rank != 2 A, B, C = (rng.standard_normal( (2, 3, 1, 2)), rng.standard_normal( (2, 3, 1, 2)), rng.standard_normal((3, 1, 3))) arr = util.tensor(A, C, rank=1) r = util.tensor_insert(arr, B, pos=1, rank=1, arr_dims=[[2, 3]]) self.assertArrayAlmostEqual(r, util.tensor(A, B, C, rank=1)) # Test exceptions for wrong arr_dims format with self.assertRaises(ValueError): util.tensor_insert(arr, B, pos=1, rank=1, arr_dims=[[3, 3], [1, 2], [2, 1]]) with self.assertRaises(ValueError): util.tensor_insert(arr, B, pos=1, rank=1, arr_dims=[[2], [2, 1]]) A, B, C = (rng.standard_normal( (2, 3, 1, 2)), rng.standard_normal( (2, 3, 2, 2)), rng.standard_normal((3, 2, 1))) arr = util.tensor(A, C, rank=3) r = util.tensor_insert(arr, B, pos=1, rank=3, arr_dims=[[3, 3], [1, 2], [2, 1]]) self.assertArrayAlmostEqual(r, util.tensor(A, B, C, rank=3)) # Test exceptions for wrong arr_dims format with self.assertRaises(ValueError): util.tensor_insert(arr, B, pos=1, rank=3, arr_dims=[[1, 2], [2, 1]]) with self.assertRaises(ValueError): util.tensor_insert(arr, B, pos=1, rank=2, arr_dims=[[3, 3, 1], [1, 2], [2]]) A, B, C = (rng.standard_normal((2, 1)), rng.standard_normal( (1, 2, 3)), rng.standard_normal(1)) arr = util.tensor(A, C, rank=1) r = util.tensor_insert(arr, B, pos=0, rank=1, arr_dims=[[1, 1]]) self.assertArrayAlmostEqual(r, util.tensor(A, B, C, rank=1)) arrs, args = [ rng.standard_normal((2, 2, 2)), rng.standard_normal((2, 2, 2)) ] arr_dims = [[2, 2], [2, 2]] r = util.tensor_insert(util.tensor(*arrs), *args, pos=(0, 1), arr_dims=arr_dims) self.assertArrayAlmostEqual( r, util.tensor(args[0], arrs[0], args[1], arrs[1])) r = util.tensor_insert(util.tensor(*arrs), *args, pos=(0, 0), arr_dims=arr_dims) self.assertArrayAlmostEqual(r, util.tensor(*args, *arrs)) r = util.tensor_insert(util.tensor(*arrs), *args, pos=(1, 2), arr_dims=arr_dims) self.assertArrayAlmostEqual( r, util.tensor(*np.insert(arrs, (1, 2), args, axis=0))) # Test exception for wrong pos argument with self.assertRaises(ValueError): util.tensor_insert(util.tensor(*arrs), *args, pos=(0, 1, 2), arr_dims=arr_dims) # Test exception for wrong shapes arrs, args = (rng.standard_normal( (2, 4, 3, 2)), rng.standard_normal((2, 2, 3, 4))) with self.assertRaises(ValueError) as err: util.tensor_insert(util.tensor(*arrs), *args, pos=(1, 2), arr_dims=[[3, 3], [2, 2]]) err_msg = ('Could not insert arg 0 with shape (4, 9, 4) into the ' + 'array with shape (2, 3, 4) at position 1.') cause_msg = ('Incompatible shapes (2, 3, 4) and (4, 9, 4) for ' + 'tensor product of rank 2.') self.assertEqual(err_msg, str(err.exception)) self.assertEqual(cause_msg, str(err.exception.__cause__)) # Do some random tests for rank, n_args, n_broadcast in zip(rng.randint(1, 4, 10), rng.randint(3, 6, 10), rng.randint(1, 11, 10)): arrs = rng.randn(n_args, n_broadcast, *[2] * rank) split_idx = rng.randint(1, n_args - 1) ins_idx = rng.randint(split_idx - n_args, n_args - split_idx) ins_arrs = arrs[:split_idx] arr = util.tensor(*arrs[split_idx:], rank=rank) sorted_arrs = np.insert(arrs[split_idx:], ins_idx, ins_arrs, axis=0) arr_dims = [[2] * (n_args - split_idx)] * rank r = util.tensor_insert(arr, *ins_arrs, pos=ins_idx, rank=rank, arr_dims=arr_dims) self.assertArrayAlmostEqual(r, util.tensor(*sorted_arrs, rank=rank)) pos = rng.randint(-split_idx + 1, split_idx, split_idx) r = util.tensor_insert(arr, *ins_arrs, pos=pos, rank=rank, arr_dims=arr_dims) sorted_arrs = np.insert(arrs[split_idx:], pos, ins_arrs, axis=0) self.assertArrayAlmostEqual(r, util.tensor(*sorted_arrs, rank=rank), atol=1e-10)
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_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')
def test_accuracy(self): paulis = np.array(util.paulis) I, X, Y, Z = paulis amps = rng.standard_normal(rng.randint(1, 11)) pulse = ff.PulseSequence( [[util.tensor(X, Y, Z), amps]], [[util.tensor(X, I, I), np.ones_like(amps), 'XII'], [util.tensor(I, X, I), np.ones_like(amps), 'IXI'], [util.tensor(I, I, X), np.ones_like(amps), 'IIX']], np.ones_like(amps), ff.Basis.pauli(3) ) omega = util.get_sample_frequencies(pulse, 50) pulse.cache_filter_function(omega) for _ in range(100): order = rng.permutation(range(3)) reordered_pulse = ff.PulseSequence( [[util.tensor(*paulis[1:][order]), amps]], [[util.tensor(*paulis[[1, 0, 0]][order]), np.ones_like(amps), (''.join(['XII'[o] for o in order]))], [util.tensor(*paulis[[0, 1, 0]][order]), np.ones_like(amps), (''.join(['IXI'[o] for o in order]))], [util.tensor(*paulis[[0, 0, 1]][order]), np.ones_like(amps), (''.join(['IIX'[o] for o in order]))]], np.ones_like(amps), ff.Basis.pauli(3) ) reordered_pulse.cache_filter_function(omega) remapped_pulse = ff.remap( pulse, order, oper_identifier_mapping={ 'A_0': 'A_0', 'XII': ''.join(['XII'[o] for o in order]), 'IXI': ''.join(['IXI'[o] for o in order]), 'IIX': ''.join(['IIX'[o] for o in order]) } ) self.assertEqual(reordered_pulse, remapped_pulse) self.assertArrayAlmostEqual(reordered_pulse.t, remapped_pulse.t) self.assertEqual(reordered_pulse.d, remapped_pulse.d) self.assertEqual(reordered_pulse.basis, remapped_pulse.basis) self.assertArrayAlmostEqual(reordered_pulse._omega, remapped_pulse.omega) self.assertArrayAlmostEqual(reordered_pulse._propagators, remapped_pulse._propagators, atol=1e-14) self.assertArrayAlmostEqual(reordered_pulse._total_propagator, remapped_pulse._total_propagator, atol=1e-14) self.assertArrayAlmostEqual( reordered_pulse._total_propagator_liouville, remapped_pulse._total_propagator_liouville, atol=1e-14 ) self.assertArrayAlmostEqual(reordered_pulse._total_phases, remapped_pulse._total_phases) self.assertArrayAlmostEqual(reordered_pulse._control_matrix, remapped_pulse._control_matrix, atol=1e-12) self.assertArrayAlmostEqual(reordered_pulse._filter_function, remapped_pulse._filter_function, atol=1e-12) # Test the eigenvalues and -vectors by the characteristic equation self.assertCorrectDiagonalization(remapped_pulse, atol=1e-14)