Cairo-Graphs is a graph library written in Cairo that allows you to create and interact with graphs, entirely in Cairo, without state persistence.
The graph is implemented as an array of Vertex
. A vertex is composed of three elements :
- Its index in the graph array.
- Its identifier (it can be a token address, a hash, a number, a string, etc.)
- An array of adjacent vertices.
Since the memory is immutable in cairo, I had to make a choice when building the graph.
Since I store in each vertex an array containing the neighboring vertices, I had to track how many neighbors each vertex had (adjacent_vertices_count[i]
).
But since the memory is immutable in cairo, to avoid having complex operations requiring rebuilding the whole graph on each change
I introduced an external array that tracks how many neighbors each vertex has.
That way, when I add a neighbor to a vertex, I can just append it to the adjacent_vertices_count
array of the current vertex, and I can update the number of neighbors it has by
rebuilding the adjacent_vertices_count
array.
This implementation is probably not the most efficient, and one should expect modifications - I have to study the benefits of using another data structure, for example, a dict, to track how many neighbors each vertex has.
Here is how the Graph struct is built :
- a member length tracks the amount of vertices
- a member
vertices
represents the array of vertices. - a member
adj_vertices_count
, an array of integers, tracks how many neighbors each vertex has.
To create a graph, import the GraphMethods
namespace from cairo_graphs.graph.graph
that exposes several methods :
new_graph
returns an empty graph that you can fill manuallybuild_undirected_graph_from_edges
: Given an array of Edges (Represented by a src_identifier, dst_identifier and weight), returns an undirected graph built from the edges.build_directed_graph_from_edges
: Given an array of Edges (Represented by a src_identifier, dst_identifier and weight), returns a directed graph built from the edges.add_edge
: Given an existing graph and an edge to add, updates the graph and returns the updated data.add_vertex_to_graph
: Given an existing graph, adds a new vertex with a specific identifier.
The easiest way is to have an array of Edge
, Edge being a struct with the following fields :
src_identifier
: The identifier of the source vertex.dst_identifier
: The identifier of the destination vertex.weight
: The weight of the edge.
You can for example simply call build_directed_graph_from_edges(edges_len,edges)
to create a directed graph from an array of edges.
For now, two algorithms are implemented :
- The Dijkstra algorithm. You can use it once you have built a valid graph.
To do so, import
Dijkstra
fromcairo_graphs.graph.dijkstra
and callDijkstra.shortest_path
, which will return the distance between the two vertices as well as the path itself. You will need to provide the actualgraph
as parameter. - A DFS algorithm that returns all the possible paths to go from a vertex A to a vertex B given a maximum number of hops. The lower the number of hops allowed, the less computing-intensive the algorithm will be.
To run the tests, install protostar and run :
protostar test