def test_4_spins(): # fmt: off matrix = np.array([[1, 0, 0, 0], [0, -1, 2, 0], [0, 2, -1, 0], [0, 0, 0, 1]]) # fmt: on number_spins = 4 edges = [(i, (i + 1) % number_spins) for i in range(number_spins)] basis = ls.SpinBasis(ls.Group([]), number_spins=4, hamming_weight=2) basis.build() assert basis.number_states == 6 operator = ls.Operator(basis, [ls.Interaction(matrix, edges)]) assert np.isclose(ls.diagonalize(operator, k=1)[0], -8) basis = ls.SpinBasis(ls.Group([]), number_spins=4, hamming_weight=2, spin_inversion=1) basis.build() assert basis.number_states == 3 operator = ls.Operator(basis, [ls.Interaction(matrix, edges)]) assert np.isclose(ls.diagonalize(operator, k=1)[0], -8) T = ls.Symmetry([1, 2, 3, 0], sector=0) basis = ls.SpinBasis(ls.Group([T]), number_spins=4, hamming_weight=2, spin_inversion=1) basis.build() assert basis.number_states == 2 operator = ls.Operator(basis, [ls.Interaction(matrix, edges)]) assert np.isclose(ls.diagonalize(operator, k=1)[0], -8)
def test_non_hermitian_matvec(): basis = ls.SpinBasis(ls.Group([]), number_spins=2) basis.build() rng = np.random.default_rng() matrix = rng.random((4, 4)) + rng.random((4, 4)) * 1j - (0.5 + 0.5j) operator = ls.Operator(basis, [ls.Interaction(matrix, [(0, 1)])]) # print(operator.to_csr().toarray()) # print(matrix[[0, 2, 1, 3], :][:, [0, 2, 1, 3]]) assert np.all( operator.to_csr().toarray() == matrix[[0, 2, 1, 3], :][:, [0, 2, 1, 3]]) for (i, spin) in enumerate(basis.states): v = np.zeros(basis.number_states, dtype=np.complex128) v[i] = 1.0 predicted = operator(v) expected = matrix[[0, 2, 1, 3], :][:, [0, 2, 1, 3]] @ v # print(predicted, expected) assert np.allclose(predicted, expected) v = rng.random(4) + rng.random(4) * 1j - (0.5 + 0.5j) predicted = operator(v) expected = matrix[[0, 2, 1, 3], :][:, [0, 2, 1, 3]] @ v # print(predicted) # print(expected) assert np.allclose(predicted, expected)
def make_operator(L_x, L_y, basis): assert L_x > 0 and L_y > 0 sites = np.arange(L_y * L_x, dtype=np.int32).reshape(L_y, L_x) def generate_nearest_neighbours(): for y in range(L_y): for x in range(L_x): if L_x > 1: yield (sites[y, x], sites[y, (x + 1) % L_x]) if L_y > 1: yield (sites[y, x], sites[(y + 1) % L_y, x]) def generate_next_nearest_neighbours(): if L_x == 1 or L_y == 1: return for y in range(L_y): for x in range(L_x): yield (sites[y, x], sites[(y + 1) % L_y, (x + L_x - 1) % L_x]) yield (sites[y, x], sites[(y + 1) % L_y, (x + 1) % L_x]) edges = list(generate_nearest_neighbours()) matrix = np.array( [[1, 0, 0, 0], [0, -1, 2, 0], [0, 2, -1, 0], [0, 0, 0, 1]], dtype=np.complex128 ) operator = ls.Operator(basis, [ls.Interaction(matrix, edges)]) return operator
def _ls_make_heisenberg(basis, nearest, next_nearest=None, j2=None, dtype=None): matrix = [[1, 0, 0, 0], [0, -1, 2, 0], [0, 2, -1, 0], [0, 0, 0, 1]] interactions = [ls.Interaction(matrix, nearest)] if next_nearest is not None: assert j2 is not None interactions.append(ls.Interaction(j2 * matrix, next_nearest)) return ls.Operator(basis, interactions)
def test_cast_to_basis(): T = ls.Symmetry([1, 2, 3, 4, 5, 6, 7, 8, 9, 0], sector=5) P = ls.Symmetry([9, 8, 7, 6, 5, 4, 3, 2, 1, 0], sector=1) basis1 = ls.SpinBasis(ls.Group([T]), number_spins=10, hamming_weight=5, spin_inversion=-1) basis1.build() matrix = np.array([[1, 0, 0, 0], [0, -1, 2, 0], [0, 2, -1, 0], [0, 0, 0, 1]]) edges = [(i, (i + 1) % basis1.number_spins) for i in range(basis1.number_spins)] operator1 = ls.Operator(basis1, [ls.Interaction(matrix, edges)]) E1, x1 = ls.diagonalize(operator1) x1 = x1.squeeze() basis2 = ls.SpinBasis(ls.Group([P]), number_spins=10, hamming_weight=5) basis2.build() operator2 = ls.Operator(basis2, [ls.Interaction(matrix, edges)]) E2, x2 = ls.diagonalize(operator2) x2 = x2.squeeze() assert np.isclose(E1, E2) y = reference_cast_to_basis(basis1, basis2, x2) y2 = cast_to_basis(basis1, basis2, x2) assert np.allclose(y, y2) assert np.isclose(np.abs(np.dot(x1, y)), 1.0)
def main(): number_spins = 10 # System size hamming_weight = number_spins // 2 # Hamming weight (i.e. number of spin ups) # Constructing symmetries symmetries = [] sites = np.arange(number_spins) # Momentum in x direction with eigenvalue π T = (sites + 1) % number_spins symmetries.append(ls.Symmetry(T, sector=number_spins // 2)) # Parity with eigenvalue π P = sites[::-1] symmetries.append(ls.Symmetry(P, sector=1)) # Constructing the group symmetry_group = ls.Group(symmetries) print("Symmetry group contains {} elements".format(len(symmetry_group))) # Constructing the basis basis = ls.SpinBasis( symmetry_group, number_spins=number_spins, hamming_weight=hamming_weight, spin_inversion=-1 ) basis.build() # Build the list of representatives, we need it since we're doing ED print("Hilbert space dimension is {}".format(basis.number_states)) # Heisenberg Hamiltonian # fmt: off σ_x = np.array([ [0, 1] , [1, 0] ]) σ_y = np.array([ [0 , -1j] , [1j, 0] ]) σ_z = np.array([ [1, 0] , [0, -1] ]) # fmt: on σ_p = σ_x + 1j * σ_y σ_m = σ_x - 1j * σ_y matrix = 0.5 * (np.kron(σ_p, σ_m) + np.kron(σ_m, σ_p)) + np.kron(σ_z, σ_z) edges = [(i, (i + 1) % number_spins) for i in range(number_spins)] hamiltonian = ls.Operator(basis, [ls.Interaction(matrix, edges)]) # Diagonalize the Hamiltonian using ARPACK eigenvalues, eigenstates = ls.diagonalize(hamiltonian, k=1) print("Ground state energy is {:.10f}".format(eigenvalues[0])) assert np.isclose(eigenvalues[0], -18.06178542)
def test_apply(): basis = ls.SpinBasis(ls.Group([]), number_spins=10, hamming_weight=5) basis.build() # fmt: off matrix = np.array([[1, 0, 0, 0], [0, -1, 2, 0], [0, 2, -1, 0], [0, 0, 0, 1]]) # fmt: on edges = [(i, (i + 1) % basis.number_spins) for i in range(basis.number_spins)] operator = ls.Operator(basis, [ls.Interaction(matrix, edges)]) for (i, spin) in enumerate(basis.states): spins, coeffs = operator.apply(spin) v = np.zeros(basis.number_states, dtype=np.float64) v[i] = 1.0 v = operator(v) for (s, c) in zip(spins, coeffs): assert v[basis.index(s[0])] == c
def test_batched_apply(): basis = ls.SpinBasis(ls.Group([]), number_spins=10, hamming_weight=5) basis.build() # fmt: off matrix = np.array([[1, 0, 0, 0], [0, -1, 2, 0], [0, 2, -1, 0], [0, 0, 0, 1]]) # fmt: on edges = [(i, (i + 1) % basis.number_spins) for i in range(basis.number_spins)] operator = ls.Operator(basis, [ls.Interaction(matrix, edges)]) for batch_size in [1, 2, 10, 20, 50]: x = basis.states[11:11 + batch_size] # just a random range spins, coeffs, counts = operator.batched_apply(x) assert len(counts) == x.shape[0] offset = 0 for i in range(batch_size): expected_spins, expected_coeffs = operator.apply(x[i]) assert np.all(spins[offset:offset + counts[i]] == expected_spins) assert np.all(coeffs[offset:offset + counts[i]] == expected_coeffs) offset += counts[i] assert offset == spins.shape[0] assert offset == coeffs.shape[0]
def notest_construction(): symmetries = [ # ls.Symmetry([18, 19, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17], sector=5), # ls.Symmetry([19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0], sector=0) ] basis = ls.SpinBasis(ls.Group(symmetries), number_spins=20, hamming_weight=10, spin_inversion=None) basis.build() # fmt: off interactions = [ ls.Interaction([[0.25, 0, 0, 0], [0, -0.25, 0.5, 0], [0, 0.5, -0.25, 0.], [0., 0., 0., 0.25]], [[0, 1], [2, 3], [4, 5], [6, 7], [8, 9], [10, 11], [12, 13], [14, 15], [16, 17], [18, 19]]), ls.Interaction( [[0.25, 0., 0., 0.], [0., -0.25, 0.5, 0.], [0., 0.5, -0.25, 0.], [0., 0., 0., 0.25]], [[0, 2], [1, 3], [2, 4], [3, 5], [4, 6], [5, 7], [6, 8], [7, 9], [8, 10], [9, 11], [10, 12], [11, 13], [12, 14], [13, 15], [14, 16], [15, 17], [16, 18], [17, 19], [18, 0], [19, 1]]), ls.Interaction( [[-0.0625, -0., -0., -0.], [-0., 0.0625, -0.125, -0.], [-0., -0.125, 0.0625, -0.], [-0., -0., -0., -0.0625]], [[0, 4], [1, 5], [2, 6], [3, 7], [4, 8], [5, 9], [6, 10], [7, 11], [8, 12], [9, 13], [10, 14], [11, 15], [12, 16], [13, 17], [14, 18], [15, 19], [16, 0], [17, 1], [18, 2], [19, 3]]), ls.Interaction( [[0.02777778, 0., 0., 0.], [0., -0.02777778, 0.05555556, 0.], [0., 0.05555556, -0.02777778, 0.], [0., 0., 0., 0.02777778]], [[0, 6], [1, 7], [2, 8], [3, 9], [4, 10], [5, 11], [6, 12], [7, 13], [8, 14], [9, 15], [10, 16], [11, 17], [12, 18], [13, 19], [14, 0], [15, 1], [16, 2], [17, 3], [18, 4], [19, 5]]), ls.Interaction( [[-0.015625, -0., -0., -0.], [-0., 0.015625, -0.03125, -0.], [-0., -0.03125, 0.015625, -0.], [-0., -0., -0., -0.015625]], [[0, 8], [1, 9], [2, 10], [3, 11], [4, 12], [5, 13], [6, 14], [7, 15], [8, 16], [9, 17], [10, 18], [11, 19], [12, 0], [13, 1], [14, 2], [15, 3], [16, 4], [17, 5], [18, 6], [19, 7]]), ls.Interaction( [[0.01, 0., 0., 0.], [0., -0.01, 0.02, 0.], [0., 0.02, -0.01, 0.], [0., 0., 0., 0.01]], [[0, 10], [1, 11], [2, 12], [3, 13], [4, 14], [5, 15], [6, 16], [7, 17], [8, 18], [9, 19], [10, 0], [11, 1], [12, 2], [13, 3], [14, 4], [15, 5], [16, 6], [17, 7], [18, 8], [19, 9]]), ls.Interaction( [[-0.00694444, -0., -0., -0.], [-0., 0.00694444, -0.01388889, -0.], [-0., -0.01388889, 0.00694444, -0.], [-0., -0., -0., -0.00694444] ], [[0, 12], [1, 13], [2, 14], [3, 15], [4, 16], [5, 17], [6, 18], [7, 19], [8, 0], [9, 1], [10, 2], [11, 3], [12, 4], [13, 5], [14, 6], [15, 7], [16, 8], [17, 9], [18, 10], [19, 11]]), ls.Interaction( [[0.00510204, 0., 0., 0.], [0., -0.00510204, 0.01020408, 0.], [0., 0.01020408, -0.00510204, 0.], [0., 0., 0., 0.00510204]], [[0, 14], [1, 15], [2, 16], [3, 17], [4, 18], [5, 19], [6, 0], [7, 1], [8, 2], [9, 3], [10, 4], [11, 5], [12, 6], [13, 7], [14, 8], [15, 9], [16, 10], [17, 11], [18, 12], [19, 13]]), ls.Interaction( [[-0.00390625, -0., -0., -0.], [-0., 0.00390625, -0.0078125, -0.], [-0., -0.0078125, 0.00390625, -0.], [-0., -0., -0., -0.00390625]], [[0, 16], [1, 17], [2, 18], [3, 19], [4, 0], [5, 1], [6, 2], [7, 3], [8, 4], [9, 5], [10, 6], [11, 7], [12, 8], [13, 9], [14, 10], [15, 11], [16, 12], [17, 13], [18, 14], [19, 15]]), ls.Interaction( [[0.00308642, 0., 0., 0.], [0., -0.00308642, 0.00617284, 0.], [0., 0.00617284, -0.00308642, 0.], [0., 0., 0., 0.00308642]], [[0, 18], [1, 19], [2, 0], [3, 1], [4, 2], [5, 3], [6, 4], [7, 5], [8, 6], [9, 7], [10, 8], [11, 9], [12, 10], [13, 11], [14, 12], [15, 13], [16, 14], [17, 15], [18, 16], [19, 17]]) ] # fmt: on operator = ls.Operator(basis, interactions) e, _ = ls.diagonalize(operator, k=5) print(e)