Quantum scars Hamiltonian: spin-1/2 system with Hilbert space constraint

This example makes use of the user_basis class to define the Hamiltonian

\[H = \sum_j P_{j-1} \sigma^x_j P_{j+1}, \qquad P_j = |\downarrow_j\rangle\langle\downarrow_j|\]

The projector operators \(P_j\) are built in the definition of the basis for the constrained Hibert space.

Please consult this post – user_basis tutorial – for more detailed explanations on using the user_basis class.

Script

download script

  1#
  2import sys, os
  3
  4os.environ["KMP_DUPLICATE_LIB_OK"] = (
  5    "True"  # uncomment this line if omp error occurs on OSX for python 3
  6)
  7os.environ["OMP_NUM_THREADS"] = "1"  # set number of OpenMP threads to run in parallel
  8os.environ["MKL_NUM_THREADS"] = "1"  # set number of MKL threads to run in parallel
  9#
 10
 11###########################################################################
 12#                            example 14                                   #
 13#  In this script we demonstrate how to use the user_basis to construct   #
 14#  a spin-1/2 Hamiltonian on a restricted Hilbert space where a spin-up   #
 15#  on a given lattice site must be preceded and succeeded by a spin-down. #
 16###########################################################################
 17from quspin.operators import hamiltonian
 18from quspin.basis import spin_basis_1d  # Hilbert space spin basis_1d
 19from quspin.basis.user import user_basis  # Hilbert space user basis
 20from quspin.basis.user import (
 21    pre_check_state_sig_32,
 22    op_sig_32,
 23    map_sig_32,
 24)  # user basis data types
 25from numba import carray, cfunc  # numba helper functions
 26from numba import uint32, int32  # numba data types
 27import numpy as np
 28
 29#
 30N = 10  # total number of lattice sites
 31
 32
 33#
 34######  function to call when applying operators
 35@cfunc(op_sig_32, locals=dict(s=int32, b=uint32))
 36def op(op_struct_ptr, op_str, ind, N, args):
 37    # using struct pointer to pass op_struct_ptr back to C++ see numba Records
 38    op_struct = carray(op_struct_ptr, 1)[0]
 39    err = 0
 40    ind = N - ind - 1  # convention for QuSpin for mapping from bits to sites.
 41    s = (((op_struct.state >> ind) & 1) << 1) - 1
 42    b = 1 << ind
 43    #
 44    if op_str == 120:  # "x" is integer value 120 (check with ord("x"))
 45        op_struct.state ^= b
 46    elif op_str == 121:  # "y" is integer value 120 (check with ord("y"))
 47        op_struct.state ^= b
 48        op_struct.matrix_ele *= 1.0j * s
 49    elif op_str == 122:  # "z" is integer value 120 (check with ord("z"))
 50        op_struct.matrix_ele *= s
 51    else:
 52        op_struct.matrix_ele = 0
 53        err = -1
 54    #
 55    return err
 56
 57
 58#
 59op_args = np.array([], dtype=np.uint32)
 60
 61
 62#
 63######  function to filter states/project states out of the basis
 64#
 65@cfunc(
 66    pre_check_state_sig_32,
 67    locals=dict(s_shift_left=uint32, s_shift_right=uint32),
 68)
 69def pre_check_state(s, N, args):
 70    """imposes that that a bit with 1 must be preceded and followed by 0,
 71    i.e. a particle on a given site must have empty neighboring sites.
 72    #
 73    Works only for lattices of up to N=32 sites (otherwise, change mask)
 74    #
 75    """
 76    mask = 0xFFFFFFFF >> (32 - N)  # works for lattices of up to 32 sites
 77    # cycle bits left by 1 periodically
 78    s_shift_left = ((s << 1) & mask) | ((s >> (N - 1)) & mask)
 79    #
 80    # cycle bits right by 1 periodically
 81    s_shift_right = ((s >> 1) & mask) | ((s << (N - 1)) & mask)
 82    #
 83    return (((s_shift_right | s_shift_left) & s)) == 0
 84
 85
 86#
 87pre_check_state_args = None
 88#
 89######  construct user_basis
 90# define maps dict
 91maps = dict()  # no symmetries to apply.
 92# define op_dict
 93op_dict = dict(op=op, op_args=op_args)
 94# define pre_check_state
 95pre_check_state = (
 96    pre_check_state,
 97    pre_check_state_args,
 98)  # None gives a null pointer to args
 99# create user basis
100basis = user_basis(
101    np.uint32,
102    N,
103    op_dict,
104    allowed_ops=set("xyz"),
105    sps=2,
106    pre_check_state=pre_check_state,
107    Ns_block_est=300000,
108    **maps,
109)
110# print basis
111print(basis)
112#
113###### construct Hamiltonian
114# site-coupling lists
115h_list = [[1.0, i] for i in range(N)]
116# operator string lists
117static = [
118    ["x", h_list],
119]
120# compute Hamiltonian, no checks have been implemented
121no_checks = dict(check_symm=False, check_pcon=False, check_herm=False)
122H = hamiltonian(static, [], basis=basis, dtype=np.float64, **no_checks)