Module BitStringAddresses

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 (heap-allocated) arrays to represent your addresses at all costs!

Fock addresses

Rimu provides a variety of address implementations that should make it straightforward to implement efficient Hamiltonians. Examples are:

  • BoseFS Single-component bosonic Fock state with fixed particle and mode number.
  • FermiFS Single-component fermionic Fock state with fixed particle and mode number.
  • CompositeFS Multi-component Fock state composed of the above types.
  • OccupationNumberFS Single-component bosonic Fock state with a fixed number of modes. The number of particles is not part of the type and can be changed by operators.

Fock address API

Rimu.BitStringAddresses.BoseFSIndexType
BoseFSIndex

Struct used for indexing and performing excitations on a BoseFS.

Fields:

  • occnum: the occupation number.
  • mode: the index of the mode.
  • offset: the position of the mode in the address. This is the bit offset of the mode when

the address is represented by a bitstring, and the position in the list when it is represented by SortedParticleList.

source
Rimu.BitStringAddresses.FermiFSIndexType
FermiFSIndex

Struct used for indexing and performing excitations on a FermiFS.

Fields:

  • occnum: the occupation number.
  • mode: the index of the mode.
  • offset: the position of the mode in the address. This is mode - 1 when the address is represented by a bitstring, and the position in the list when using SortedParticleList.
source
Rimu.BitStringAddresses.OccupiedModeMapType
OccupiedModeMap(addr) <: AbstractVector

Get a map of occupied modes in address as an AbstractVector of indices compatible with excitation - BoseFSIndex or FermiFSIndex.

OccupiedModeMap(addr)[i] contains the index for the i-th occupied mode. This is useful because repeatedly looking for occupied modes with find_occupied_mode can be time-consuming. OccupiedModeMap(addr) is an eager version of the iterator returned by occupied_modes. It is similar to onr but contains more information.

Example

julia> b = BoseFS(10, 0, 0, 0, 2, 0, 1)
BoseFS{13,7}(10, 0, 0, 0, 2, 0, 1)

julia> mb = OccupiedModeMap(b)
3-element OccupiedModeMap{7, BoseFSIndex}:
 BoseFSIndex(occnum=10, mode=1, offset=0)
 BoseFSIndex(occnum=2, mode=5, offset=14)
 BoseFSIndex(occnum=1, mode=7, offset=18)

julia> f = FermiFS(1,1,1,1,0,0,1,0,0)
FermiFS{5,9}(1, 1, 1, 1, 0, 0, 1, 0, 0)

julia> mf = OccupiedModeMap(f)
5-element OccupiedModeMap{5, FermiFSIndex}:
 FermiFSIndex(occnum=1, mode=1, offset=0)
 FermiFSIndex(occnum=1, mode=2, offset=1)
 FermiFSIndex(occnum=1, mode=3, offset=2)
 FermiFSIndex(occnum=1, mode=4, offset=3)
 FermiFSIndex(occnum=1, mode=7, offset=6)

julia> mf == collect(occupied_modes(f))
true

julia> dot(mf, mb)
11

julia> dot(mf, 1:20)
17

See also dot, SingleComponentFockAddress.

source
Rimu.BitStringAddresses.OccupiedPairsMapType
OccupiedPairsMap(addr::SingleComponentFockAddress) <: AbstractVector

Get a map of all distinct pairs of indices in addr. Pairs involving multiply-occupied modes are counted once, (including self-pairing). This is useful for cases where identifying pairs of particles for eg. interactions is not well-defined or efficient to do on the fly. This is an eager iterator whose elements are a tuple of particle indices that can be given to excitation

Example

julia> addr = BoseFS(10, 0, 0, 0, 2, 0, 1)
BoseFS{13,7}(10, 0, 0, 0, 2, 0, 1)

julia> pairs = OccupiedPairsMap(addr)
5-element OccupiedPairsMap{78, Tuple{BoseFSIndex, BoseFSIndex}}:
 (BoseFSIndex(occnum=10, mode=1, offset=0), BoseFSIndex(occnum=10, mode=1, offset=0))
 (BoseFSIndex(occnum=2, mode=5, offset=14), BoseFSIndex(occnum=2, mode=5, offset=14))
 (BoseFSIndex(occnum=2, mode=5, offset=14), BoseFSIndex(occnum=10, mode=1, offset=0))
 (BoseFSIndex(occnum=1, mode=7, offset=18), BoseFSIndex(occnum=10, mode=1, offset=0))
 (BoseFSIndex(occnum=1, mode=7, offset=18), BoseFSIndex(occnum=2, mode=5, offset=14))

julia> excitation(addr, pairs[2], pairs[4])
(BoseFS{13,7}(9, 0, 0, 0, 4, 0, 0), 10.954451150103322)

See also OccupiedModeMap.

source
Rimu.BitStringAddresses.SingleComponentFockAddressType
SingleComponentFockAddress{N,M} <: AbstractFockAddress{N,M}

A type representing a single component Fock state with N particles and M modes.

Implemented subtypes: BoseFS, FermiFS.

Supported functionality

See also CompositeFS, AbstractFockAddress.

source
Rimu.BitStringAddresses.excitationFunction
excitation(addr::SingleComponentFockAddress, creations::NTuple, destructions::NTuple)

Generate an excitation on address addr by applying creations and destructions, which are tuples of the appropriate address indices (i.e. BoseFSIndex for bosons, or FermiFSIndex for fermions).

\[a^†_{c_1} a^†_{c_2} \ldots a_{d_1} a_{d_2} \ldots |\mathrm{addr}\rangle \to α|\mathrm{naddr}\rangle\]

Returns the new address naddr and the factor α. The value of α is given by the square root of the product of mode occupations before destruction and after creation. If the excitation is illegal, returns an arbitrary address and the value 0.0.

Example

julia> f = FermiFS(1,1,0,0,1,1,1,1)
FermiFS{6,8}(1, 1, 0, 0, 1, 1, 1, 1)

julia> i, j, k, l = find_mode(f, (3,4,2,5))
(FermiFSIndex(occnum=0, mode=3, offset=2), FermiFSIndex(occnum=0, mode=4, offset=3), FermiFSIndex(occnum=1, mode=2, offset=1), FermiFSIndex(occnum=1, mode=5, offset=4))

julia> excitation(f, (i,j), (k,l))
(FermiFS{6,8}(1, 0, 1, 1, 0, 1, 1, 1), -1.0)

See SingleComponentFockAddress.

source
Rimu.BitStringAddresses.find_occupied_modeFunction
find_occupied_mode(::SingleComponentFockAddress, k)
find_occupied_mode(::BoseFS, k, [n])

Find the k-th occupied mode in address (with at least n particles). Returns BoseFSIndex for BoseFS, and FermiFSIndex for FermiFS. When unsuccessful it returns a zero index.

Example

julia> find_occupied_mode(FermiFS(1, 1, 1, 0), 2)
FermiFSIndex(occnum=1, mode=2, offset=1)

julia> find_occupied_mode(BoseFS(1, 0, 2), 1)
BoseFSIndex(occnum=1, mode=1, offset=0)

julia> find_occupied_mode(BoseFS(1, 0, 2), 1, 2)
BoseFSIndex(occnum=2, mode=3, offset=3)

See also occupied_modes, OccupiedModeMap, SingleComponentFockAddress.

source
Rimu.BitStringAddresses.occupied_modesFunction
occupied_modes(::SingleComponentFockAddress)

Return a lazy iterator over all occupied modes in an address. Iterates over BoseFSIndexs for BoseFS, and over FermiFSIndexs for FermiFS. See OccupiedModeMap for an eager version.

Example

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

julia> foreach(println, occupied_modes(b))
BoseFSIndex(occnum=1, mode=1, offset=0)
BoseFSIndex(occnum=5, mode=2, offset=2)
BoseFSIndex(occnum=4, mode=4, offset=9)
julia> f = FermiFS((1,1,0,1,0,0,1));

julia> foreach(println, occupied_modes(f))
FermiFSIndex(occnum=1, mode=1, offset=0)
FermiFSIndex(occnum=1, mode=2, offset=1)
FermiFSIndex(occnum=1, mode=4, offset=3)
FermiFSIndex(occnum=1, mode=7, offset=6)

See also find_occupied_mode, SingleComponentFockAddress.

source
Rimu.BitStringAddresses.onrFunction
occupation_number_representation(fs::SingleComponentFockAddress)
onr(fs::SingleComponentFockAddress)

Compute and return the occupation number representation of the Fock state fs as an SVector{M}, where M is the number of modes.

source
Rimu.BitStringAddresses.@fs_strMacro
fs"$(string)"

Parse the compact representation of a Fock state. Useful for copying the printout from a vector to the REPL.

Example

julia> DVec(BoseFS{3,4}(0, 1, 2, 0) => 1)
DVec{BoseFS{3, 4, BitString{6, 1, UInt8}},Int64} with 1 entry, style = IsStochasticInteger{Int64}()
  fs"|0 1 2 0⟩" => 1

julia> fs"|0 1 2 0⟩" => 1 # Copied from above printout
BoseFS{3,4}(0, 1, 2, 0) => 1

julia> fs"|1 2 3⟩⊗|0 1 0⟩" # composite bosonic Fock state
CompositeFS(
  BoseFS{6,3}(1, 2, 3),
  BoseFS{1,3}(0, 1, 0),
)

julia> fs"|↑↓↑⟩" # construct a fermionic Fock state
CompositeFS(
  FermiFS{2,3}(1, 0, 1),
  FermiFS{1,3}(0, 1, 0),
)

julia> s = fs"|0 1 2 0⟩{}" # constructing OccupationNumberFS with default UInt8 container
OccupationNumberFS{4, UInt8}(0, 1, 2, 0)

julia> [s] # prints out with the signifcant number of bits specified in braces
1-element Vector{OccupationNumberFS{4, UInt8}}:
 fs"|0 1 2 0⟩{8}"

See also FermiFS, BoseFS, CompositeFS, FermiFS2C, OccupationNumberFS.

source
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, or a SortedParticleList. Which is wrapped is chosen automatically based on the properties of the address.

Constructors

  • BoseFS{[N,M]}(val::Integer...): Create BoseFS{N,M} from occupation numbers. This is type-stable if the number of modes M and the number of particles N are provided. Otherwise, M and N are inferred from the arguments.

  • BoseFS{[N,M]}(onr): Create BoseFS{N,M} from occupation number representation, see onr. This is efficient if N and M are provided, and onr is a statically-sized collection, such as a Tuple or SVector.

  • BoseFS{[N,M]}([M, ]pairs...): Provide the number of modes M and mode => occupation_number pairs. If M is provided as a type parameter, it should not be provided as the first argument. Useful for creating sparse addresses. pairs can be multiple arguments or an iterator of pairs.

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

  • @fs_str: Addresses are sometimes printed in a compact manner. This representation can also be used as a constructor. See the last example below.

Examples

julia> BoseFS{6,5}(0, 1, 2, 3, 0)
BoseFS{6,5}(0, 1, 2, 3, 0)

julia> BoseFS([abs(i - 3) ≤ 1 ? i - 1 : 0 for i in 1:5])
BoseFS{6,5}(0, 1, 2, 3, 0)

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

julia> BoseFS{6,5}(i => i - 1 for i in 2:4)
BoseFS{6,5}(0, 1, 2, 3, 0)

julia> fs"|0 1 2 3 0⟩"
BoseFS{6,5}(0, 1, 2, 3, 0)

julia> fs"|b 5: 2 3 3 4 4 4⟩"
BoseFS{6,5}(0, 1, 2, 3, 0)

See also: SingleComponentFockAddress, OccupationNumberFS, FermiFS, CompositeFS, FermiFS2C.

source
Rimu.BitStringAddresses.bose_hubbard_interactionMethod
bose_hubbard_interaction(address)

Return $Σ_i n_i (n_i-1)$ for computing the Bose-Hubbard on-site interaction (without the $U$ prefactor.)

Example

julia> Hamiltonians.bose_hubbard_interaction(BoseFS{4,4}((2,1,1,0)))
2
julia> Hamiltonians.bose_hubbard_interaction(BoseFS{4,4}((3,0,1,0)))
6
source
Rimu.BitStringAddresses.hopnextneighbourMethod
new_address, product = hopnextneighbour(add, chosen)

Compute the new address of a hopping event for the Bose-Hubbard model. Returns the new address and the square root of product of occupation numbers of the involved modes.

The off-diagonals are indexed as follows:

  • (chosen + 1) ÷ 2 selects the hopping site.
  • Even chosen indicates a hop to the left.
  • Odd chosen indicates a hop to the right.
  • Boundary conditions are periodic.

Example

julia> using Rimu.Hamiltonians: hopnextneighbour

julia> hopnextneighbour(BoseFS(1, 0, 1), 3)
(BoseFS{2,3}(2, 0, 0), 1.4142135623730951)

julia> hopnextneighbour(BoseFS(1, 0, 1), 4)
(BoseFS{2,3}(1, 1, 0), 1.0)
source
Rimu.BitStringAddresses.near_uniformMethod
near_uniform(BoseFS{N,M}) -> BoseFS{N,M}

Create bosonic Fock state with near uniform occupation number of M modes with a total of N particles.

Examples

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

julia> near_uniform(FermiFS{3,5})
FermiFS{3,5}(1, 1, 1, 0, 0)
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, or a SortedParticleList. Which is wrapped is chosen automatically based on the properties of the address.

Constructors

  • FermiFS{[N,M]}(val::Integer...): Create FermiFS{N,M} from occupation numbers. This is type-stable if the number of modes M and the number of particles N are provided. Otherwise, M and N are inferred from the arguments.

  • FermiFS{[N,M]}(onr): Create FermiFS{N,M} from occupation number representation, see onr. This is efficient if N and M are provided, and onr is a statically-sized collection, such as a Tuple{M} or SVector{M}.

  • FermiFS{[N,M]}([M, ]pairs...): Provide the number of modes M and pairs of the form mode => 1. If M is provided as a type parameter, it should not be provided as the first argument. Useful for creating sparse addresses. pairs can be multiple arguments or an iterator of pairs.

  • FermiFS{N,M,S}(bs::S): Unsafe constructor. Does not check whether the number of particles in bs is equal to N, or whether each mode only contains one particle.

  • @fs_str: Addresses are sometimes printed in a compact manner. This representation can also be used as a constructor. See the last example below.

Examples

julia> FermiFS{3,5}(0, 1, 1, 1, 0)
FermiFS{3,5}(0, 1, 1, 1, 0)

julia> FermiFS([abs(i - 3) ≤ 1 for i in 1:5])
FermiFS{3,5}(0, 1, 1, 1, 0)

julia> FermiFS(5, 2 => 1, 3 => 1, 4 => 1)
FermiFS{3,5}(0, 1, 1, 1, 0)

julia> FermiFS{3,5}(i => 1 for i in 2:4)
FermiFS{3,5}(0, 1, 1, 1, 0)

julia> fs"|⋅↑↑↑⋅⟩"
FermiFS{3,5}(0, 1, 1, 1, 0)

julia> fs"|f 5: 2 3 4⟩"
FermiFS{3,5}(0, 1, 1, 1, 0)

See also: SingleComponentFockAddress, BoseFS, CompositeFS, FermiFS2C, BitString, OccupationNumberFS.

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

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.FermiFS2CType
FermiFS2C <: AbstractFockAddress
FermiFS2C(onr_a, onr_b)

Fock state address with two fermionic (spin) components. Alias for CompositeFS with two FermiFS components. Construct by specifying either two compatible FermiFSs, two onrs, or the number of modes followed by mode => occupation_number pairs, where occupation_number=1 will put a particle in the first component and occupation_number=-1 will put a particle in the second component. See examples below.

Examples

julia> FermiFS2C(FermiFS(1,0,0), FermiFS(0,1,1))
CompositeFS(
  FermiFS{1,3}(1, 0, 0),
  FermiFS{2,3}(0, 1, 1),
)

julia> FermiFS2C((1,0,0), (0,1,1))
CompositeFS(
  FermiFS{1,3}(1, 0, 0),
  FermiFS{2,3}(0, 1, 1),
)

julia> FermiFS2C(3, 1 => 1, 2 => -1, 3 => -1)
CompositeFS(
  FermiFS{1,3}(1, 0, 0),
  FermiFS{2,3}(0, 1, 1),
)

julia> fs"|↑↓↓⟩"
CompositeFS(
  FermiFS{1,3}(1, 0, 0),
  FermiFS{2,3}(0, 1, 1),
)
source
Rimu.BitStringAddresses.time_reverseMethod
time_reverse(addr)

Apply the time-reversal operation on a two-component Fock address that flips all the spins.

Requires each component address to have the same type.

source
Rimu.BitStringAddresses.OccupationNumberFSType
OccupationNumberFS{M,T} <: SingleComponentFockAddress

Address type that stores the occupation numbers of a single component bosonic Fock state with M modes. The occupation numbers must fit into the type T <: Unsigned. The number of particles is runtime data, and can be retrieved with num_particles(address).

Constructors

  • OccupationNumberFS(val::Integer...): Construct from occupation numbers. Must be < 256 to fit into UInt8.
  • OccupationNumberFS{[M,T]}(onr): Construct from collection onr with M occupation numbers with type T. If unspecified, the type T of the occupation numbers is inferred from the type of the arguments.
  • OccupationNumberFS(fs::BoseFS): Construct from BoseFS.
  • With shortform macro @fs_str. Specify the number of significant bits in braces. See example below.

Examples

julia> ofs = OccupationNumberFS(1,2,3)
OccupationNumberFS{3, UInt8}(1, 2, 3)

julia> ofs == fs"|1 2 3⟩{8}"
true

julia> num_particles(ofs)
6
source
Rimu.BitStringAddresses.excitationMethod
excitation(addr::OccupationNumberFS, c::NTuple, d::NTuple)
→ (nadd, α)

Generate an excitation on an OccupationNumberFS by applying the creation and destruction operators specified by the tuples of mode numbers c and d to the Fock state addr. The modes are indexed by integers (starting at 1), or by indices of type BoseFSIndex. The value of α is given by the square root of the product of mode occupations before destruction and after creation.

The number of particles may change by this type of excitation.

Example

julia> s = fs"|1 2 3⟩{8}"
OccupationNumberFS{3, UInt8}(1, 2, 3)

julia> num_particles(s)
6

julia> es, α = excitation(s, (1,1), (3,))
(OccupationNumberFS{3, UInt8}(3, 2, 2), 4.242640687119285)

julia> num_particles(es)
7
source

Internal representations

The atomic addresses, BoseFS and FermiFS, are implemented as either bitstrings or sorted lists of particles. Using these approaches over an occupation number representation makes the addresses much more space-efficient.

Therewhile OccupationNumberFS internally uses the occupation number representation, which allows it to handle excitation operations that change the particle number. This is fast but requires more storage space.

Internal APIs

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.SortedParticleListType
SortedParticleList{N,M,T<:Unsigned}

Type for storing sparse fock states. Stores the mode number of each particle as an entry with only its mode stored. The entries are always kept sorted.

Iterating over SortedParticleLists yields occupied modes as a tuple of occupation number, mode number, and position in list.

Constructors

  • SortedParticleList{N,M,T}(::SVector{N,T}): unsafe constructor. Does not sort input.

  • SortedParticleList(arr::AbstractVector): convert ONR to SortedParticleList

source

Index