# Accessing tensor elements

Hi there,

I have some old v2 ITensor code that I would like to make current with v3. I would just like to access tensor elements (real part). This might be similar to https://itensor.org/support/1209/accessing-elements-of-tensor-with-variable-rank?show=1209#q1209.

I've done a DMRG calculation with an output psi (MPS). This is a snippet of my proceeding code.

int N = length(psi);
auto sites = SpinHalf(N);
ITensor cap;

for (auto i : range1(N)) {
auto tensor = i == 1 ? psi.A(i) : cap * psi.A(i);
auto rho = prime(dag(tensor), "Site") * tensor;
auto I = sites(i);
auto Ip = prime(I);

vector<Real> weights(2+1);
for (auto idx : range1(2)) {
weights[idx] = rho.real(I(idx), Ip(idx));
}
// irrelevant stuff
}


This returns the following error (see https://github.com/ITensor/ITensor/blob/1011a6f9c56eccf60b117920fc06d6f296ca8e58/itensor/tensor/permutation.h#L135):

terminate called after throwing an instance of 'std::runtime_error'
what():  sets are not permutations of each other
Aborted (core dumped)


The line that's giving me trouble is rho.real(I(idx), Ip(idx)). What's the new way of doing this?

Thank you for your help. I hope you all are staying safe!

Hi, thanks for the question. So the new way of getting elements of tensors in v3 is to use .elt instead of .real and .eltC instead of .cplx. But in fact, those are just renamings and have the same interface and behavior.

So for the particular error you are getting, I believe it's not so much a version 2 versus version 3 issue. It's probably rather that the ITensor rho doesn't have one or both of the indices I and Ip. Did you confirm by printing out rho, I, and Ip that it has exactly those indices?

Also, I'm not sure if you ran your code in debug mode or not, but if you do run the debug build you'll often get nicer error messages in cases like these.

Best,
Miles

commented by (150 points)
You are right that this is less of a v2 -> v3 issue, as changing .real to .elt resulted in the same error. Here is rho, I and Ip printed.

I =
(2|id=35|n=1,Site,S=1/2) <Out>
1: 1 QN({"Sz",1})
2: 1 QN({"Sz",-1})
Ip =
(2|id=35|n=1,Site,S=1/2)' <Out>
1: 1 QN({"Sz",1})
2: 1 QN({"Sz",-1})
rho =
ITensor ord=2:
(2|id=212|n=1,Site,S=1/2)' <In>
1: 1 QN({"Sz",1})
2: 1 QN({"Sz",-1})
(2|id=212|n=1,Site,S=1/2) <Out>
1: 1 QN({"Sz",1})
2: 1 QN({"Sz",-1})
{norm=1.41 (QDense Real)}

I'm not sure that I'm interpreting the output properly, but it seems to me that rho has I and Ip as indices... Is this not the case? I see small differences like the "id" and <In> versus <out>. but I'm unsure if that's detrimental.
commented by (46.7k points)
Good question. So the key piece of information here is the id number of each Index. Although rho has indices which are physically similar to I and Ip, they have different id numbers than I and Ip (id=212, versus id=35, so that means formally they represent different spaces).

Probably this is because you created psi with a different set of sites (a different call to SpinHalf). Did you recover psi from an earlier run where you wrote it to disk, perhaps? If so, you can write the sites object too and reuse that. If it’s for a different reason we can discuss the best approach further -

Miles
commented by (150 points)
Yes, I created psi with a different set of sites. I basically just have a separate function that draws S^z samples from MPS psi (from a DMRG calculation), but wasn't calling on the same SiteSet that I used for the DMRG calculation. I've got the SiteSet used for the DMRG calculation as a function argument now. Thank you for your help!