-
Notifications
You must be signed in to change notification settings - Fork 13
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
Implement inner(x,A,y)
for TTN
via BP
.
#146
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -721,6 +721,48 @@ function contract_inner( | |||||
return contract(tn; sequence)[] | ||||||
end | ||||||
|
||||||
function contract_with_BP( | ||||||
itn::AbstractITensorNetwork; outputlevel=1, partitioning=group(v -> v, vertices(itn)) | ||||||
) | ||||||
return contract_with_BP( | ||||||
ComplexF64, itn::AbstractITensorNetwork; outputlevel, partitioning | ||||||
) | ||||||
end | ||||||
|
||||||
function contract_with_BP( | ||||||
T::Type, | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm confused by this part of the interface, why can you set the element type in this way? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is not the right way to do it. Basically, due to the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok. I think |
||||||
itn::AbstractITensorNetwork; | ||||||
outputlevel=1, | ||||||
partitioning=group(v -> v, vertices(itn)), | ||||||
) | ||||||
@assert isempty(externalinds(itn)) | ||||||
bp_cache = BeliefPropagationCache(copy(itn), partitioning) | ||||||
|
||||||
bp_cache = update(bp_cache) | ||||||
|
||||||
pg = partitioned_itensornetwork(bp_cache) | ||||||
|
||||||
if !is_tree(partitioned_graph(pg)) && outputlevel > 0 | ||||||
println("Partitioned graph is not a tree, result will be approximate!!") | ||||||
end | ||||||
Comment on lines
+745
to
+747
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's remove this, I think this is inherent if someone selects that they are using BP. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, but it may be good to allow to pass a flag like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's think about the design of that, but I don't think we have to address that in this PR. I agree with the sentiment that we don't want to secretly perform approximate contractions but give users the impression that we are doing exact contractions. |
||||||
|
||||||
log_numerator, log_denominator = 0, 0 | ||||||
for pv in partitionvertices(pg) | ||||||
incoming_mts = incoming_messages(bp_cache, [pv]) | ||||||
mtfishman marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
local_state = ITensor[itn[v] for v in vertices(pg, pv)] | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can't you use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Or |
||||||
log_numerator += log(complex(ITensors.contract(vcat(incoming_mts, local_state))[])) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
end | ||||||
for pe in partitionedges(pg) | ||||||
log_denominator += log( | ||||||
complex( | ||||||
ITensors.contract(vcat(message(bp_cache, pe), message(bp_cache, reverse(pe))))[] | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
), | ||||||
) | ||||||
end | ||||||
res = exp(log_numerator - log_denominator) | ||||||
return T(res) | ||||||
end | ||||||
|
||||||
# TODO: rename `sqnorm` to match https://github.com/JuliaStats/Distances.jl, | ||||||
# or `norm_sqr` to match `LinearAlgebra.norm_sqr` | ||||||
norm_sqr(ψ::AbstractITensorNetwork; sequence) = contract_inner(ψ, ψ; sequence) | ||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -365,20 +365,14 @@ end | |
# Inner products | ||
# | ||
|
||
# TODO: implement using multi-graph disjoint union | ||
function inner( | ||
y::AbstractTTN, A::AbstractTTN, x::AbstractTTN; root_vertex=default_root_vertex(x, A, y) | ||
) | ||
traversal_order = reverse(post_order_dfs_vertices(x, root_vertex)) | ||
check_hascommoninds(siteinds, A, x) | ||
check_hascommoninds(siteinds, A, y) | ||
# TODO: Remove dispatch on AbstractTTN (unless we want to trigger warning for trees if BP is nonexact) | ||
function inner(y::AbstractTTN, A::AbstractTTN, x::AbstractTTN; kwargs...) | ||
ydag = sim(dag(y); sites=[]) | ||
x = sim(x; sites=[]) | ||
O = ydag[root_vertex] * A[root_vertex] * x[root_vertex] | ||
for v in traversal_order[2:end] | ||
O = O * ydag[v] * A[v] * x[v] | ||
end | ||
return O[] | ||
blf = BilinearFormNetwork(A, ydag, x) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think we should be using a form here, that is mostly meant for optimization. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is your goal to make a tensor network out of the network There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, as far as I understand the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok, let's do that without going through |
||
blf_scalar_bp = contract_with_BP( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we just use To handle partitioning in the more general case, something we could do is that instead of passing an |
||
tensornetwork(blf); outputlevel=1, partitioning=group(v -> first(v), vertices(blf)) | ||
) | ||
return blf_scalar_bp | ||
end | ||
|
||
# TODO: implement using multi-graph disjoint | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
using ITensors | ||
using ITensors: contract | ||
using ITensorNetworks | ||
using ITensorNetworks: contract_with_BP, group | ||
using Test | ||
|
||
@testset "TTN constructor defaulting to link_space=1" begin | ||
tooth_lengths = fill(5, 6) | ||
c = named_comb_tree(tooth_lengths) | ||
s = siteinds("S=1/2", c) | ||
d = Dict() | ||
for (i, v) in enumerate(vertices(s)) | ||
d[v] = isodd(i) ? "Up" : "Dn" | ||
end | ||
states = v -> d[v] | ||
#test a few signatures | ||
state = TTN(s, states) | ||
lds = edge_data(linkdims(state)) | ||
@test all([isone(lds[k]) for k in keys(lds)]) | ||
state = TTN(s) | ||
lds = edge_data(linkdims(state)) | ||
@test all([isone(lds[k]) for k in keys(lds)]) | ||
end | ||
|
||
@testset "Inner products for TTN via BP" begin | ||
Random.seed!(1234) | ||
Lx, Ly = 3, 3 | ||
χ = 2 | ||
g = named_comb_tree((Lx, Ly)) | ||
s = siteinds("S=1/2", g) | ||
y = TTN(randomITensorNetwork(ComplexF64, s; link_space=χ)) | ||
x = TTN(randomITensorNetwork(ComplexF64, s; link_space=χ)) | ||
|
||
A = TTN(ITensorNetworks.heisenberg(s), s) | ||
#First lets do it with the flattened version of the network | ||
xy = inner_network(x, y; combine_linkinds=true) | ||
xy_scalar = contract(xy)[] | ||
xy_scalar_bp = contract_with_BP(xy) | ||
|
||
@test_broken xy_scalar ≈ xy_scalar_bp | ||
|
||
#Now lets keep it unflattened and do Block BP to keep the partitioned graph as a tree | ||
xy = inner_network(x, y; combine_linkinds=false) | ||
xy_scalar = contract(xy)[] | ||
xy_scalar_bp = contract_with_BP(xy; partitioning=group(v -> first(v), vertices(xy))) | ||
|
||
@test xy_scalar ≈ xy_scalar_bp | ||
# test contraction of three layers for expectation values | ||
# for TTN inner with this signature passes via contract_with_BP | ||
@test inner(prime(x), A, y) ≈ | ||
inner(x, apply(A, y; nsweeps=10, maxdim=16, cutoff=1e-10, init=y)) rtol = 1e-6 | ||
end | ||
nothing |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
contract_with_BP
isn't a good function name, what about overloadingITensors.contract(::Algorithm"bp", kwargs...)
and running withcontract(itn; alg="bp", kwargs...)
.