Module BitStringAddresses.jl

This module contains the implementations of BitString and various Fock addresses. The addresses serve as a basis for a Hamiltonian.

While there are not restrictions on the type of address a Hamiltonian uses, Rimu provides implementations for Bosonic, Fermionic, and mixed Fock States.

When implementing a new address type, care must be taken to make them space-efficient and stack-allocated - avoid using arrays to represent your addresses at all costs!

Fock addresses

Rimu provides a variety of address implementations (see below) that should make it straightforward to implement efficient Hamiltonians.

Currently, only single-particle operators are implemented directly (via move_particle). To implement multi-particle operators, convert the address to the onr representation and back. See the implementation of HubbardMom1D for an example.

Fock address API

Rimu.BitStringAddresses.BoseFSType
BoseFS{N,M,S} <: SingleComponentFockAddress

Address type that represents a Fock state of N spinless bosons in M modes by wrapping a bitstring of type S <: BitString.

Constructors

  • BoseFS{N,M}(bs::BitString): Unsafe constructor. Does not check whether the number of particles in bs is equal to N.

  • BoseFS(::BitString): Automatically determine N and M. This constructor is not type stable!

  • BoseFS{[N,M,S]}(onr): Create BoseFS{N,M} from onr representation. This is efficient as long as at least N is provided.

See also: SingleComponentFockAddress, FermiFS, BitString.

source
Rimu.BitStringAddresses.FermiFSType
FermiFS{N,M,S} <: SingleComponentFockAddress

Address type that represents a Fock state of N fermions of the same spin in M modes by wrapping a bitstring of type S <: BitString.

Constructors

  • FermiFS{N,M}(bs::BitString): Unsafe constructor. Does not check whether the number of particles in bs is equal to N.

  • FermiFS(::BitString): Automatically determine N and M. This constructor is not type stable!

  • FermiFS{[N,M,S]}(onr): Create FermiFS{N,M} from onr representation. This is efficient as long as at least N is provided.

See also: SingleComponentFockAddress, BoseFS, BitString.

source
Rimu.BitStringAddresses.BoseFS2CType
BoseFS2C{NA,NB,M,AA,AB} <: AbstractFockAddress

Address type that constructed with two BoseFS{N,M,S}. It represents a Fock state with two components, e.g. two different species of bosons with particle number NA from species S and particle number NB from species B. The number of modes M is expected to be the same for both components.

source
Rimu.BitStringAddresses.onrFunction
onr(bs)

Compute and return the occupation number representation of the bit string address bs as an SVector{M,Int32}, where M is the number of modes.

source
onr(add::AbstractFockAddress, geom::LatticeGeometry)

Returns the occupation number representation of a Fock state address as an SArray with the shape of the lattice geometry geom. For composite addresses, a tuple of onrs is returned.

source
Rimu.BitStringAddresses.near_uniformFunction
near_uniform(BoseFS{N,M})
near_uniform(BoseFS{N,M,S}) -> bfs::BoseFS{N,M,S}

Create bosonic Fock state with near uniform occupation number of M modes with a total of N particles. Specifying the bit address type S is optional.

Examples

julia> near_uniform(BoseFS{7,5,BitString{14}})
BoseFS{7,5}((2, 2, 1, 1, 1))

julia> near_uniform(BoseFS{7,5})
BoseFS{7,5}((2, 2, 1, 1, 1))
source
Rimu.BitStringAddresses.occupied_modesFunction
occupied_modes(::SingleComponentFockAddress)

Iterate over all occupied modes in an address. Iterates BoseFSIndex for BoseFS, and an integers for FermiFS.

Example

julia> b = BoseFS((1,5,0,4));

julia> foreach(println, occupied_modes(b))
[1, 1, 0]
[5, 2, 2]
[4, 4, 9]
julia> f = FermiFS((1,1,0,1,0,0,1));

julia> foreach(println, occupied_modes(f))
1
2
4
7
source
Rimu.BitStringAddresses.num_occupied_modesFunction
num_occupied_modes(::SingleComponentFockAddress)

Get the number of occupied modes in address. Equivalent to length(occupied_modes(address)), or the number of non-zeros in its ONR representation.

Example

julia> num_occupied_modes(BoseFS((1, 0, 2)))
2
julia> num_occupied_modes(FermiFS((1, 1, 1, 0)))
3
source
Rimu.BitStringAddresses.find_occupied_modeFunction
find_occupied_mode(::SingleComponentFockAddress, k)

Find the k-th occupied mode in address. Returns BoseFSIndex for BoseFS, and an integer for FermiFS. When unsuccessful it returns zero.

Example

julia> find_occupied_mode(BoseFS((1, 0, 2)), 2)
3-element Rimu.BitStringAddresses.BoseFSIndex with indices SOneTo(3):
 2
 3
 3

julia> find_occupied_mode(FermiFS((1, 1, 1, 0)), 2)
2
source
Rimu.BitStringAddresses.find_modeFunction
find_mode(::SingleComponentFockAddress, i)

Find the i-th mode in address. Returns BoseFSIndex for BoseFS, and an integer index for FermiFS. Does not check bounds.

julia> find_mode(BoseFS((1, 0, 2)), 2)
3-element Rimu.BitStringAddresses.BoseFSIndex with indices SOneTo(3):
 0
 2
 2

julia> find_mode(FermiFS((1, 1, 1, 0)), 2)
2
source
Rimu.BitStringAddresses.move_particleFunction
move_particle(add::SingleComponentFockAddress, i, j) -> nadd, α

Move particle from mode i to mode j. Returns the new Fock state address nadd and amplitude α. Equivalent to

\[a^{\dagger}_i a_j |\mathrm{add}\rangle \to α|\mathrm{nadd}\rangle\]

Note that the modes in BoseFS are indexed by BoseFSIndex, while the ones in FermiFS are indexed by integers (see example below). For illegal moves where α == 0 the value of nadd is undefined.

Example

julia> b = BoseFS((1, 1, 3, 0))
BoseFS{5,4}((1, 1, 3, 0))

julia> i = find_occupied_mode(b, 2)
3-element Rimu.BitStringAddresses.BoseFSIndex with indices SOneTo(3):
 1
 2
 2

julia> j = find_mode(b, i.mode + 1)
3-element Rimu.BitStringAddresses.BoseFSIndex with indices SOneTo(3):
 3
 3
 4

julia> move_particle(b, i, j)
(BoseFS{5,4}((1, 0, 4, 0)), 2.0)

julia> move_particle(b, j, j)
(BoseFS{5,4}((1, 1, 3, 0)), 3.0)
julia> f = FermiFS((1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0))
FermiFS{7,12}((1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0))

julia> i = find_occupied_mode(f, 2)
6

julia> move_particle(f, i, i + 1)
(FermiFS{7,12}((1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0)), 0.0)

julia> move_particle(f, i, i - 1)
(FermiFS{7,12}((1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0)), 1.0)

julia> move_particle(f, i, 12)
(FermiFS{7,12}((1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1)), -1.0)
source

BitStrings

The atomic addresses, BoseFS and FermiFS, are implemented as bitstrings. Using this approach over an occupation number representation makes the addresses much more space-efficient. The API for BitStrings is as follows.

BitString API

Rimu.BitStringAddresses.BitStringType
BitString{B,N,T<:Unsigned}

Type for storing bitstrings of static size. Holds B bits in N chunks, where each chunk is of type T.

N is chosen automatically to accommodate B bits as efficiently as possible.

Constructors

  • BitString{B,N,T}(::SVector{N,T}): unsafe constructor. Does not check for ghost bits.

  • BitString{B,N,T}(i::T): as above, but sets i as the rightmost chunk.

  • BitString{B}(::Integer): Convert integer to BitString. Integer is truncated to the correct number of bits.

source
Rimu.BitStringAddresses.num_chunksFunction
num_chunks(::Val{B})

Determine the number and type of chunks needed to store B bits.

source
num_chunks(::Type{<:BitString})
num_chunks(s::BitString)

Number of chunks in bitstring. Equivalent to length(chunks(s)).

source