-
Notifications
You must be signed in to change notification settings - Fork 3
ITensorNetwork type fixes and other minor refactors. #175
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
base: main
Are you sure you want to change the base?
Changes from all commits
35e491e
25b18fa
5dc2aeb
9e57b58
fc2b71f
0c59060
01b76ee
511703e
d9db486
7ca1852
5b277f3
112b78c
0bc2b8f
4482a48
48534f9
1ed3f96
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 |
|---|---|---|
|
|
@@ -142,8 +142,10 @@ vertex_scalars(factors, messages) = vertex_scalars(factors, messages, keys(facto | |
| function vertex_scalars(factors::AbstractGraph, messages) | ||
| return vertex_scalars(factors, messages, vertices(factors)) | ||
| end | ||
| # `vertex_scalar` reads a number out of an `ITensor`, whose array field is untyped, so `map` would | ||
| # give element type `Any`; collecting the values instead picks up the type they actually have. | ||
| function vertex_scalars(factors, messages, vertices) | ||
| return map(v -> vertex_scalar(factors, messages, v), vertices) | ||
| return [vertex_scalar(factors, messages, v) for v in vertices] | ||
|
Member
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 think an issue with this version is that it now returns a Vector instead of a Dictionary, I think a Dictionary is a bit nicer since it preserves which scalar is associated with which vertex. Maybe we could do
Member
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. Ah, I see, I guess before it would have output whatever narrow_map(f, v) = map(f, v)
narrow_map(f, v::AbstactIndices) = dictionary(v, [f(x) for x in v])
Contributor
Author
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. The problem with |
||
| end | ||
|
|
||
| function edge_scalar(cache, edge) | ||
|
|
@@ -153,45 +155,49 @@ end | |
| edge_scalars(cache) = edge_scalars(cache, keys(cache)) | ||
|
|
||
| function edge_scalars(cache, edges) | ||
| processed = Set{eltype(edges)}() | ||
|
|
||
| T = Base.promote_op(edge_scalar, typeof(cache), eltype(edges)) | ||
|
|
||
| scalars = T[] | ||
| unique_edges = Indices{eltype(edges)}() | ||
|
|
||
| # Ignore repeated edges and their reverses. | ||
| for e in edges | ||
| if e in processed || reverse(e) in processed | ||
| if e in unique_edges || reverse(e) in unique_edges | ||
| continue | ||
| end | ||
| push!(processed, e) | ||
| push!(scalars, edge_scalar(cache, e)) | ||
| insert!(unique_edges, e) | ||
| end | ||
|
|
||
| return scalars | ||
| return [edge_scalar(cache, e) for e in unique_edges] | ||
| end | ||
|
|
||
| function region_scalar(factors, messages, region) | ||
| return mapreduce(vertex -> vertex_scalar(factors, messages, vertex), *, region) | ||
| end | ||
|
|
||
| # (log|∏terms|, sign(∏terms)) | ||
| function sumlogabs(terms) | ||
| T = eltype(terms) | ||
|
|
||
| return mapreduce( | ||
| t -> (log(abs(t)), sign(t)), | ||
| ((d1, s1), (d2, s2)) -> (d1 + d2, s1 * s2), | ||
| terms; init = (zero(float(real(T))), one(T)) | ||
| ) | ||
| end | ||
|
|
||
| function sumlog(terms) | ||
| d, s = sumlogabs(terms) | ||
| return s isa Real && s > 0 ? d : d + log(complex(s)) | ||
| end | ||
|
|
||
| # We need a graph structure here, so assume `factors` is a graph. | ||
| function bethe_free_energy(factors, messages) | ||
| numerator_terms = vertex_scalars(factors, messages) | ||
| denominator_terms = edge_scalars(messages) | ||
|
|
||
| if any(t -> real(t) < 0, numerator_terms) | ||
| numerator_terms = complex.(numerator_terms) | ||
| end | ||
| if any(t -> real(t) < 0, denominator_terms) | ||
| denominator_terms = complex.(denominator_terms) | ||
| end | ||
|
|
||
| if any(iszero, denominator_terms) | ||
| return -Inf | ||
| end | ||
|
|
||
| return sum(log.(numerator_terms)) - sum(log.(denominator_terms)) | ||
| return sumlog(numerator_terms) - sumlog(denominator_terms) | ||
| end | ||
|
|
||
| # ===================================== NormNetwork ====================================== # | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -116,38 +116,60 @@ DataGraphs.is_edge_assigned(::ITensorNetwork, _edge) = false | |||||
|
|
||||||
| DataGraphs.get_vertex_data(tn::ITensorNetwork, v) = tn.tensors[v] | ||||||
|
|
||||||
| function check_input(::typeof(set_vertex_data!), tn, tensor, vertex) | ||||||
| for name in dimnames(tensor) | ||||||
| vertices = get(tn.dimname_vertices, name, Set()) | ||||||
| if length(setdiff(vertices, Set([vertex]))) > 1 | ||||||
| throw( | ||||||
| ArgumentError( | ||||||
| "index $name can appear in at most one existing tensor" | ||||||
| ) | ||||||
| ) | ||||||
| end | ||||||
| end | ||||||
| return nothing | ||||||
| end | ||||||
|
|
||||||
| function DataGraphs.insert_vertex_data!(tn::ITensorNetwork, vertex, tensor) | ||||||
| check_input(set_vertex_data!, tn, tensor, vertex) | ||||||
| add_vertex!(tn.underlying_graph, vertex) | ||||||
| set!_tensornetwork(tn, vertex, tensor) | ||||||
| update_tensornetwork_metadata!(tn, vertex, tensor) | ||||||
| insert!(tn.tensors, vertex, tensor) | ||||||
| return tn | ||||||
| end | ||||||
|
|
||||||
| function DataGraphs.set_vertex_data!(tn::ITensorNetwork, tensor, vertex) | ||||||
| set!_tensornetwork(tn, vertex, tensor) | ||||||
| check_input(set_vertex_data!, tn, tensor, vertex) | ||||||
| update_tensornetwork_metadata!(tn, vertex, tensor) | ||||||
| set!(tn.tensors, vertex, tensor) | ||||||
| return tn | ||||||
| end | ||||||
|
|
||||||
| # "upsert" | ||||||
| function set!_tensornetwork(tn::ITensorNetwork, vertex, tensor) | ||||||
| newinds = dimnames(tensor) | ||||||
| function update_tensornetwork_metadata!(tn, vertex, tensor) | ||||||
| oldnames = isassigned(tn, vertex) ? dimnames(tn[vertex]) : Set() | ||||||
|
Member
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
|
||||||
| newnames = dimnames(tensor) | ||||||
|
|
||||||
| oldinds = get(mapview(dimnames, tn.tensors), vertex, Set()) | ||||||
| update_tensornetwork_metadata!(tn, vertex, oldnames, newnames) | ||||||
|
|
||||||
| return tn | ||||||
| end | ||||||
|
|
||||||
| function update_tensornetwork_metadata!(tn, vertex, oldnames, newnames) | ||||||
| # Only have to deal with the indices that aren't shared. | ||||||
| for ind in symdiff(oldinds, newinds) | ||||||
| if ind in oldinds | ||||||
| delete_ind_edge!(tn, ind) | ||||||
| delete_ind_vertex!(tn, ind, vertex) | ||||||
| for name in symdiff(oldnames, newnames) | ||||||
| if name in oldnames | ||||||
| delete_ind_edge!(tn, name) | ||||||
| delete_ind_vertex!(tn, name, vertex) | ||||||
| continue | ||||||
| end | ||||||
|
|
||||||
| # Now `ind` must be a new index that's not in `oldinds` | ||||||
| # Now `name` must be a new index that's not in `oldinds` | ||||||
|
|
||||||
| vertex_list = get!(tn.dimname_vertices, ind, Set()) | ||||||
| vertex_list = get!(tn.dimname_vertices, name, Set()) | ||||||
| if length(vertex_list) > 1 | ||||||
| throw( | ||||||
| ArgumentError( | ||||||
| "index $ind can appear in at most one existing tensor, got $(length(vertex_list))." | ||||||
| "index $name can appear in at most one existing tensor, got $(length(vertex_list))." | ||||||
| ) | ||||||
| ) | ||||||
| end | ||||||
|
|
@@ -160,8 +182,6 @@ function set!_tensornetwork(tn::ITensorNetwork, vertex, tensor) | |||||
| end | ||||||
| end | ||||||
|
|
||||||
| set!(tn.tensors, vertex, tensor) | ||||||
|
|
||||||
| return tn | ||||||
| end | ||||||
|
|
||||||
|
|
@@ -171,20 +191,14 @@ function DataGraphs.underlying_graph_type(type::Type{<:ITensorNetwork{T, V}}) wh | |||||
| return fieldtype(type, :underlying_graph) | ||||||
| end | ||||||
|
|
||||||
| function Graphs.rem_edge!(::ITensorNetwork, _edge) | ||||||
| return throw( | ||||||
| ErrorException("removing edges from the `ITensorNetwork` type is not supported.") | ||||||
| ) | ||||||
| end | ||||||
|
|
||||||
| function Graphs.add_edge!(::ITensorNetwork, _edge) | ||||||
| return throw( | ||||||
| ErrorException("Adding edges to the `ITensorNetwork` type is not supported.") | ||||||
| ) | ||||||
| end | ||||||
| # Can't add/remove edges from `ITensorNetwork` as graph topology fixed by indices. | ||||||
| Graphs.rem_edge!(::ITensorNetwork, _edge) = false | ||||||
| Graphs.add_edge!(::ITensorNetwork, _edge) = false | ||||||
|
|
||||||
| # PERF: fast lookup compared to `AbstractITensorNetwork` fallback. | ||||||
| dimnamevertices(tn::ITensorNetwork, name) = tn.dimname_vertices[name] | ||||||
| function dimnamevertices(tn::ITensorNetwork, name) | ||||||
| return get(tn.dimname_vertices, name, Set{vertextype(tn)}()) | ||||||
|
Member
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 think this makes more sense, but was this inspired by a particular use case?
Contributor
Author
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. It is for consistency with the fallback method (which returns an empty set). |
||||||
| end | ||||||
|
|
||||||
| # PERF: fast lookup compared to `AbstractITensorNetwork` fallback. | ||||||
| has_dimname(tn::ITensorNetwork, name) = haskey(tn.dimname_vertices, name) | ||||||
|
|
||||||
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.
Maybe use
Dictionaries.Indices?