Hi Bart,
it's essentially defined by the following line in
ExactDiag.__init__()
Python: Select all
self._pipe = npc.LegPipe(legs, qconj=1, sort=(not sparse), bunch=(not sparse))
Unless you use the `sort=False` keyword, the pipe internally sorts by charge values, more precises such that it's `qmap` is lexiographically sorted - that's why you get that strange order in this case.
The task of the Pipe is essentially to 1) store the orginal legs it was contracted from and 2) the permutations done, such that the combine_legs can be un-done with the `split_legs`. Which order the pipe chooses is considered an implementation detail (it's a somewhat arbitrary convention how we do that), but we guarantee that the `split_legs` can undo the permutation done.
When you call
psi_full.to_ndarray()
where psi_full is e.g. the ground state returend by exact_diag.groundstate(), you will get a full single leg with d^L entries. The straightforward solution is to call split_legs() first, which undoes whatever permutation was done for the combine_legs, such that
psi_full.split_legs().to_ndarray()
is simply a shape [d]*L array instead - then the mapping of indices should be very clear.
This is a bit inefficient (since it fills on all the zeros that are guaranteed by to be zero by charge conservation) - if you need to avoid that as well, you instead need to directly get the data block out of the np_conserved array, and undo the permutation yourself.
Technically, the permutation data is stored in LegPipe._perm and ._qmap, but it's probably hard to read that out and disentangle the code, if you don't know the structure. The more bruteforce but simple way would be to just call
LegPipe.map_incoming_inds()
for all combinations of indices you need, and get the permutation from that. (Given that we are currently rewriting the np_conserved for version 2.0, I would recommend to not invest too much time into understanding the LegPipe's internal details)