GraphCore.jl User Guide
A high-performance, type-safe graph library for Julia with a focus on efficiency, flexibility, and ease of use.
GraphCore.jl provides multiple specialized graph data structures optimized for different use cases - from static analysis with CoreGraph's compressed storage to dynamic construction with AdjGraph's adjacency lists. All graph types support efficient mutations, type-safe properties, and seamless integration with the Graphs.jl ecosystem, allowing you to use existing algorithms while benefiting from GraphCore's performance optimizations.
Quick Start
using GraphCore
# Create your first graph
edges = [(1,2), (2,3), (1,3)]
g = build_core_graph(edges; directed=false)
# Query the graph
println("Graph has $(num_vertices(g)) vertices and $(num_edges(g)) edges")
println("Neighbors of vertex 1: $(collect(neighbor_indices(g, 1)))")Installation
using Pkg
Pkg.add("GraphCore")For optional features:
# For benchmarking examples
Pkg.add("BenchmarkTools")
# For plotting examples
Pkg.add(["Plots", "GraphRecipes"])Graph Types Overview
GraphCore provides four main graph types, each optimized for different use cases:
CoreGraph - High-Performance Static Analysis
# Best for: Fast queries, analysis algorithms, memory efficiency
g = build_core_graph([(1,2), (2,3), (1,3)]; directed=false)
# Fast neighbor access
for neighbor in neighbor_indices(g, 1)
println("Neighbor: $neighbor")
end
# Efficient mutations
add_edge!(g, 1, 4)
add_vertex!(g)WeightedGraph - Graphs with Edge Weights
# Best for: Algorithms needing edge weights (shortest paths, MST, etc.)
edges = [(1,2), (2,3), (1,3)]
weights = [1.0, 2.5, 1.2]
wg = build_weighted_graph(edges, weights; directed=false)
# Access weights efficiently
for (neighbor, weight) in neighbor_weights(wg, 1)
println("Edge to $neighbor has weight $weight")
end
# Add weighted edges
add_edge!(wg, 1, 4, 3.7)PropertyGraph - Graphs with Custom Data
# Best for: Attaching custom data to vertices and edges
vertices = ["Alice", "Bob", "Charlie"]
edges = [(1,2), (2,3), (1,3)]
edge_types = ["friend", "colleague", "family"]
pg = build_property_graph(edges, vertices, edge_types; directed=false)
# Access properties
println("Vertex 1 is: $(vertex_property(pg, 1))")
println("Edge (1,2) type: $(edge_property(pg, 1, 2))")AdjGraph - Dynamic Modification
# Best for: Frequent edge additions/removals during construction
g = build_adj_graph([(1,2)]; directed=false)
# Very fast mutations
add_edge!(g, 2, 3) # O(1)
add_edge!(g, 3, 4) # O(1)
remove_edge!(g, 1, 2) # O(degree)Common Workflows
Building Graphs
From edge lists:
# Simple unweighted graph
edges = [(1,2), (2,3), (3,4), (4,1)]
g = build_core_graph(edges; directed=true)
# With weights
weights = [1.0, 2.0, 1.5, 0.8]
wg = build_weighted_graph(edges, weights; directed=true)Incrementally with GraphBuilder:
using GraphCore.Builders
builder = WeightedGraphBuilder(Float64; directed=false)
add_edge!(builder, 1, 2; weight=1.5)
add_edge!(builder, 2, 3; weight=2.0)
add_edge!(builder, 1, 3; weight=1.0)
# Convert to your preferred graph type
core_g = build_graph(builder, CoreGraph) # For analysis
adj_g = build_graph(builder, AdjGraph) # For further modificationsFrom other graph libraries:
using GraphCore.Conversions
using Graphs
# From Graphs.jl
simple_g = SimpleGraph(5)
add_edge!(simple_g, 1, 2)
our_g = from_graphs_jl(simple_g)
# To Graphs.jl
graphs_g = to_graphs_jl(our_g)Graph Analysis
Basic queries:
g = build_core_graph([(1,2), (2,3), (1,3)]; directed=false)
# Graph properties
println("Vertices: $(num_vertices(g))")
println("Edges: $(num_edges(g))")
println("Directed: $(is_directed(g))")
# Vertex queries
println("Degree of vertex 1: $(degree(g, 1))")
println("Neighbors: $(collect(neighbor_indices(g, 1)))")
# Edge queries
println("Has edge (1,2): $(has_edge(g, 1, 2))")Iteration patterns:
# Iterate over all vertices
for v in vertices(g)
println("Processing vertex $v")
end
# Iterate over all edges
for (u, v) in edges(g)
println("Edge: $u → $v")
end
# Iterate over neighbors efficiently
for v in vertices(g)
for neighbor in neighbor_indices(g, v)
println("$v is connected to $neighbor")
end
endUnified Edge Weight Interface
GraphCore provides a unified interface for edge weights that works seamlessly with both weighted and unweighted graphs:
# Works on ANY graph type!
unweighted_g = build_core_graph([(1,2), (1,3)]; directed=false)
weighted_g = build_weighted_graph([(1,2), (1,3)], [1.5, 2.0]; directed=false)
# edge_weight() returns 1 for unweighted graphs, actual weight for weighted graphs
println(edge_weight(unweighted_g, 1)) # → 1 (Int32)
println(edge_weight(weighted_g, 1)) # → 1.5 (Float64)
# neighbor_weights() works universally - perfect for generic algorithms!
for (neighbor, weight) in neighbor_weights(unweighted_g, 1)
println("Edge to $neighbor has weight $weight") # weight = 1 for unweighted
end
for (neighbor, weight) in neighbor_weights(weighted_g, 1)
println("Edge to $neighbor has weight $weight") # actual weights
end
# Runtime detection for algorithm optimization
if is_weighted_graph(g)
dijkstra_shortest_paths(g, source) # Use actual weights
else
bfs_shortest_paths(g, source) # More efficient for unweighted
endGraph Modification
Adding elements:
g = build_core_graph([(1,2)]; directed=false)
# Add vertices and edges
new_vertex = add_vertex!(g) # Returns vertex index
add_edge!(g, 1, new_vertex)
add_edge!(g, 2, new_vertex)
# For weighted graphs
wg = build_weighted_graph([(1,2)], [1.0]; directed=false)
add_edge!(wg, 1, 3, 2.5) # vertex 3, weight 2.5Removing elements:
# Remove edges
remove_edge!(g, 1, 2)
# Remove vertices (removes all connected edges)
remove_vertex!(g, 3)Converting Between Types
Easy conversions:
# Start with one type
adj_g = build_adj_graph([(1,2), (2,3)]; directed=false)
# Convert as needed
core_g = CoreGraph(adj_g) # For fast analysis
weighted_g = WeightedGraph(core_g) # Add weight support
property_g = PropertyGraph(core_g, ["A", "B", "C"], ["edge1", "edge2"])Type-safe conversions:
directed_g = build_core_graph([(1,2)]; directed=true)
# This prevents mistakes:
# undirected_g = CoreGraph{false}(directed_g) # Would throw error!
# Explicit conversion when you know what you're doing:
undirected_g = CoreGraph{false}(edges(directed_g)) # OKWorking with Properties
Vertex properties:
names = ["Alice", "Bob", "Charlie"]
g = build_property_graph([(1,2), (2,3)], names, String[]; directed=false)
# Access properties
println(vertex_property(g, 1)) # "Alice"
# or equivalently
println(g[1])
# Modify properties
set_vertex_property!(g, 1, "Alice Smith") # of g[1] = ...Edge properties:
edges = [(1,2), (2,3)]
edge_labels = ["friend", "colleague"]
g = build_property_graph(edges, String[], edge_labels; directed=false)
# Access edge properties
println(edge_property(g, 1, 2)) # "friend"
# or equivalently
println(g[1 => 2])Integration with Graphs.jl
GraphCore graphs work seamlessly with the Graphs.jl ecosystem:
using Graphs, GraphCore
g = build_core_graph([(1,2), (2,3), (1,3)]; directed=false)
# Standard Graphs.jl functions work
println("Vertices: $(nv(g))")
println("Edges: $(ne(g))")
println("Neighbors of 1: $(outneighbors(g, 1))")
# Algorithms work too
wg = build_weighted_graph([(1,2), (2,3)], [1.0, 2.0]; directed=false)
paths = dijkstra_shortest_paths(wg, 1)Safety and Performance
Bounds Checking
GraphCore provides safe access by default with optimizations available:
g = build_core_graph([(1,2), (2,3)]; directed=false)
# Safe by default
try
neighbor_indices(g, 10) # BoundsError: vertex 10 out of bounds
catch e
println("Caught: $e")
end
# Optimize when you know access is safe
function fast_algorithm(g, valid_vertices)
for v in valid_vertices
# @inbounds skips bounds checking for speed
neighbors = @inbounds neighbor_indices(g, v)
# ... fast inner loop
end
endEdge Iterator Information
GraphCore provides helpful edge iterator displays:
g = build_core_graph([(1,2), (2,3), (1,3)]; directed=false)
println(edges(g))
# Output: "EdgeIterator over 3 edges from CoreGraph (undirected): (1, 2), (1, 3), (2, 3)"
# Shows: edge count, graph type, directedness, and previewNext Steps
- Design Philosophy - Architecture and performance details
- API Reference - Complete function documentation
- Examples - Check the
examples/directory for:- Performance benchmarks
- Algorithm implementations
- Plotting examples
- Graphs.jl integration
Need Help?
- Check the examples in the
examples/directory - Look at the comprehensive test suite in
test/ - See the API reference for detailed function documentation