I wanted to ask if it is possible to programmatically generate SiteTypes (or maybe some equivalent design)? Below, I list three use cases that I am currently handling with custom objects (let’s call them SiteObjects), and I was wondering if I could switch to the SiteType machinery. The first, I think, is quite generic, but the other two might be non-standard:
Two-species fermionic site - Specifically I use it to describe the space of a vectorized density matrix (so 4-dimensional space). I start, for example, with a site that conserves some U(1) charge labeled “N”. Then I wish create a new site by replacing the label with “N↑” and adding a trivial (0 value) label “N↓” (and a similar site where “N↑”=0 and “N↓” labels the charge). The operators are identical in all three cases, but I do not want to hardcode all three, as I can also have other cases, e.g., four U(1) charges labeled “N1↑”, “N1↓”, “N2↑”, “N2↓” and many other options. So I am thinking along the following lines: Define a SiteType for only one space, on-the-fly specify one-to-one mappings between different spaces, and then use this to infer the other SiteTypes. Is this something that is possible?
Compressed physical spaces - I combine multiple physical indices into one large index and then compress it with some projector. This yields an effective space, which could, for example, serve as the physical space of an MPS site. I would then also have compressed operators and special states for this effective sites. There are many possible compressions (for example depending on parameters), and different MPS sites could have different effective spaces. So signing on tags is quite inconvenient. But, nevertheless, each index is associated with a given set of operators and states that are computed once, and used many times. Can this fit in the SiteType machinery?
Composite multisites - For example, I have 4 single-species fermionic sites, and I want to construct a 4-species site (with a combiner) that has operators that know about some chosen Jordan-Wigner order. I would really like to use a combiner, and not generate a new 4-species site from a separate SiteType as: (a) I would like to be able to decompose the space back to the original 4 indices; and (b) each of the original 4 fermions might have a different fermionic space (SiteType), for example different values for conserved charges. But, it could still be nice to access the operators acting on this space with the SiteType machinery.
My current code does: For each index that I work with, I define a custom SiteObject that stores / generates all the relevant operators and interesting states for that index. This clearly overlaps with what SiteTypes are meant for. But, one SiteObject type corresponds to a class of possible SiteTypes, with different instances holding the specific dimension of the space, symmetry labels, and set of operators (i.e., “programmatically generated SiteTypes”, although I never use SiteTypes). While this offers nice flexibility, it is also stores redundant information (many of the SiteObject instances are identical), and reimplements an already existing and mature system. Do you think the above cases could be treated with the SiteType machinery?
Hi Matan,
Thanks for the interesting question. Since there are many details and cases above, perhaps I can ask for a little more background to simplify?
Narrowly, your question is whether you can use the SiteType system for the examples you want to do. I think in that framing, the answer is probably no. What I mean is that the SiteType system is based around Index tags, and while you could probably devise a way to store the information you want into Index tags, it is most likey an ‘abuse’ of what tags are good at and might cause a lot of headaches and so on.
Zooming out, is your question really about having a good way to programmatically generate new, and potentially complicated / custom, Index’s and nevertheless automatically know how to define or compute certain operators acting on these indices?
If so, I think it calls for a more powerful approach than using Index tags and/or the SiteType system (which again is really just a system for dispatching on certain Index tags).
Here are some ideas, just off the top of my head so they could use improving or a careful evaluation:
presumably when your indices get formed, they are made of some previous spaces where you know how to define operators. You could imagine when the next indices are made, you could do an on-the-fly analysis of how operators transform into the new space, then use a global dictionary where the keys are Index id numbers to store the matrix elements of the new operators (operators in the new spaces). If this leads to a dictionary that is too large, which could be because a lot of the indices are “physically” identical (same spaces and matrix elements) you could think of ways around this, like a two-level dictionary or some other way of id’ing the new spaces.
a better idea might be to use the freedom of Index objects to store an arbitrary “space” inside them. Right now, we use this capability in a pretty narrow way. We just have the space either be an integer (for the dimension) or a Vector of QN=>Int pairs denoting “blocks” of an Index and under what irreps they transform (what QN they have). But in some code of my own, I’ve explored putting other information in these spaces and found, happily, that I can still get such custom Index objects to play well with the rest of the ITensor system by just defining a few method overloads. So you could imagine something like storing in your Index objects a custom space type that could be e.g. the matrix elements of a certain basis of operators in that Index, alongside more basic information like the dimension of the Index.
it might just be that the operators you are trying to “track” are uniquely defined by the QN structure of your indices. Like if your indices conserve total “Sz” (are labeled by the “Sz” quantum number) then the “Sz” operator is just a diagonal matrix with the"Sz" QN values as entries, correct? So maybe a lot of operators can just be worked out on the fly that way?
Playing around, I realized that my first usecase (equivalent SiteTypes with many different quantum numbers) is already supported (and exactly for the same reason)! Apparently op only cares about the tag, so as long as the dimension of the Hilbert space is unchanged and I do not mess up the fluxes, I can assign whatever quantum numbers I wish to the index while defining only a single SiteType.
Then for my second usecase (compressed physical spaces), storing information in a custom space looks promising! For more context, I have the vectorized, or double space in which some large density matrix lives. However, I compress this space, so, for example, the (vectorized) trace operation becomes nontrivial. Thus, it cannot be recalculated without prior knowledge, in contrast to Sz operations, which I indeed generated on the fly from the quantum numbers as you suggested.
If the trace is stored in the space, I do not need to worry about carrying it around all the time. This approach only makes sense for states and block-diagonal operators on a given index (because it is encoded for the space of each block), but that covers what I need. Also, it makes the index a somewhat heavier object, but this is probably not a problem. It seems that whenever I generate a new tensor with some index, the index gets copied, but they point to the same instances of spaces, so the operators are only stored once!
Usecase three (composite sites) is something that could be generically useful. But, from my side, it is not that pressing from at the moment, as I am using it in a nongeneric and non modular part of the code. So let’s leave that for now.
Glad to hear you have a plan for each of those cases. Yes, think about trying the custom spaces if that seems like the best solution to your problem. I think it could eventually become quite a powerful technique and something we could use more in applications of ITensor.
To give an interesting example, the method I tried it for was the “tensor cross interpolation” (TCI or TT-cross) for learning MPS from calling a function. In that algorithm, the bond or virtual spaces are ‘decorated’ with ‘pivot’ information which are kind of like how indices can be blocked by quantum numbers except that these aren’t quantum numbers but rows or columns of the MPS, viewed as a matrix across that bond. So I tried, successfully, in an experimental code to store those pivots inside the indices themselves. It was interesting and worked well but time will tell if that’s the best design.