It sounds like you are trying to pass the ITensor M
as the operator directly to eigsolve. If that is the case, we have not defined the operation M(v)
, since it is not clear what the definition of that should be in general (it makes sense if ITensor M has pairs of primed and unprimed indices, but doesn't for other ITensors). I had been considering defining M(v)
for certain kinds of ITensors, but we were being conservative about it to start out.
In the meantime, you can define your own callable ITensor wrapper, which here I call an ITensorMap:
using ITensors
using KrylovKit
i = Index(2)
M = randomITensor(i', dag(i))
v0 = randomITensor(i)
# λs, vs = eigsolve(M, v0)
# Gives:
# ERROR: MethodError: objects of type ITensor{2} are not callable
struct ITensorMap
A::ITensor
end
(M::ITensorMap)(v::ITensor) = noprime(M.A * v)
λs, vs = eigsolve(ITensorMap(M), v0)
@show norm(noprime(M * vs[1]) - vs[1] * λs[1])
This will be a way to test if you are making your custom projected MPO correctly.
However, in general, it is not as efficient to form the operator and then contract it with the ITensor v
. Instead, you should define something like the ProjMPO that contains the ITensors of the projected Hamiltonian you are interested in (in your case, H[1], H[N], and then the contraction of the bulk tensors 2...N-1), and define your own function like the product function here:
https://github.com/ITensor/ITensors.jl/blob/master/src/mps/projmpo.jl#L71
which takes the ITensor "vector" and applies the appropriate tensors. In the end the two approaches are equivalent, but the order of contraction is different, which can make a big difference in the efficiency of your algorithm.