Skip to content

Commit

Permalink
Merge pull request #856 from AlgebraicJulia/export-named-graphs
Browse files Browse the repository at this point in the history
Export named graphs from `Catlab.Graphs`
  • Loading branch information
epatters authored Sep 29, 2023
2 parents f4f9182 + 1ca141d commit a8e1539
Show file tree
Hide file tree
Showing 10 changed files with 140 additions and 65 deletions.
7 changes: 4 additions & 3 deletions src/categorical_algebra/FinCats.jl
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,14 @@ using DataStructures: IntDisjointSets, in_same_set, num_groups
using ACSets
using ...GATs
import ...GATs: equations
using ...Theories: ThCategory, ThSchema, ThPointedSetCategory, ThPointedSetSchema, ObExpr, HomExpr, AttrExpr, AttrTypeExpr, FreeSchema, FreePointedSetCategory, zeromap
using ...Theories: ThCategory, ThSchema, ThPointedSetCategory, ThPointedSetSchema,
ObExpr, HomExpr, AttrExpr, AttrTypeExpr, FreeSchema, FreePointedSetCategory, zeromap
import ...Theories: dom, codom, id, compose, ,
using ...Graphs
import ...Graphs: edges, src, tgt, enumerate_paths
import ...Graphs.BasicGraphs: vertex_named, vertex_name, DiagramGraph, edge_named, edge_name
@reexport using ..Categories
import ..Categories: CatSize, ob, hom, ob_map, hom_map, component, op

# Categories
############

Expand Down Expand Up @@ -110,7 +111,7 @@ hom generators are indexable, other
than one explicitly generated by a graph.
"""
function graph(C::FinCat)
g = DiagramGraph()
g = NamedGraph{Symbol,Symbol}()
obgens = ob_generators(C)
homgens = hom_generators(C)
add_vertices!(g,length(obgens);vname=nameof.(obgens))
Expand Down
7 changes: 2 additions & 5 deletions src/categorical_algebra/FunctorialDataMigrations.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,19 @@ export SigmaMigration, DeltaMigration, migrate, migrate!,
internal_hom, SigmaMigrationFunctor, DeltaMigrationFunctor,
DataMigrationFunctor, functor

#maybe should only define DeltaMigrationFunctor at this point
using MLStyle: @match

using ACSets
using ACSets.DenseACSets: constructor, datatypes
using ...GATs
using ...Theories: ob, hom, dom, codom, attr, AttrTypeExpr,
using ..Categories, ..FinCats, ..Limits, ..Diagrams, ..FinSets, ..CSets, ..HomSearch
using ...Graphs, ..FreeDiagrams
using ...Graphs.BasicGraphs: NamedGraph, vertex_named
import ..Categories: ob_map, hom_map
import ...GATs: functor
using ..FinCats: make_map, mapvals, presentation_key
using ..Diagrams
import ..FinCats: FinCatPresentation
using ..Chase: collage, crel_type, pres_to_eds, add_srctgt, chase
using ..FinSets: VarSet
using MLStyle: @match

# Data types
############
Expand Down
43 changes: 10 additions & 33 deletions src/graphs/BasicGraphs.jl
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
""" Data structures for graphs, based on C-sets.
Provides the category theorist's four basic kinds of graphs: graphs (aka
directed multigraphs), symmetric graphs, reflexive graphs, and symmetric
reflexive graphs. Also defines half-edge graphs. The API generally follows that
of [Graphs.jl](https://github.com/JuliaGraphs/Graphs.jl), with some departures
due to differences between the data structures.
This module provides the category theorist's four basic kinds of graphs: graphs
(aka directed multigraphs), symmetric graphs, reflexive graphs, and symmetric
reflexive graphs. It also defines half-edge graphs, which are isomorphic to
symmetric graphs, and a few standard kinds of attributed graphs, such as
weighted graphs.
The graphs API generally follows that of
[Graphs.jl](https://github.com/JuliaGraphs/Graphs.jl), with some departures due
to differences between the data structures.
"""
module BasicGraphs
export HasVertices, HasGraph, AbstractGraph, Graph, SchGraph,
Expand Down Expand Up @@ -117,6 +121,7 @@ has_vertex(g::HasVertices, v) = has_part(g, :V, v)
""" Whether the graph has the given edge, or an edge between two vertices.
"""
has_edge(g::HasGraph, e) = has_part(g, :E, e)

function has_edge(g::HasGraph, s::Int, t::Int)
(1 <= s <= nv(g)) || return false
for e in outedges(g,s)
Expand Down Expand Up @@ -572,32 +577,4 @@ function Base.reverse!(g::G) where G<:HasGraph
end
Base.reverse(g::G) where G<:HasGraph = g |> deepcopy |> reverse!

vertex_name(G::HasGraph, v) = v
edge_name(G::HasGraph, e) = e

@present SchNamedGraph <: SchGraph begin
VName::AttrType
EName::AttrType
vname::Attr(V, VName)
ename::Attr(E, EName)
end

""" Abstract type for graph with named vertices and edges.
"""
@abstract_acset_type AbstractNamedGraph <: AbstractGraph

""" Graph with named vertices and edges.
The default graph type used to construct the graph underlying
a finite category given by a presentation.
"""
@acset_type NamedGraph(SchNamedGraph, index=[:src,:tgt,:ename],
unique_index=[:vname]) <: AbstractNamedGraph
vertex_name(g::AbstractNamedGraph, args...) = subpart(g, args..., :vname)
edge_name(g::AbstractNamedGraph, args...) = subpart(g, args..., :ename)

vertex_named(g::AbstractNamedGraph, name) = only(incident(g, name, :vname))
edge_named(g::AbstractNamedGraph, name)= only(incident(g, name, :ename))
const DiagramGraph = NamedGraph{Symbol,Symbol}


end # module
2 changes: 1 addition & 1 deletion src/graphs/Searching.jl → src/graphs/GraphSearching.jl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module Searching
module GraphSearching
export bfs_parents, bfs_tree, dfs_parents, dfs_tree

using ACSets
Expand Down
6 changes: 4 additions & 2 deletions src/graphs/Graphs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,18 @@ using Reexport

include("BasicGraphs.jl")
include("BipartiteGraphs.jl")
include("NamedGraphs.jl")
include("PropertyGraphs.jl")
include("GraphAlgorithms.jl")
include("GraphGenerators.jl")
include("Searching.jl")
include("GraphSearching.jl")

@reexport using .BasicGraphs
@reexport using .BipartiteGraphs
@reexport using .NamedGraphs
@reexport using .PropertyGraphs
@reexport using .GraphAlgorithms
@reexport using .GraphGenerators
@reexport using .Searching
@reexport using .GraphSearching

end
69 changes: 69 additions & 0 deletions src/graphs/NamedGraphs.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
""" Extends the basic graph types with vertex and/or edge names.
Naming vertices and edges and looking them up by name is a common requirement.
This module provides a simple interface and default graph types for named
graphs. Names are understood to be unique within the graph but are *not* assumed
to be strings or symbols.
"""
module NamedGraphs
export vertex_name, edge_name, vertex_named, edge_named,
AbstractNamedGraph, NamedGraph

using ACSets
using ...GATs, ..BasicGraphs

# Names interface
#################

""" Name of a vertex in a graph.
By default, the name of a vertex is its ID.
"""
vertex_name(g::HasVertices, v) = v

""" Name of an edge in a graph.
By default, the name of an edge is its ID.
"""
edge_name(g::HasGraph, e) = e

""" Get vertex in graph with given name.
"""
function vertex_named(g::HasVertices, name)
@assert has_vertex(g, name)
name
end

""" Get edge in graph with given name.
"""
function edge_named(g::HasGraph, name)
@assert has_edge(g, name)
name
end

# Named graphs
##############

@present SchNamedGraph <: SchGraph begin
VName::AttrType
EName::AttrType
vname::Attr(V, VName)
ename::Attr(E, EName)
end

""" Abstract type for graph with named vertices and edges.
"""
@abstract_acset_type AbstractNamedGraph <: AbstractGraph

""" Graph with named vertices and edges.
"""
@acset_type NamedGraph(SchNamedGraph, index=[:src,:tgt,:ename],
unique_index=[:vname]) <: AbstractNamedGraph

vertex_name(g::AbstractNamedGraph, args...) = subpart(g, args..., :vname)
edge_name(g::AbstractNamedGraph, args...) = subpart(g, args..., :ename)

vertex_named(g::AbstractNamedGraph, name) = only(incident(g, name, :vname))
edge_named(g::AbstractNamedGraph, name)= only(incident(g, name, :ename))

end
13 changes: 0 additions & 13 deletions test/graphs/GraphAlgorithms.jl
Original file line number Diff line number Diff line change
Expand Up @@ -72,17 +72,4 @@ ep = enumerate_paths(g)
(2, 3, [3])
(3, 3, [])]

# Trees
#######

g = Searching.tree([1, 1, 1, 2, 2])
g′ = @acset Graph begin
V = 5
E = 4
src = [1, 1, 2, 2]
tgt = [2, 3, 4, 5]
end

@test is_isomorphic(g,g′)

end
25 changes: 17 additions & 8 deletions test/graphs/Searching.jl → test/graphs/GraphSearching.jl
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
module TestSearching
module TestGraphSearching
using Test

using Catlab.Graphs.BasicGraphs, Catlab.Graphs.Searching
import Catlab.Graphs.Searching: tree

# Tests stolen from Graphs.jl
using Catlab.Graphs.BasicGraphs, Catlab.Graphs.GraphSearching
using Catlab.Graphs.GraphSearching: tree
using Catlab.CategoricalAlgebra: @acset, is_isomorphic

# BFS
#----
Expand All @@ -24,8 +23,7 @@ parents = bfs_parents(g, 1)
t1 = @inferred(bfs_tree(g, 1))
t2 = tree(parents)
@test t1 == t2
@test is_directed(t2)
@test typeof(t2) <: AbstractGraph
@test t2 isa AbstractGraph
@test ne(t2) < nv(t2)

# DFS
Expand All @@ -36,6 +34,17 @@ add_edges!(g, [1,2,1,3], [2,3,3,4])
z = @inferred(dfs_tree(g, 1))
@test ne(z) == 3 && nv(z) == 4
@test !has_edge(z, 1, 3)
@test !is_cyclic(g)

# Trees
#------

g = tree([1, 1, 1, 2, 2])
g′ = @acset Graph begin
V = 5
E = 4
src = [1, 1, 2, 2]
tgt = [2, 3, 4, 5]
end
@test is_isomorphic(g, g′)

end
8 changes: 8 additions & 0 deletions test/graphs/Graphs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ end
include("BipartiteGraphs.jl")
end

@testset "NamedGraphs" begin
include("NamedGraphs.jl")
end

@testset "PropertyGraphs" begin
include("PropertyGraphs.jl")
end
Expand All @@ -22,4 +26,8 @@ end
include("GraphGenerators.jl")
end

@testset "GraphSearching" begin
include("GraphSearching.jl")
end

end
25 changes: 25 additions & 0 deletions test/graphs/NamedGraphs.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
module TestNamedGraphs
using Test

using Catlab.Graphs

# Basic graphs
##############

g = path_graph(Graph, 3)
@test vertex_name(g, 2) == 2
@test vertex_named(g, 2) == 2
@test edge_name(g, 1) == 1
@test edge_named(g, 1) == 1

# Named graphs
##############

g = path_graph(NamedGraph{Symbol,Symbol}, 3,
V=(vname=[:x,:y,:z],), E=(ename=[:f,:g],))
@test vertex_name(g, 2) == :y
@test vertex_named(g, :y) == 2
@test edge_name(g, 1) == :f
@test edge_named(g, :f) == 1

end

0 comments on commit a8e1539

Please sign in to comment.