From 5a231fb7090464cd4e86db679bc41ea0ceddd13a Mon Sep 17 00:00:00 2001 From: Al Date: Tue, 6 Oct 2015 19:03:10 -0400 Subject: [PATCH] [graph] Builder for graphs not constructed in vertex-sorted order --- src/graph_builder.c | 108 ++++++++++++++++++++++++++++++++++++++++++++ src/graph_builder.h | 53 ++++++++++++++++++++++ 2 files changed, 161 insertions(+) create mode 100644 src/graph_builder.c create mode 100644 src/graph_builder.h diff --git a/src/graph_builder.c b/src/graph_builder.c new file mode 100644 index 00000000..477044aa --- /dev/null +++ b/src/graph_builder.c @@ -0,0 +1,108 @@ +#include "graph_builder.h" + + +#define ks_lt_graph_edge(a, b) ((a).v1 < (b).v1) +KSORT_INIT(graph_edge_array, graph_edge_t, ks_lt_graph_edge) + +#define ks_lt_graph_edge_sort_vertices(a, b) (((a).v1 < (b).v1) || ((a).v1 == (b).v1 && (a).v2 < (b).v2)) +KSORT_INIT(graph_edge_array_sort_vertices, graph_edge_t, ks_lt_graph_edge_sort_vertices) + + +static void graph_builder_destroy(graph_builder_t *self) { + if (self == NULL) return; + + if (self->edges != NULL) { + graph_edge_array_destroy(self->edges); + } + + free(self); +} + +graph_builder_t *graph_builder_new(graph_type_t type, bool fixed_rows) { + graph_builder_t *builder = malloc(sizeof(graph_builder_t)); + + builder->type = type; + builder->m = 0; + builder->n = 0; + builder->fixed_rows = fixed_rows; + + builder->edges = graph_edge_array_new(); + if (builder->edges == NULL) { + graph_builder_destroy(builder); + return NULL; + } + + return builder; +} + + +static graph_t *graph_builder_build_edges(graph_builder_t *self, bool remove_duplicates) { + graph_t *graph = graph_new(self->type); + if (graph == NULL) return NULL; + + uint32_t last_vertex = 0; + uint32_t last_edge = 0; + + for (int i = 0; i < self->edges->n; i++) { + graph_edge_t edge = self->edges->a[i]; + if (edge.v1 > last_vertex) { + for (uint32_t row = last_vertex; row < edge.v1; row++) { + graph_finalize_vertex(graph); + + } + + } + + if (!remove_duplicates || i == 0 || edge.v1 != last_vertex || edge.v2 != last_edge) { + graph_append_edge(graph, edge.v2); + } + last_vertex = edge.v1; + last_edge = edge.v2; + } + + graph_finalize_vertex(graph); + + return graph; +} + +graph_t *graph_builder_finalize(graph_builder_t *self, bool sort_edges, bool remove_duplicates) { + graph_t *graph; + if (remove_duplicates && !sort_edges) { + sort_edges = true; + } + + if (!sort_edges) { + ks_introsort(graph_edge_array, self->edges->n, self->edges->a); + graph = graph_builder_build_edges(self, remove_duplicates); + } else { + ks_introsort(graph_edge_array_sort_vertices, self->edges->n, self->edges->a); + graph = graph_builder_build_edges(self, remove_duplicates); + } + + graph->fixed_rows = self->fixed_rows; + graph_set_size(graph); + + graph_builder_destroy(self); + return graph; +} + +void graph_builder_add_edge(graph_builder_t *self, uint32_t v1, uint32_t v2) { + if (v1 == v2) return; + graph_edge_t edge; + + if (self->type != GRAPH_UNDIRECTED || v2 > v1) { + edge = (graph_edge_t) {v1, v2}; + } else { + edge = (graph_edge_t) {v2, v1}; + } + + graph_edge_array_push(self->edges, edge); + + if (v1 >= self->m) { + self->m = v1 + 1; + } + + if (v2 >= self->n) { + self->n = v2 + 1; + } +} diff --git a/src/graph_builder.h b/src/graph_builder.h new file mode 100644 index 00000000..897ee372 --- /dev/null +++ b/src/graph_builder.h @@ -0,0 +1,53 @@ +/* +graph_builder.h +--------------- + +For graphs it's sometimes impractical to assume that the vertices +will arrive in sorted order, which is required for constructing a +compressed sparse row (CSR) matrix. This is simply a coordinate matrix +(COO) style constructor where the rows/columns do not need to be +ordered or unique. + +*/ + +#ifndef GRAPH_BUILDER_H +#define GRAPH_BUILDER_H + +#include "collections.h" +#include "file_utils.h" +#include "graph.h" + + +typedef struct graph_edge { + uint32_t v1; + uint32_t v2; +} graph_edge_t; + +VECTOR_INIT(graph_edge_array, graph_edge_t) + + +typedef struct graph_builder { + graph_type_t type; + size_t m; + size_t n; + bool fixed_rows; + graph_edge_array *edges; +} graph_builder_t; + +graph_builder_t *graph_builder_new(graph_type_t type, bool fixed_rows); +/* +Destroy the builder and return a graph. + +Note: remove_duplicates=true requires sorting the indices. Can only preserve +edge ordering if we can guarantee there are no duplicates. +*/ +graph_t *graph_builder_finalize(graph_builder_t *self, bool sort_edges, bool remove_duplicates); + +/* +Add an edge. Order + +Reflexive edges not allowed. +*/ +void graph_builder_add_edge(graph_builder_t *self, uint32_t v1, uint32_t v2); + +#endif \ No newline at end of file