# Copying MPS into vector

+1 vote

Hi,
In order to compute the excited states there is a formula described here
https://www.itensor.org/docs.cgi?vers=cppv3&page=formulas/excited_dmrg
which mentions that we need a std::vector that contains the states that should be orthogonal to the excited state.

In the code it is done by

auto wfs = std::vector<MPS>(1);
wfs.at(0) = psi0;


Doesn't this copy psi0 into wfs? If this is true, then this is expensive for large MPS so what is the best way to get around this? Perhaps starting with a vector already containing psi0 and then modifying its value through the original dmrg that finds the ground state is the better way?

Thanks for the help.

commented by (8.5k points)
My understanding is that the MPS is copied, but it is not a "deep" copy, in that the ITensor data contained in the MPS is not copied. ITensors use "copy on write", so if you copy an ITensor, the data is not copied until you try to modify the new ITensor. So "copying" an MPS should just involve make a vector of pointers that point to the ITensor data, and should be very fast. Miles can correct me if I am wrong here.

Also, compared to the time of actually running DMRG to get the excited state, even if all of the data of the MPS was copied, I doubt it would add a noticeable amount of time (keep in mind that copying all of the data would be O(m^2) for an MPS of bond dimension m, but DMRG is O(m^3)). For things like this, it is helpful to add timers and do profiling to time parts of the code.

Hi, I’d recommend Matt’s answer above as the correct one:

1) yes, the copy of an MPS does not copy the data right away. (Actually this is true even at the ITensor level, so applies to any container holding ITensors too.) So the copying only happens at the last possible minute, when you modify one of the MPS tensors and then have to copy it anyway.

2) most important is what Matt said about the timing. It’s not slow to copy data, or to do any operation, unless you can measure that it takes a significant percentage of your code’s running time. So if your code copies MPS thousands of times, or if the MPS itself is on a system with thousands of sites or has a bond dimension in the 10’s of thousands, then it might be a slow part of your code. But otherwise it should take probably only a handful of microseconds or at worst milliseconds at most for normal MPS sizes.

Please let us know if you are able to measure a slowdown of your code that is due to copying MPS and we can discuss ways to mitigate it in that case.

Best,
Miles

commented by (220 points)
Thanks for the reply. I was more worried about the use of memory for having multiple (unnecessary) copies of the MPS. As Matt and you mentioned copying just once shouldn't be much of an issue.
commented by (46.8k points)
No problem. Overall I think it shouldn’t be a big concern unless you are finding that you are getting low on memory resources or if copying is taking a lot of the runtime of the program (which you’d see here because DMRG would take a long time to start if so).

But also ITensor goes to pretty great lengths underneath to avoid copies. Copying an ITensor only copies information like the indices and a (shared) pointer to the data. The actual data doesn’t get copied until you do an in-place operation like the *= operator times a scalar. So for the excited-state DMRG code, because the previous MPS are used in a read-only way, I imagine their data never actually gets copied at all!

Best,
Miles