Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#===============================================================================
rep_integer.jl - LR, Jan 2021
Representation of states is done via an Integer.
===============================================================================#
const SpinState = UInt64 # That's a single species state.
const FullState = UInt128 # That's the full state describing the entire system.
# That's the shift which is applied to fuse the two spins to a full state.
const _bshift = 2^60
function f_to_s(fs::FullState)::Tuple{SpinState,SpinState}
""" Takes a state that represents the full state in the Hilbert space
and maps it to the constituent spin states.
"""
return SpinState(fs%_bshift), SpinState(fs÷_bshift)
end
function s_to_f(su::SpinState, sd::SpinState)::FullState
""" Maps two spin states to a full state.
"""
return FullState(sd)*_bshift + FullState(su)
end
function create(s::SpinState, i::Integer)::Union{Nothing,SpinState}
""" Creates a particle at position i, false if there's a particle already.
"""
shift = 1 << (i-1)
if s & shift == 0
return s ⊻ shift
else
return nothing
end
end
function annihilate(s::SpinState, i::Integer)::Union{Nothing,SpinState}
""" Destroys a particle at position i, false if there's no particle to destroy.
"""
shift = 1 << (i-1)
if s & shift > 0
return s ⊻ shift
else
return nothing
end
end
function count_occupancies(s::SpinState, src::Integer, dst::Integer)
# return sum([(s >>> k) & 1 for k=0:63]) --> slower!
c = 0
for k=src-1:dst-1
c += (s >>> k) & 1
end
return c
end
function sign(s::SpinState, src::Integer, dst::Integer)
""" This is the sum of densities between the anihilation and creation operators
(including both endpoints) which gives the entire fermionic sign factor.
The contributions from up and down states simply add.
"""
if src > dst
return (-1)^count_occupancies(s, dst, src)
end
return (-1)^count_occupancies(s, src, dst)
end
# Indexing.
function max_orbital(s::SpinState)
""" Returns the index of the maximally occupied orbital in a SpinState.
Note:
- For integers, this is essentially the bit length.
"""
# sizeof = number of bytes.
# leading_zeros = built in for leading zeros in representation.
return sizeof(s) * 8 - leading_zeros(s)
end
function Base.getindex(s::SpinState, i::Unsigned)::SpinState
""" Note: Indexing works with the lowest bits first (i.e., the ones from the
right). It doesn't matter how it is used, only the implementation here
needs to be consistent.
Only positive integers are allowed. Negatives would only give zeros.
"""
return s >>> (i-1) & 1
end
Base.getindex(s::SpinState, i::Integer)::SpinState = s[UInt(i)]
Base.firstindex(s::SpinState) = 1
Base.lastindex(s::SpinState) = max_orbital(s)
Base.length(s::SpinState) = max_orbital(s)