Hi, so the answer to your question is that if you want matrix elements of the entire (pure state) density matrix, these are products of the amplitudes of the wavefunction itself. Amplitudes of MPS wavefunctions are efficient to compute: you just have to "clamp" all of the indices then multiply the resulting matrices. We don't have an automatic facility for this with ITensor but it's easy to do. Here is an example code.
Say we have an MPS "psi" on four S=1/2 sites (sites = SpinHalf(4)).
Then if we want the psi_{1212} amplitude (the up, down, up, down amplitude) for that wavefunction we can do:
auto amp = psi.A(1)*setElt(sites(1)(1));
amp *= psi.A(2)*setElt(sites(2)(2));
amp *= psi.A(3)*setElt(sites(3)(1));
amp *= psi.A(4)*setElt(sites(4)(2));
Print(amp.real());
Here recall that "sites" is a site set object (a SpinHalf object in this example) that retrieves for us the site indices that the MPS uses. The setElt function is given an "IndexVal" (an index set t to a specific value) and makes an ITensor with a "1" entry for that index value and "0" entry otherwise.
I think if you write out the tensor diagram for the above code it should be apparent what it does, and you can generalize it to an MPS of size "N" by doing steps 2,3,..., N inside a for loop.
Let me know if you have more questions about it.
(Oh and you might want to do amp.cplx() if you expect the amplitude to be complex.)
Miles