# Overview

In the Relational Knowledge Graph System (RKGS) you typically work with data organized into a knowledge graph. Most graph algorithms, however, operate on unlabeled graphs. Rel’s Graph Library is designed to work with these unlabeled graphs. It provides constructors for creating graphs with the correct schema.

## Rel Graph Schema

A graph in Rel is a module containing some or all of the following relations:

1. `node` is a set containing the nodes of the graph. Every graph has a `node` relation.
2. `edge` is a set of pairs of nodes. Every graph has an `edge` relation.
3. `weight` is a set of triples that map edges to numeric weights. Only weighted graphs have a `weight` relation.
4. `is_directed` distinguishes directed graphs from undirected graphs.
5. `is_weighted` distinguished weighted graph from unweighted graphs.

For example, the following module represents a weighted, directed graph with two nodes and one edge with a weight of `1.0`:

``````module my_graph
def edge = {(1, 2)}
def node = {1; 2}
def weight = {(1, 2, 1.0)}
def :is_directed = true
def :is_weighted = true
end``````

You may easily create modules with valid graph schemas using the `create_graph`, `undirected_graph`, and `directed_graph` constructors described in Creating Graphs. See Create a Graph From a CSV File and Create a Graph From a Knowledge Graph for examples of creating graphs from external data.

## Performance Tips

For the best performance, use integer node IDs. To convert non-integer nodes to integers, install the following module, which transforms an edge relation to pairs of integers and provides a mapping to get the original nodes back from their integer ID:

``````// model

@inline
module transform[E]
// Map integers to nodes.
// The set of nodes is inferred from the edge set `E` as the
// union of all of the nodes in the first and second columns of `E`.
def int_to_node = enumerate[{first[E]; second[E]}]

// Reverse mapping to go from nodes to integers.
def node_to_int = transpose[int_to_node]

// Define the transformed edge set.
def edge = (node_to_int[u], node_to_int[v]) from u, v where E(u, v)
end

// Sample usage:

// Declare an edge set with mixed node types.
// Node `"a"` is a `String`, node `1.25` is a `Float`,
// and node `2023-05-12` is a `Date` literal.
def my_edge = {("a", 1.25); (1.25, 2023-05-12)}

// Transform the nodes and edges.
// Note that this is installed so that the mapping relations
// may be used in future queries to retrieve actual node values.
def transformed = transform[my_edge]

// Construct a directed graph from the transformed edge set.
def my_graph = directed_graph[transformed:edge]``````

The nodes of the graph are integers:

``````// read query

// Display the contents of `my_graph`.
def output = my_graph``````

To recover the original node from an integer, partially apply the `int_to_node` relation to the node’s integer index:

``````// read query

// Display the original node corresponding to node 3.
def output = transformed:int_to_node[3]``````