-
Notifications
You must be signed in to change notification settings - Fork 8
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
Taking blocks seriously #230
Comments
Direct flat/unflat IndexingAbout the indexing functionality above, there is a much better syntax than the proposed one. Instead of doing the following to get the block Matrix of a
we could repurpose
This would immediately return a In other words, there is no need to go though a SubArray of a HybridSliceMatrix, which would not have any meaningful functionality except as an argument to We could then extend this also to the |
Diagonal indexingThere is a special functionality currently whereby The |
I have a lingering worry. While the case of |
Indexing memoization as an alternative to
|
#232 has a simpler approach to block access that seems more transparent than the whole SiteIndexCache story. The more I think about it, the more tricky caching looks: what happens if we compute two multisite slices twice? Since we're storing only single-site results, do we read the cache or do a full recompute? It would need to be a full recompute. The cache is probably only useful for second-time single-site indexing, which is a rather restricted case in exchange for considerable code complexity. Not saying we should not do it at some point if there is a compelling reason. But the reasons given here, including the mean-field implementation, seems to be solved more simply in #232. In particular, that proposal is just a Array-like wrapper, so it is orthogonal to the current indexing of GreenFunctions, which is good. In that sense, it is similar but cleaner than the HybridSliceMatrix approach in this thread. It follows the same logic as repeated slicing of Arrays in Julia. Hence, I'm closing this for the moment. We could reopen further down the road if we find a good reason for single-site caching. |
Here I'd like to discuss how to represent the block structure (i.e. orbital groups corresponding to each cell/site) of two types of objects:
Bloch Hamiltonians such as
h(φs; params...)
, which currently yields a flatSparseMatrixCSC
over all orbitals in one unit cellGreen functions such as
g[siteselector](ω)
, which currently yields a flatMatrix
over all orbitals in theLatticeSlice
defined bysiteselector
The issue is how to recover the substructure in these flat matrices corresponding to each (multiorbital) site or unit cell. Currently this is klunky or impossible. This functionality is necessary in many instances, but in particular to be able to implement Hartree-Fock mean fields #229, since the density matrix (a Green-function-derived object) needs to be site-indexable.
Warning: this is a bit of a heavy-going, internal-developer-dialogue kind of issue.
Bloch Hamiltonians
In master, we already have both a flat and an unflat SparseMatrixCSC representation of each of the Bloch Harmonics
h[dcell]
. Each of this Harmonic is internally stored as aHybridSparseMatrix
that takes care of syncing the flat and block sparse representations of each Harmonic after each update of model parameters.Currently, if we do
h[unflat(dcell)]
we get the block-sparse representation of that specific Harmonic. However, we don't yet have a way to do the same for the full Bloch Hamiltonian (sum over harmonics with a givenk
). In other words,h(unflat(φs); params...)
is not defined.One of the reasons is that I don't quite like the idea of wrapping
dcell
orφs
withunflat
for this. I would much prefer to be able to doh[dcell] |> unflat
orh(φs; params...) |> unflat
. But ifh[dcell]
andh(φs; params...)
are already flat SparseMatrixCSC, they have already lost the information to rebuild them as a block sparse matrix.I see two options:
Define a macro
@unflat
, such that@unflat h[dcell]
gets lowered tounflat_getindex(h, dcell)
or similar, and@unflat h(φs; params...)
becomesunflat_bloch!(h, sanitize_SVector(T, φs))
(instead of the curentflat_bloch!(h, sanitize_SVector(T, φs))
).Make both
h[dcell]
andh(φs; params...)
return aresult::HybridSparseCSC
, such thatunflat(result)
yields a block-sparse matrix, and perhapsflat(result)
yields the current result. To make things non-breaking, we would need to makeHybridSparseCSC
act in all other respects as a flat SparseMatrixCSC, in regards togetindex
,setindex
,show
,mul!
,nonzeros
, etc... We could also admit a breaking change, and require the user to callflat
orunflat
before using the result (maybe the cleanest way).In both cases, we would deprecate the current
h[unflat(dcell)]
syntax.Approach 2 may seem to involve some overhead, since it seems we need to build two versions of the Bloch matrix, where we usually only need the flat one (e.g. for diagonalization or use in a GreenSolver, which is 90% of the time). But note that
HybridSparseCSC
is smart, in the sense that it can be initialized with just the flat version of a Matrix, and the unflat one gets built from the former upon callingunflat
(only the first time, after that both versions are marked in-sync).Green functions over a LatticeSlice
The current result of
gmat = g[siteselector](ω)
orgmat = g[siteselector´, siteselector](ω)
is borderline useless when we have several orbitals per site, because we get a flat dense matrix, and no information of what entry corresponds to what orbital. We should actually return something different, which would be a breaking change, but it is probably unavoidable. The question is what should we return.One of the missing functionalities is the ability to do
gmat[sites´, sites]
, wheresites
andsites´
are aCellSites
(which can be currently created withcellsites(cell_indices, site_indices)
, already exported). Note that what we can already do is to use thosesites
in place ofsiteselector
beforehand (i.e.gmat = g[sites´, sites](ω)
), but not after construction.Another functionality is the computation of traces. If
gmat = g[siteselector](ω)
and we have several orbitals per site, we probably would liketr(gmat)
to return an SMatrix, so that trace is a sum over sites, not orbitals. Without this, we cannot easily compute things like the hole component of the LDOS in a superconducting model, or the magnetic moment in a ferromagnet model.Like for Bloch Hamiltonians I see basically two options
Make an
@unflat
macro that instead of a flat Matrix, convertsgmat = @unflat g[siteselector...](ω)
into a Matrix of Matrices/Views/SMatrices.Make
g[siteselector...](ω)
return always anHybridDenseMatrix
, to be defined, that can itself be cast into a flat or block dense matrix withflat
/unflat
. Theunflat
version should probably be aMatrix
ofView
s, since the block size may be variable in the multiorbital case (cannot be an eltype of a fixedSMatrix
type).Indexing
As can probably be read between lines, I am more inclined towards option 2 in both cases. In the case of Bloch Hamiltonians, the
unflat
of a multiorbitalh
would yield aSparseMatrixCSC{SMatrixView}
, whereSMatrixView
is a Quantica type represented anSMatrix
padded with the required zeros to allow variable block size. This a don't like very much, to be honest. We could perhaps do a quick conversion when callingunflat
so that we get aSparseMatrixCSC{SubArray}
(i.e. a sparse matrix of views, like in option 2 of the Green function case).Apart from the
flat
/unflat
functionality, there is another reason why I like option 2: advanced indexing.We could define
view(h::HybridSparseMatrix, sites´, sites)
, wheresites
andsites´
are a collection of Integers (site indices in the unit cell). This could return aSubArray{HybridSparseMatrix}
, which could be cast into a sparse matrix withflat
/unflat
, which in this case would make an independent sparse array.Since it doesn't make sense to specify cells for a Bloch matrix, we should then probably rename
HybridSparseMatrix
toHybridBlochMatrix
(this also prepares the way for a potential dense version of a Bloch Matrix, to be discussed).We could also define
view(g::HybridDenseMatrix, sites´, sites)
, wheresites
andsites´
are nowCellSites
, i.e. collections of cell and site indices. This would again create aSubArray{HybridDenseMatrix}
, which would be madeflat
/unflat
.For symmetry, we could rename
HybridDenseMatrix
to e.g.HybridSliceMatrix
to emphasize itsLatticeSlice
domain, instead of its Dense nature. This way we could perhaps leave the door open to a sparse version ofHybridSliceMatrix
, such as a sparse density matrix with a mask (using SuiteSparseGraphBLAS.jl)If any requested site in
view(g::HybridSliceMatrix, sites´, sites)
is not contained in theLatticeSlice
ofg
, aBoundsError
should probably be thrown.This defines a
view
->flat
/unflat
workflow. Should we define agetindex
too? Probably not, since it is equivalent to establishing a flat or unflat preference, like in current master.Implementation
The
HybridBlochMatrix
is essentially implemented already. We just need to adapt the code to (a) callflat
in certain places (and export theflat
function), and (b) Implement theflat
/unflat
ofSubArray{HybridBlochMatrix}
.The
HybridSliceMatrix
needs to be implemented from scratch. It requires some constructor that can take a flatMatrix
(the current output of all GreenSolvers), aLatticeSlice
+OrbitalBlockStructure
from the generating parent object, and build with those aDictionary
that can map cell+site indices for sites included in theLatticeSlice
to orbitalUnitRange
s, i.e. indices in the flatMatrix
. Then,view(g::HybridSliceMatrix, s´::CellSites, s::CellSites)
would find the index ranges by agetindex
call to theDictionary
, and then build a view of the flatMatrix
with them. If theCellSites
are all contiguous (i.e.site_indices
are contiguouscell_indices
are a single cell), the Dictionary should be able to provide a single indexUnitRange
, so that the returnedSubArray{Matrix}
is non-allocating. Otherwise we would need to allocate aVector
of indices of the flatMatrix
, and the view will unavoidably allocate.Note: I mention
Dictionary
because in considering this implementation it is only natural to consider also a refactor of all our collection of cell objects, such asHarmonics
insideHamiltonian
, orLatticeSlice
itself. We could convert the currentVector
-of-cells to aDictionary
withcell::SVector{L,Int}
as keys. The virtue ofDictionary.jl
as opposed toBase.Dict
is that iteration over values (i.e. cells) is very efficient, which is the reason we usedVector
s in Quantica for cell containers in the first place. Moving to Dictionary.jl for this (a very minimal dependence) would not slow down iteration, and would speed up cell indexing considerably (we currently do an O(N) search).Scalar case
In the scalar case (each site has a single orbital), there is no distinction between flat and unflat. It might seem that in such case we should return a
SparseMatrixCSC
directly instead of aHybridBlochMatrix
. This may be acceptable. However, we would still need to build aHybridSliceMatrix
in the case of GreenFunctions, since we need to support cell+site indexing. To avoid surprising behaviors I am inclined to not make exceptions, and make the return type always beHybridBlochMatrix
orHybridSliceMatrix
, regardless of whether the problem is single or multiorbital.The text was updated successfully, but these errors were encountered: