Misc
Subregion
When the Hilbert space has a restricted set of fock states, the Hilbert space of the subregion will only include fock states compatible with this restriction. In the example below, the total number of particles 1, and the subregion will have three possible states: (1,0), (0,1), and (0,0).
using FermionicHilbertSpaces
@fermions f
H = hilbert_space(f, 1:4, NumberConservation(1))
Hsub = subregion(hilbert_space(f, 1:2), H)
basisstates(Hsub)3-element Vector{FockNumber{UInt64}}:
|1⟩
|01⟩
|0⟩Parallelization
Matrix construction can be parallelized by passing a chunking strategy to matrix_representation. The two supported options are TermChunking(scheduler), which splits work by operator terms, and StateChunking(scheduler), which splits work by basis states. Any OhMyThreads scheduler can be used, for example StaticScheduler.
using FermionicHilbertSpaces, OhMyThreads
using FermionicHilbertSpaces: TermChunking, StateChunking
@fermions f
H = hilbert_space(f, 1:4)
op = f[1]' * f[2] + 1im * f[2]' * f[1] + f[3]' * f[4] + f[4]' * f[3] + 2
scheduler = StaticScheduler(; nchunks=4)
M1 = matrix_representation(op, H; chunking=TermChunking(scheduler))
M2 = matrix_representation(op, H; chunking=StateChunking(scheduler))16×16 SparseArrays.SparseMatrixCSC{Complex{Int64}, Int64} with 32 stored entries:
⎡⠱⢆⠀⠀⠀⠀⠀⠀⎤
⎢⠀⠀⠱⢆⠑⢄⠀⠀⎥
⎢⠀⠀⠑⢄⠱⢆⠀⠀⎥
⎣⠀⠀⠀⠀⠀⠀⠱⢆⎦For distributed sparse matrices, use PartitionedSparseRepr with a PartitionedArrays backend:
using FermionicHilbertSpaces, PartitionedArrays
using FermionicHilbertSpaces: PartitionedSparseRepr
@fermions f
space = hilbert_space(f, 1:3)
op = f[1]' * f[2] + (1 + 2im) * f[3]' * f[1] + 2.0
rep = PartitionedSparseRepr(; backend=DebugArray)
M = matrix_representation(op, space, rep)To use MPI, start julia with MPI (mpiexec -n 8 julia) and do
using MPI
MPI.Init()
rep = PartitionedSparseRepr(; backend=distribute_with_mpi, nparts=MPI.Comm_size(MPI.COMM_WORLD))
matrix_representation(op, space, rep)Reshaping
reshape converts arrays by splitting or combining axes according to Hilbert-space mappings. Mappings are applied left-to-right, and each mapping consumes the next consecutive group of input axes.
reshape(t::AbstractArray, mappings...; repeat=false)Supported mapping forms:
H => (H1, H2, ...): split one axis into several(H1, H2, ...) => H: combine several consecutive axes into one(H1, H2, ...) => (K1, K2, ...): repartition several axes into severalH => H: keep one axis unchanged
Direct many-to-many mappings are equivalent to explicit combine-then-split composition:
reshape(A, (H1, H2) => (K1, K2))
# equivalent to reshape(reshape(A, (H1, H2) => Hmid), Hmid => (K1, K2))where Hmid is the canonical combined space of the input tuple.
Multiple mappings
Provide one mapping per axis group:
reshape(A, H1 => (H1a, H1b), (H2a, H2b) => H2, H3 => H3)This splits the first axis, combines the next two, and keeps the last unchanged.
Single-mapping shorthand
If exactly one mapping is provided, it is expanded automatically:
- If it consumes all axes of
t, it is applied once. - If
thas twice as many axes as the mapping consumes, the mapping is applied to the first half and again to the second half.
This is convenient for square operator matrices:
reshape(v, H => (H1, H2))
reshape(m, H => (H1, H2))
reshape(T, (H1, H2) => H)For asymmetric operators, specify both sides explicitly:
reshape(m, Hout => (H1, H2), Hin => (K1, K2))Repeating one mapping
With repeat=true, one mapping is applied to every consecutive compatible axis group:
reshape(A, H => (H1, H2); repeat=true)Pair syntax and curried form
Mappings use Pair syntax and can be passed directly:
reshape(m, H => (H1, H2))
reshape(T, (H1, H2) => H)reshape also accepts mappings first and returns a function:
to_tensor = reshape(H => (H1, H2))
to_matrix = reshape((H1, H2) => H)This does not provide any performance benefit at the moment, but might in the future.
Practical usage
For worked examples, see docs/src/literateoutput/opensystem_lindblad.md.
State mapper interface
Internal tensor/reshape/partial-trace routines use a common mapper protocol:
state_mapper(H, Hs)returns a mapper object.split_state(state, mapper)returns a tuple with one entry per target subsystem.- Each tuple entry is a weighted collection
((substate, weight), ...). combine_states(substates, mapper)returns a weighted collection((state, weight), ...).
This package does not require a single concrete container type for weighted collections; callers should treat them as iterable collections of (state, weight) outcomes.