-
Notifications
You must be signed in to change notification settings - Fork 125
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[NDTensors] [BUG] Incorrect result when contracting off-diagonal DiagBlockSparse with BlockSparse #1474
Comments
Interesting, thanks for reporting. I guess that type of contraction doesn't show up much in ITensor code or else I assume it would have been reported, though it seems like a pretty basic contraction. Maybe it doesn't come up much because it is a full contraction over all of the indices as opposed to a contraction that is more like a matrix multiplication. |
@kmp5VT one issue with the contraction you tried is that I think there is an implicit assumption in parts of the DiagBlockSparse code that the nonzero blocks should be on the diagonal, i.e. that it is a block diagonal tensor where the diagonal blocks are diagonal. Of course if that is an assumption in the code it should throw an error if the tensor is not block diagonal instead of silently giving wrong results, maybe we should check for that in the contract code. In practice in ITensors.jl DiagBlockSparse tensors that are constructed (say as delta tensors or resulting from an SVD) are always block diagonal so I think this issue doesn't come up for standard user code. The design of DiagBlockSparse is probably the worst part of the codebase but as you know it will be improved a lot in the NDTensors rewrite since it will just be a special type of BlockSparseArray. |
Here's a demonstration that the issue is specific to non-block diagonal using NDTensors:
BlockSparseTensor,
DiagBlockSparse,
Tensor,
blockoffsets,
contract,
dense,
nzblocks
using LinearAlgebra: norm
using Random: randn!
function main(; elt=Float64, blocks)
inds1 = ([1, 1], [1, 1])
inds2 = ([1, 1], [1, 1])
a1 = BlockSparseTensor{elt}(blocks, inds1...)
for b in nzblocks(a1)
randn!(a1[b])
end
a2 = Tensor(DiagBlockSparse(one(elt), blockoffsets(a1)), inds2)
for (labels1, labels2) in (
((1, -1), (-1, 2)),
((-1, -2), (-1, -2)),
)
r1 = dense(contract(a1, labels1, a2, labels2))
r2 = contract(dense(a1), labels1, dense(a2), labels2)
@show r1
@show r2
@show norm(r1 - r2)
end
end which gives: julia> main(; blocks=[(1, 1), (2, 2)])
r1 = [0.7390378355622387 0.0; 0.0 -1.162604903514136]
r2 = [0.7390378355622387 0.0; 0.0 -1.162604903514136]
norm(r1 - r2) = 0.0
r1 = fill(-0.42356706795189725)
r2 = fill(-0.42356706795189725)
norm(r1 - r2) = 0.0
julia> main(; blocks=[(1, 2), (2, 1)])
r1 = [0.33674473147731404 0.0; 0.0 -1.4875851680775094]
r2 = [0.0 0.33674473147731404; -1.4875851680775094 0.0]
norm(r1 - r2) = 2.1569917229613655
r1 = fill(-1.1508404366001954)
r2 = fill(0.0)
norm(r1 - r2) = 1.1508404366001954 so a good strategy for now would be to throw an error when a |
In #1475 I catch the case of off-diagonal blocks and throw an error. |
Description of bug
Minimal code demonstrating the bug or unexpected behavior
Minimal runnable code
Version information
versioninfo()
:The text was updated successfully, but these errors were encountered: