Skip to content

New interface for GraphsExtensions.similar_graph; misc bug fixes.#147

Open
jack-dunham wants to merge 16 commits intoITensor:mainfrom
jack-dunham:main
Open

New interface for GraphsExtensions.similar_graph; misc bug fixes.#147
jack-dunham wants to merge 16 commits intoITensor:mainfrom
jack-dunham:main

Conversation

@jack-dunham
Copy link
Contributor

@jack-dunham jack-dunham commented Mar 13, 2026

qThis PR overhauls the way the GraphsExtensions.similar_graph function behaves, and includes some minor bug fixes and refactors.

New similar_graph interface

Essentially, the base case is now the three argument method, where one provides both vertices and edges. This defaults to constructing a concrete NamedGraph or NamedDiGraph depending on the IsDirected trait of the input graph.

similar_graph(::AbstractGraph::!(IsDirected), vertices, edges) # -> NamedGraph
similar_graph(::AbstractGraph::IsDirected, vertices, edges) # -> NamedDiGraph

If edges are not provided, then the function attempts to construct a similar graph to the input graph, but with the provided vertices and no edges. If no vertices or edges are provided, then the output graph will be a similar graph with the same vertices and edges. For a given subtype of AbstractNamedGraph, one should overload the three argument method only (if a different return type is desired).

Type domain

If instead a graph type is provided as the first argument to similar_graph, then the constructor is called by default:

similar_graph(T::Type{<:AbstractGraph})  = T()
similar_graph(T::Type{<:AbstractGraph}, vertices)  = T(vertices)
similar_graph(T::Type{<:AbstractGraph}, vertices, edges)  = add_edges!(similar_graph(T, vertices), edges)

Note, unlike the case where a graph value is provided, the one argument method is not defined in terms of the two or three argument method. This is to accommodate cases where a given AbstractGraph may have fixed edges, say (a notable example would be a tree graph). In that case, it is assumes there exists a constructor T(vertices). As the method

similar_graph(T::Type{<:AbstractGraph}, vertices)  = T(vertices)

may or may not return an edgeless graph, depending on the definition of the constructor.
In light of this, there now exists the function

edgeless_graph(T::Type{<:AbstractGraph}, vertices)

that attempts to explicitly a construct an edgeless graph, thus throwing an error when this is not possible. Likewise, there exists a function

empty_graph(T::Type{<:AbstractGraph})

for explicitly constructing a graph of type T with no vertices or edges.

If your graph type MyGraph has freedom over vertices and edges, all three type-based method can be overloaded simultaneously using the followings signature:

similar_graph(T::Type{<:MyGraph}, vertices = [], edges = [])  = ...

@mtfishman
Copy link
Member

Likewise, there exists a function

empty_graph(T::Type{<:AbstractGraph}, vertices)

for explicitly constructing a graph of type T with no vertices or edges.

Is that supposed to be:

empty_graph(T::Type{<:AbstractGraph})

?

@mtfishman
Copy link
Member

mtfishman commented Mar 18, 2026

If no vertices or edges are provided, then the output graph will be a similar empty graph.

I thought we had decided it would be a graph with the same vertices and edges as the input graph (in the case where a graph instance is input)? That would be analogous to similar of SparseArrays:

julia> using SparseArrays

julia> a = sprandn(5, 5, 0.5)
5×5 SparseMatrixCSC{Float64, Int64} with 13 stored entries:
                     -0.313373         
            0.360588  -2.40419       -0.885288
 -0.538721  -1.59639                  2.41016
 -1.25074             -0.652935         
 -2.0638    -0.512399   2.09563       -1.35611

julia> similar(a)
5×5 SparseMatrixCSC{Float64, Int64} with 13 stored entries:
                           2.27785e-314        
              2.76437e-314  2.27785e-314      2.27785e-314
 2.27785e-314  2.20064e-314                   2.76437e-314
 2.27785e-314               2.27785e-314        
 2.27785e-314  2.27785e-314  2.27785e-314      2.76437e-314

EDIT: I think I see that is how it is implemented, so maybe it is just that the description in the first post is outdated.

@jack-dunham
Copy link
Contributor Author

jack-dunham commented Mar 18, 2026

If no vertices or edges are provided, then the output graph will be a similar empty graph.

I thought we had decided it would be a graph with the same vertices and edges as the input graph (in the case where a graph instance is input)? That would be analogous to similar of SparseArrays:

julia> using SparseArrays

julia> a = sprandn(5, 5, 0.5)
5×5 SparseMatrixCSC{Float64, Int64} with 13 stored entries:
                     -0.313373         
            0.360588  -2.40419       -0.885288
 -0.538721  -1.59639                  2.41016
 -1.25074             -0.652935         
 -2.0638    -0.512399   2.09563       -1.35611

julia> similar(a)
5×5 SparseMatrixCSC{Float64, Int64} with 13 stored entries:
                           2.27785e-314        
              2.76437e-314  2.27785e-314      2.27785e-314
 2.27785e-314  2.20064e-314                   2.76437e-314
 2.27785e-314               2.27785e-314        
 2.27785e-314  2.27785e-314  2.27785e-314      2.76437e-314

EDIT: I think I see that is how it is implemented, so maybe it is just that the description in the first post is outdated.

Sorry this is my mistake in the post description. It should construct a graph with the same vertices and edges. I've updated the head comment.

@mtfishman
Copy link
Member

(I closed and reopened the PR to try to trigger the CI again, I'm trying to fix the docs build.)

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