Skip to content

Conversation

@JoeyT1994
Copy link
Collaborator

This PR changes gauge_edge(Algorithm::"orthogonalize", tn::AbstractITensorNetwork, edge, ...) and truncate(tn::AbstractITensorNetwork, edge, ...) to use graph preserving updates of the tn::AbstractITensorNetwork to improve their efficiency.

The current use of orthogonalize(...) in alternating_update (now sweep_solver in NetworkSolvers) involves rechecking the graph structure every time gauge_edge is called and thus invokes an O(L) time complexity call in a step that should be O(1) where L is the system-size.

It is not clear to me there is a case where these operations should re-check the graph structure as they implicitly conserve it from the looks of things provided the factorization is done correctly...

@emstoudenmire @mtfishman

@mtfishman
Copy link
Member

Makes sense to me, I think it is fair to assume they preserve the graph.

The only case I could imagine is if the edge isn't actually in the graph originally. It would be strange to gauge along a non-existent edge, so probably we should check for that case in those functions and users will have to manually add edges they want to gauge/truncate along if they don't exist yet. Can you add a check in those functions you modified that the edge exists in the graph?

@JoeyT1994
Copy link
Collaborator Author

Agreed it would be strange to gauge on a non-existing edge. I added a check based on the neighbors of dst(edge) so the check doesn't scale with system size.

@mtfishman
Copy link
Member

I added a check based on the neighbors of dst(edge) so the check doesn't scale with system size.

I think if you use has_edge(g, e) (or e in edges(g), which should call has_edge: https://juliagraphs.org/Graphs.jl/stable/core_functions/interface/#Graphs.has_edge-Tuple%7BAny,%20Any,%20Any%7D though we should double check that for NamedGraphs.jl) it should be O(1). If it isn't we should fix that, since in principle you can implement it by checking the neighbors of the source or destination vertex of the edge.

@JoeyT1994
Copy link
Collaborator Author

I changed it to has_edge(g, e) which (from my testing) appears to also be system-size independent in terms of time and memory allocations.
e in edges(g) does appear to scale with system-size and also is dependent on the order of the edges. I guess it's not calling has_edge but is just checking e against the whole list of edges?

@mtfishman
Copy link
Member

I changed it to has_edge(g, e) which (from my testing) appears to also be system-size independent in terms of time and memory allocations. e in edges(g) does appear to scale with system-size and also is dependent on the order of the edges. I guess it's not calling has_edge but is just checking e against the whole list of edges?

Thanks for checking, good to know. Graphs.jl can make e in edges(g) call has_edge for SimpleGraph because edges(::SimpleGraph) outputs a special type (https://github.com/JuliaGraphs/Graphs.jl/blob/v1.12.1/src/SimpleGraphs/simpleedgeiter.jl#L119), while edges(::NamedGraph) outputs an arbitrary collection. We should raise an issue about that in NamedGraphs.jl.

@mtfishman mtfishman merged commit 43f3272 into ITensor:main May 13, 2025
10 of 11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants