Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vacuum constructors for OccupationNumberFS #308

Merged
merged 8 commits into from
Feb 6, 2025
12 changes: 8 additions & 4 deletions src/BitStringAddresses/bosefs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,15 @@ automatically based on the properties of the address.
particles in `bs` is equal to `N`.

* [`@fs_str`](@ref): Addresses are sometimes printed in a compact manner. This
representation can also be used as a constructor. See the last example below.
representation can also be used as a constructor. See the examples below.

# Examples

```jldoctest
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])
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)
Expand Down Expand Up @@ -97,7 +97,8 @@ function BoseFS{N,M}(onr::Union{AbstractArray{<:Integer},NTuple{M,<:Integer}}) w
end
return BoseFS{N,M,S}(from_bose_onr(S, onr))
end
function BoseFS(onr::Union{AbstractArray,Tuple})
function BoseFS(onr) # single argument constructor
onr = Tuple(onr)
M = length(onr)
N = sum(onr)
return BoseFS{N,M}(onr)
Expand All @@ -106,10 +107,13 @@ BoseFS(vals::Integer...) = BoseFS(vals) # specify occupation numbers
BoseFS(val::Integer) = BoseFS((val,)) # single mode address
BoseFS{N,M}(vals::Integer...) where {N,M} = BoseFS{N,M}(vals)

# Sparse constructors
BoseFS(M::Integer, pairs::Pair...) = BoseFS(M, pairs)
BoseFS(M::Integer, pairs) = BoseFS(sparse_to_onr(M, pairs))
BoseFS{N,M}(pairs::Pair...) where {N,M} = BoseFS{N,M}(pairs)
BoseFS{N,M}(pairs) where {N,M} = BoseFS{N,M}(sparse_to_onr(M, pairs))
BoseFS(pairs::Pair...) = throw(ArgumentError("number of modes must be provided"))


function print_address(io::IO, b::BoseFS{N,M}; compact=false) where {N,M}
if compact && b.bs isa SortedParticleList
Expand Down Expand Up @@ -259,7 +263,7 @@ end

Compute the new address of a hopping event for the Hubbard model. Returns the new
address and the square root of product of occupation numbers of the involved modes
multiplied by a term consistent with boundary condition as the `value`.
multiplied by a term consistent with boundary condition as the `value`.
The following boundary conditions are supported:

* `:periodic`: hopping over the boundary gives does not change the `value`.
Expand Down
6 changes: 4 additions & 2 deletions src/BitStringAddresses/fermifs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ chosen automatically based on the properties of the address.
particles in `bs` is equal to `N`, or whether each mode only contains one particle.

* [`@fs_str`](@ref): Addresses are sometimes printed in a compact manner. This
representation can also be used as a constructor. See the last example below.
representation can also be used as a constructor. See the examples below.

# Examples

Expand Down Expand Up @@ -95,7 +95,8 @@ function FermiFS{N,M}(onr::Union{AbstractArray{<:Integer},NTuple{M,<:Integer}})
end
return FermiFS{N,M,S}(from_fermi_onr(S, onr))
end
function FermiFS(onr::Union{AbstractArray,Tuple})
function FermiFS(onr)
onr = Tuple(onr)
M = length(onr)
N = sum(onr)
return FermiFS{N,M}(onr)
Expand All @@ -109,6 +110,7 @@ FermiFS(M::Integer, pairs::Pair...) = FermiFS(M, pairs)
FermiFS(M::Integer, pairs) = FermiFS(sparse_to_onr(M, pairs))
FermiFS{N,M}(pairs::Vararg{Pair,N}) where {N,M} = FermiFS{N,M}(pairs)
FermiFS{N,M}(pairs) where {N,M} = FermiFS{N,M}(sparse_to_onr(M, pairs))
FermiFS(pairs::Pair...) = throw(ArgumentError("number of modes must be provided"))

function print_address(io::IO, f::FermiFS{N,M}; compact=false) where {N,M}
if compact && f.bs isa SortedParticleList
Expand Down
52 changes: 43 additions & 9 deletions src/BitStringAddresses/occupationnumberfs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ particles is runtime data, and can be retrieved with `num_particles(address)`.
- `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{M[,T]}()`: Construct a vacuum state with `M` modes. If `T` is
unspecified, `UInt8` is used.
- `OccupationNumberFS(fs::BoseFS)`: Construct from [`BoseFS`](@ref).
- With shortform macro [`@fs_str`](@ref). Specify the number of
significant bits in braces. See example below.
Expand All @@ -24,36 +26,68 @@ true

julia> num_particles(ofs)
6

julia> OccupationNumberFS{5}() # vacuum state with 5 modes
OccupationNumberFS{5, UInt8}(0, 0, 0, 0, 0)

julia> OccupationNumberFS(i for i in 1:3) # use list comprehension
OccupationNumberFS{3, UInt8}(1, 2, 3)

julia> OccupationNumberFS(4, 1=>2, 3=>4) # sparse constructor
OccupationNumberFS{4, UInt8}(2, 0, 4, 0)
```
"""
struct OccupationNumberFS{M,T<:Unsigned} <: SingleComponentFockAddress{missing,M}
onr::SVector{M,T}

function OccupationNumberFS{M,T}(args...) where {M,T<:Unsigned}
return new(SVector{M,T}(args...))
end
end

function OccupationNumberFS{M,T}(args...) where {M,T}
return OccupationNumberFS(SVector{M,T}(args...))
function OccupationNumberFS(sv::SVector{M,T}) where {M,T<:Unsigned}
return OccupationNumberFS{M,T}(sv)
end

function OccupationNumberFS(args...)
sv = SVector(args...)
all(isinteger, sv) || throw(ArgumentError("all arguments must be integers"))
all(x -> x ≥ 0, sv) || throw(ArgumentError("all arguments must be non-negative"))
all(x -> x < 256, sv) || throw(ArgumentError("arguments don't fit in a byte, specify type"))
return OccupationNumberFS(SVector{length(sv),UInt8}(args...))
function OccupationNumberFS(arg)
t = Tuple(arg)
return OccupationNumberFS{length(t)}(t)
end

function OccupationNumberFS(args::Integer...)
return OccupationNumberFS{length(args)}(args)
end
OccupationNumberFS(arg::Integer) = OccupationNumberFS{1}(arg) # to resolve ambiguity

function OccupationNumberFS{M}(args...) where M
sv = SVector{M}(args...)
joachimbrand marked this conversation as resolved.
Show resolved Hide resolved
all(isinteger, sv) || throw(ArgumentError("all arguments must be integers"))
all(x -> x ≥ 0, sv) || throw(ArgumentError("all arguments must be non-negative"))
all(x -> x < 256, sv) || throw(ArgumentError("arguments don't fit in a byte, specify type"))
return OccupationNumberFS(SVector{M,UInt8}(args...))
return OccupationNumberFS{M,UInt8}(args...)
end

function OccupationNumberFS(fs::BoseFS{N,M}) where {N,M}
return OccupationNumberFS{M,select_int_type(N)}(onr(fs))
end

# convenience constructors for vacuum state
function OccupationNumberFS{M,T}() where {M,T<:Unsigned}
return OccupationNumberFS(SVector{M,T}(zero(T) for _ in 1:M))
end
OccupationNumberFS{M}() where {M} = OccupationNumberFS{M,UInt8}()

# Sparse constructors
OccupationNumberFS(M::Integer, pairs::Pair...) = OccupationNumberFS(M, pairs)
OccupationNumberFS(M::Integer, pairs) = OccupationNumberFS(sparse_to_onr(M, pairs))
OccupationNumberFS{M}(pairs::Pair...) where {M} = OccupationNumberFS{M}(pairs)

function OccupationNumberFS{M}(pairs::NTuple{<:Any,Pair}) where {M}
OccupationNumberFS{M}(sparse_to_onr(M, pairs))
end

OccupationNumberFS(pairs::Pair...) = throw(ArgumentError("number of modes must be provided"))

function print_address(io::IO, ofs::OccupationNumberFS{M,T}; compact=false) where {M,T}
if compact
BITS = sizeof(T) * 8
Expand Down
18 changes: 9 additions & 9 deletions src/BitStringAddresses/sortedparticlelist.jl
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
"""
select_int_type(M)
select_int_type(n)

Select unsigned integer type that can hold values up to `M`.
Select unsigned integer type that can hold values up to `n`.
"""
function select_int_type(M)
if M ≤ 0
throw(ArgumentError("`M` must be positive!"))
elseif M ≤ typemax(UInt8)
function select_int_type(n)
if n < 0
throw(ArgumentError("`n` must be a non-negative integer!"))
elseif n ≤ typemax(UInt8)
return UInt8
elseif M ≤ typemax(UInt16)
elseif n ≤ typemax(UInt16)
return UInt16
elseif M ≤ typemax(UInt32)
elseif n ≤ typemax(UInt32)
return UInt32
else
return UInt64
Expand All @@ -20,7 +20,7 @@ end
"""
SortedParticleList{N,M,T<:Unsigned}

Type for storing sparse fock states. Stores the mode number of each particle as an entry
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 `SortedParticleList`s yields occupied modes as a tuple of occupation number,
Expand Down
17 changes: 14 additions & 3 deletions test/BitStringAddresses.jl
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ end

@test_throws ArgumentError BoseFS(10, 11 => 1)
@test_throws ArgumentError BoseFS(10, 10 => -1)
@test_throws MethodError BoseFS(10 => 1)
@test_throws ArgumentError BoseFS(10 => 1)
end
@testset "onr" begin
middle_full_onr = onr(middle_full)
Expand Down Expand Up @@ -461,8 +461,10 @@ end
end

@testset "OccupationNumberFS with multiple arguments" begin
@test isa(OccupationNumberFS(1, 2, 3), OccupationNumberFS{3, UInt8})
@test_throws ArgumentError OccupationNumberFS(1.1, 2, 3)
@test OccupationNumberFS(i for i in 1:3) == OccupationNumberFS(1, 2, 3)
@test isa(OccupationNumberFS{3,UInt32}(i for i in 1:3), OccupationNumberFS{3,UInt32})
@test isa(OccupationNumberFS(1, 2, 3), OccupationNumberFS{3,UInt8})
@test_throws MethodError OccupationNumberFS(1.1, 2, 3)
@test_throws ArgumentError OccupationNumberFS(-1, 2, 3)
@test_throws ArgumentError OccupationNumberFS(1, 2, 300)
end
Expand All @@ -479,6 +481,15 @@ end
@test isa(OccupationNumberFS(fs), OccupationNumberFS{2, UInt8})
fs = BoseFS(1, 333)
@test isa(OccupationNumberFS(fs), OccupationNumberFS{2,UInt16})
fs = BoseFS(0, 0)
@test isa(OccupationNumberFS(fs), OccupationNumberFS{2,UInt8})
end

@testset "OccupationNumberFS with sparse constructor" begin
@test OccupationNumberFS(2, 2=>4) == OccupationNumberFS(0, 4)
@test OccupationNumberFS{2}(2 => 4) == OccupationNumberFS(2, 2 => 4)
@test OccupationNumberFS(5, i => i + 1 for i in 1:3) ==
OccupationNumberFS{5}(Tuple(i => i + 1 for i in 1:3))
end

@testset "Printing and parsing OccupationNumberFS" begin
Expand Down
Loading