def test_find_connections(self): expr = [ExpressionR(), c_dag("up", 0) * c("dn", 1), c_dag("up", 0) * c("dn", 1) + c_dag("dn", 0) * c("dn", 1), c_dag("dn", 1) * c_dag("up", 1), n("up", 2) ] sp, melem = make_space_partition(self.Hop, self.hs, False) op = LOperatorR(sum(expr[1:]), self.hs) conns = sp.find_connections(op, self.hs) conns_ref = set() in_state = np.zeros((sp.dim,), dtype=float) for i in range(sp.dim): in_state[i] = 1.0 out_state = op * in_state for f, a in enumerate(out_state): if abs(a) > 1e-10: conns_ref.add((sp[i], sp[f])) in_state[i] = 0.0 self.assertEqual(conns, conns_ref) for expr1, expr2 in product(expr, expr): conns1 = sp.find_connections(LOperatorR(expr1, self.hs), self.hs) conns2 = sp.find_connections(LOperatorR(expr2, self.hs), self.hs) conns = sp.find_connections(LOperatorR(expr1 + expr2, self.hs), self.hs) self.assertEqual(conns, conns1.union(conns2))
def test_HilbertSpace(self): indices = [("dn", 0), ("dn", 1), ("up", 0), ("up", 1)] hs = HilbertSpace([make_space_fermion(*ind) for ind in indices]) for ind in indices: c_op = LOperatorR(c(*ind), hs) assert_equal(make_matrix(c_op, hs), self.c_mat(hs, *ind)) c_dag_op = LOperatorR(c_dag(*ind), hs) assert_equal(make_matrix(c_dag_op, hs), self.c_dag_mat(hs, *ind)) H1 = 1.0 * (c_dag("up", 0) * c("up", 1) + c_dag("up", 1) * c("up", 0)) H1 += 2.0 * (c_dag("dn", 0) * c("dn", 1) + c_dag("dn", 1) * c("dn", 0)) H1op = LOperatorR(H1, hs) ref1 = 1.0 * (self.c_dag_mat(hs, "up", 0) @ self.c_mat(hs, "up", 1) + self.c_dag_mat(hs, "up", 1) @ self.c_mat(hs, "up", 0)) ref1 += 2.0 * (self.c_dag_mat(hs, "dn", 0) @ self.c_mat(hs, "dn", 1) + self.c_dag_mat(hs, "dn", 1) @ self.c_mat(hs, "dn", 0)) assert_equal(make_matrix(H1op, hs), ref1) H2 = 1.0j * (c_dag("up", 0) * c("up", 1) + c_dag("up", 1) * c("up", 0)) H2 += 2.0 * (c_dag("dn", 0) * c("dn", 1) + c_dag("dn", 1) * c("dn", 0)) H2op = LOperatorC(H2, hs) ref2 = 1.0j * (self.c_dag_mat(hs, "up", 0) @ self.c_mat(hs, "up", 1) + self.c_dag_mat(hs, "up", 1) @ self.c_mat(hs, "up", 0)) ref2 += 2.0 * (self.c_dag_mat(hs, "dn", 0) @ self.c_mat(hs, "dn", 1) + self.c_dag_mat(hs, "dn", 1) @ self.c_mat(hs, "dn", 0)) assert_equal(make_matrix(H2op, hs), ref2)
def test_loperator(self): out = np.zeros((6,), dtype=float) dst = self.mapper(out) # Spin flips Hop = LOperatorR(self.Hex, self.hs) in1 = np.array([1, 1, 1, 1, 1, 1], dtype=float) src = self.mapper(in1) Hop(src, dst) assert_equal(out, np.array([0, 0, 2, 2, 0, 0], dtype=float)) in2 = np.array([1, 1, 1, -1, 1, 1], dtype=float) src = self.mapper(in2) Hop(src, dst) assert_equal(out, np.array([0, 0, -2, 2, 0, 0], dtype=float)) # Pair hops Hop = LOperatorR(self.Hp, self.hs) src = self.mapper(in1) Hop(src, dst) assert_equal(out, np.array([0, 2, 0, 0, 2, 0], dtype=float)) in2 = np.array([1, 1, 1, 1, -1, 1], dtype=float) src = self.mapper(in2) Hop(src, dst) assert_equal(out, np.array([0, -2, 0, 0, 2, 0], dtype=float))
def test_compositions(self): mapper = BasisMapper([], self.hs, 0) self.assertEqual(len(mapper), 1) self.assertEqual(mapper.map[0], 0) O_list = [LOperatorR(c_dag("dn", 1), self.hs), LOperatorR(c_dag("dn", 2), self.hs), LOperatorR(c_dag("up", 1), self.hs), LOperatorR(c_dag("up", 2), self.hs)] mapper_N0 = BasisMapper(O_list, self.hs, 0) self.assertEqual(len(mapper_N0), 1) self.assertEqual(mapper_N0.map[0], 0) mapper_N2 = BasisMapper(O_list, self.hs, 2) self.assert_equal_dicts_up_to_value_permutation(mapper_N2.map, self.mapping) O_list_complex = [LOperatorC(1j * c_dag("dn", 1), self.hs), LOperatorC(1j * c_dag("dn", 2), self.hs), LOperatorC(1j * c_dag("up", 1), self.hs), LOperatorC(1j * c_dag("up", 2), self.hs)] mapper_N2 = BasisMapper(O_list_complex, self.hs, 2) self.assert_equal_dicts_up_to_value_permutation(mapper_N2.map, self.mapping)
def test_compositions_bosons(self): hs = HilbertSpace(a_dag(1) + a_dag(2) + a_dag(3) + a_dag(4), 4) O_list = [LOperatorR(a_dag(1), hs), LOperatorR(a_dag(2), hs), LOperatorR(a_dag(3), hs), LOperatorR(a_dag(4), hs)] map_size_ref = [1, 4, 10, 20, 35, 56, 84, 120, 165, 220] for N in range(10): mapper = BasisMapper(O_list, hs, N) self.assertEqual(len(mapper), map_size_ref[N])
def test_LOperatorR(self): expr1 = 3 * c_dag("dn") expr2 = 3 * c("up") expr = 2 * expr1 - 2 * expr2 hs = HilbertSpace(expr) lop1 = LOperatorR(expr1, hs) lop2 = LOperatorR(expr2, hs) lop = LOperatorR(expr, hs) src = np.array([1, 1, 1, 1]) dst_real = np.zeros((4, ), dtype=float) dst_complex = np.zeros((4, ), dtype=complex) assert_equal(lop1 * src, np.array([0, 3, 0, 3])) lop1(src, dst_real) assert_equal(dst_real, np.array([0, 3, 0, 3])) lop1(src, dst_complex) assert_equal(dst_complex, np.array([0, 3, 0, 3], dtype=complex)) assert_equal(lop2 * src, np.array([3, -3, 0, 0])) lop2(src, dst_real) assert_equal(dst_real, np.array([3, -3, 0, 0])) lop2(src, dst_complex) assert_equal(dst_complex, np.array([3, -3, 0, 0], dtype=complex)) assert_equal(lop * src, np.array([-6, 12, 0, 6])) lop(src, dst_real) assert_equal(dst_real, np.array([-6, 12, 0, 6])) lop(src, dst_complex) assert_equal(dst_complex, np.array([-6, 12, 0, 6], dtype=complex)) src_complex = 1j * np.array([1, 1, 1, 1]) assert_equal(lop * src_complex, np.array([-6j, 12j, 0, 6j])) lop(src_complex, dst_complex) assert_equal(dst_complex, np.array([-6j, 12j, 0, 6j])) with self.assertRaisesRegex( RuntimeError, "^State vector must be a 1-dimensional array$"): lop * np.zeros((3, 3, 3)) with self.assertRaisesRegex( RuntimeError, "^Source state vector must be a 1-dimensional array$"): lop(np.zeros((3, 3, 3)), np.zeros((5, ))) with self.assertRaisesRegex( RuntimeError, "^Destination state vector must be a 1-dimensional array$"): lop(np.zeros((5, )), np.zeros((3, 3, 3)))
def test_basis_state_indices(self): indices = [("dn", 0), ("dn", 1), ("up", 0), ("up", 1)] hs = HilbertSpace([make_space_fermion(*ind) for ind in indices]) # Basis of the N=2 sector basis_state_indices = [3, 5, 6, 9, 10, 12] H1 = 1.0 * (c_dag("up", 0) * c("up", 1) + c_dag("up", 1) * c("up", 0)) H1 += 2.0 * (c_dag("dn", 0) * c("dn", 1) + c_dag("dn", 1) * c("dn", 0)) H1op = LOperatorR(H1, hs) ref1 = 1.0 * (self.c_dag_mat(hs, "up", 0) @ self.c_mat(hs, "up", 1) + self.c_dag_mat(hs, "up", 1) @ self.c_mat(hs, "up", 0)) ref1 += 2.0 * (self.c_dag_mat(hs, "dn", 0) @ self.c_mat(hs, "dn", 1) + self.c_dag_mat(hs, "dn", 1) @ self.c_mat(hs, "dn", 0)) ref1 = ref1[basis_state_indices, :][:, basis_state_indices] assert_equal(make_matrix(H1op, basis_state_indices), ref1) H2 = 1.0j * (c_dag("up", 0) * c("up", 1) + c_dag("up", 1) * c("up", 0)) H2 += 2.0 * (c_dag("dn", 0) * c("dn", 1) + c_dag("dn", 1) * c("dn", 0)) H2op = LOperatorC(H2, hs) ref2 = 1.0j * (self.c_dag_mat(hs, "up", 0) @ self.c_mat(hs, "up", 1) + self.c_dag_mat(hs, "up", 1) @ self.c_mat(hs, "up", 0)) ref2 += 2.0 * (self.c_dag_mat(hs, "dn", 0) @ self.c_mat(hs, "dn", 1) + self.c_dag_mat(hs, "dn", 1) @ self.c_mat(hs, "dn", 0)) ref2 = ref2[basis_state_indices, :][:, basis_state_indices] assert_equal(make_matrix(H2op, basis_state_indices), ref2)
def test_overload_selection(self): expr = 6 * c_dag("dn") - 6 * c("up") hs = HilbertSpace(expr) lop = LOperatorR(expr, hs) src_int = np.array([1, 1, 1, 1], dtype=int) src_real = np.array([1, 1, 1, 1], dtype=float) src_complex = np.array([1, 1, 1, 1], dtype=complex) ref_real = np.array([-6, 12, 0, 6], dtype=float) ref_complex = np.array([-6, 12, 0, 6], dtype=complex) self.assertEqual((lop * src_int).dtype, np.float64) self.assertEqual((lop * src_real).dtype, np.float64) self.assertEqual((lop * src_complex).dtype, np.complex128) dst_int = np.zeros(4, dtype=int) dst_real = np.zeros(4, dtype=float) dst_complex = np.zeros(4, dtype=complex) self.assertRaises(TypeError, lop, src_int, dst_int) self.assertRaises(TypeError, lop, src_real, dst_int) self.assertRaises(TypeError, lop, src_complex, dst_int) self.assertRaises(TypeError, lop, src_complex, dst_real) lop(src_int, dst_real) assert_equal(dst_real, ref_real) lop(src_int, dst_complex) assert_equal(dst_complex, ref_complex) lop(src_real, dst_real) assert_equal(dst_real, ref_real) lop(src_real, dst_complex) assert_equal(dst_complex, ref_complex) lop(src_complex, dst_complex) assert_equal(dst_complex, ref_complex) expr = 6j * c_dag("dn") - 6j * c("up") hs = HilbertSpace(expr) lop = LOperatorC(expr, hs) self.assertEqual((lop * src_int).dtype, np.complex128) self.assertEqual((lop * src_real).dtype, np.complex128) self.assertEqual((lop * src_complex).dtype, np.complex128) ref_complex = np.array([-6j, 12j, 0, 6j], dtype=complex) self.assertRaises(TypeError, lop, src_int, dst_int) self.assertRaises(TypeError, lop, src_real, dst_int) self.assertRaises(TypeError, lop, src_complex, dst_int) self.assertRaises(TypeError, lop, src_int, dst_real) self.assertRaises(TypeError, lop, src_real, dst_real) self.assertRaises(TypeError, lop, src_complex, dst_real) lop(src_int, dst_complex) assert_equal(dst_complex, ref_complex) lop(src_real, dst_complex) assert_equal(dst_complex, ref_complex) lop(src_complex, dst_complex) assert_equal(dst_complex, ref_complex)
def test_empty(self): expr0 = ExpressionR() hs = HilbertSpace(expr0) lop = LOperatorR(expr0, hs) sv = np.array([], dtype=float) assert_equal(lop * sv, sv) dst = np.array([], dtype=float) lop(sv, dst) assert_equal(sv, dst)
def test_merge_subspaces(self): sp, melem = make_space_partition(self.Hop, self.hs, False) Cd, C, all_ops = [], [], [] for spin in ("dn", "up"): for o in range(self.n_orbs): Cd.append(LOperatorR(c_dag(spin, o), self.hs)) C.append(LOperatorR(c(spin, o), self.hs)) all_ops.append(Cd[-1]) all_ops.append(C[-1]) sp.merge_subspaces(Cd[-1], C[-1], self.hs) # Calculated classification of states v_cl = [set() for _ in range(sp.n_subspaces)] foreach(sp, lambda i, subspace: v_cl[subspace].add(i)) cl = set(map(frozenset, v_cl)) in_state = np.zeros((sp.dim,), dtype=float) for op in all_ops: for i_sp in cl: f_sp = set() for i in i_sp: in_state[i] = 1.0 out_state = op * in_state for f, a in enumerate(out_state): if abs(a) > 1e-10: f_sp.add(f) in_state[i] = 0.0 # op maps i_sp onto zero if len(f_sp) == 0: continue # Check if op maps i_sp to only one subspace self.assertEqual( sum(int(f_sp.issubset(f_sp_ref)) for f_sp_ref in cl), 1 )
def test_left_right_basis_state_indices(self): indices = [("dn", 0), ("dn", 1), ("up", 0), ("up", 1)] hs = HilbertSpace([make_space_fermion(*ind) for ind in indices]) # Basis of the N=1 sector N1_basis_state_indices = [1, 2, 4, 8] # Basis of the N=2 sector N2_basis_state_indices = [3, 5, 6, 9, 10, 12] # Basis of the N=3 sector N3_basis_state_indices = [7, 11, 13, 14] for ind1, ind2 in product(indices, indices): op1 = LOperatorR(c(*ind1) * c(*ind2), hs) ref1 = self.c_mat(hs, *ind1) @ self.c_mat(hs, *ind2) ref1 = ref1[N1_basis_state_indices, :][:, N3_basis_state_indices] assert_equal( make_matrix(op1, N1_basis_state_indices, N3_basis_state_indices), ref1) op2 = LOperatorC(1j * c(*ind1) * c(*ind2), hs) ref2 = 1j * self.c_mat(hs, *ind1) @ self.c_mat(hs, *ind2) ref2 = ref2[N1_basis_state_indices, :][:, N3_basis_state_indices] assert_equal( make_matrix(op2, N1_basis_state_indices, N3_basis_state_indices), ref2) for ind in indices: op1 = LOperatorR(c(*ind), hs) ref1 = self.c_mat(hs, *ind) ref1 = ref1[N2_basis_state_indices, :][:, N3_basis_state_indices] assert_equal( make_matrix(op1, N2_basis_state_indices, N3_basis_state_indices), ref1) op2 = LOperatorC(1j * c(*ind), hs) ref2 = 1j * self.c_mat(hs, *ind) ref2 = ref2[N2_basis_state_indices, :][:, N3_basis_state_indices] assert_equal( make_matrix(op2, N2_basis_state_indices, N3_basis_state_indices), ref2)
def test_O_vac(self): P = c_dag("dn", 1) * c_dag("dn", 2) + \ c_dag("dn", 1) * c_dag("up", 1) + \ c_dag("dn", 2) * c_dag("up", 1) + \ c_dag("dn", 1) * c_dag("up", 2) + \ c_dag("dn", 2) * c_dag("up", 2) + \ c_dag("up", 1) * c_dag("up", 2) mapper = BasisMapper(LOperatorR(P, self.hs), self.hs) self.assertEqual(len(mapper), 6) self.assert_equal_dicts_up_to_value_permutation(mapper.map, self.mapping) mapper = BasisMapper(LOperatorC(1j * P, self.hs), self.hs) self.assertEqual(len(mapper), 6) self.assert_equal_dicts_up_to_value_permutation(mapper.map, self.mapping)
def test_strided_arrays(self): expr = 6 * c_dag("dn") - 6 * c("up") hs = HilbertSpace(expr) lop = LOperatorR(expr, hs) src_real = 999 * np.ones((10, ), dtype=float) src_real[3:10:2] = 1 src_complex = np.array(src_real, dtype=complex) assert_equal(lop * src_real[3:10:2], np.array([-6, 12, 0, 6], dtype=float)) assert_equal(lop * src_complex[3:10:2], np.array([-6, 12, 0, 6], dtype=complex)) dst_real = 777 * np.ones((10, ), dtype=float) dst_complex = np.array(dst_real, dtype=complex) ref_real = np.array([777, 777, -6, 777, 12, 777, 0, 777, 6, 777], dtype=float) ref_complex = np.array(ref_real, dtype=complex) lop(src_real[3:10:2], dst_real[2:9:2]) assert_equal(dst_real, ref_real) lop(src_real[3:10:2], dst_complex[2:9:2]) assert_equal(dst_complex, ref_complex) lop(src_complex[3:10:2], dst_complex[2:9:2]) assert_equal(dst_complex, ref_complex) expr = 6j * c_dag("dn") - 6j * c("up") hs = HilbertSpace(expr) lop = LOperatorC(expr, hs) ref_complex = np.array([777, 777, -6j, 777, 12j, 777, 0, 777, 6j, 777], dtype=complex) lop(src_real[3:10:2], dst_complex[2:9:2]) assert_equal(dst_complex, ref_complex) lop(src_complex[3:10:2], dst_complex[2:9:2]) assert_equal(dst_complex, ref_complex)
def setUpClass(cls): # Parameters of the 3 orbital Hubbard-Kanamori atom cls.n_orbs = 3 cls.mu = 0.7 cls.U = 3.0 cls.J = 0.3 indices_up = [("up", o) for o in range(cls.n_orbs)] indices_dn = [("dn", o) for o in range(cls.n_orbs)] # Hamiltonian cls.H = dispersion(-cls.mu * np.ones(cls.n_orbs), indices=indices_up) cls.H += dispersion(-cls.mu * np.ones(cls.n_orbs), indices=indices_dn) cls.H += kanamori_int(cls.n_orbs, cls.U, cls.J, indices_up=indices_up, indices_dn=indices_dn) # Hilbert space cls.hs = HilbertSpace(cls.H) # Linear operator form of the Hamiltonian cls.Hop = LOperatorR(cls.H, cls.hs)
H = jaynes_cummings(eps, omega, g) # Construct state space of our problem as a direct product of two # two-dimensional Hilbert spaces (qubits) and one truncated bosonic Hilbert # space. # make_space_boson(4) returns the truncated bosonic space with allowed # occupation numbers N = 0, 1, ..., (2^4-1). hs = HilbertSpace([ make_space_spin(1 / 2, 0), # Qubit 1: spin-1/2, index 0 make_space_spin(1 / 2, 1), # Qubit 2: spin-1/2, index 1 make_space_boson(4, 0) # Oscillator, index 0 ]) # Construct a linear operator corresponding to 'H' and acting in the Hilbert # space 'hs'. H_op = LOperatorR(H, hs) # # Prepare a matrix representation of 'H_op' # # Method I (manual). H_mat1 = np.zeros((hs.dim, hs.dim)) for i in range(hs.dim): # A column vector psi = {0, 0, ..., 1, ..., 0} psi = np.zeros(hs.dim) psi[i] = 1.0 # Act with H_op on psi and store the result the i-th column of H_mat H_mat1[:, i] = H_op * psi # Method II (automatic and faster).