From c63d6f0a7bf559b870bb5b11c6eaece3bbc2becc Mon Sep 17 00:00:00 2001 From: nimrodVarga Date: Wed, 25 Oct 2023 15:47:05 +0200 Subject: [PATCH] split graph code into own file --- include/graph.c | 148 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 include/graph.c diff --git a/include/graph.c b/include/graph.c new file mode 100644 index 0000000..b220529 --- /dev/null +++ b/include/graph.c @@ -0,0 +1,148 @@ +typedef struct{ + PyObject_HEAD + Index node_count; + Index* pre_neighbor_offsets; + PyArrayObject* edge_list; +} Graph; + + +static void Graph_dealloc(Graph* graph){ + free(graph->pre_neighbor_offsets); + Py_DECREF(graph->edge_list); + Py_TYPE(graph)->tp_free((PyObject*)graph); +} + + +static PyObject* Graph_new(PyTypeObject* type, PyObject* args, PyObject* kwds){ + Index node_count; + PyArrayObject* edges; + + // ASSUMPTION: edge list should be sorted in the second argument or destination + + if(!PyArg_ParseTuple(args, "OI", (PyObject**)&edges, &node_count)){ + puts("no new graph without correct args"); + return NULL; + } + + + + // TODO: check edges.dtype in {np.uint32, np.uint64} + + + Graph* graph = (Graph*) type->tp_alloc(type, 0); + + if(graph!=NULL){ + // NOTE: if ASSUMPTION in count_neighbors is wrong, memory needs to be zeroed out before starting counting + graph->pre_neighbor_offsets = (Index*)malloc((node_count+1)*sizeof(Index)); + + + + ASSERT(graph->pre_neighbor_offsets); + } + + return (PyObject*)graph; +} + + + + + + + + + + +static int Graph_init(Graph* graph, PyObject* args, PyObject* kwds){ + PyArrayObject* edges; + Index node_count; + + // ASSUMPTION: edge list should be sorted in the second argument + + if(!PyArg_ParseTuple(args, "OI", (PyObject**)&edges, &node_count)){ + puts("couldn't parse edge list"); + return -1; + } + + graph->node_count = node_count; + + graph->edge_list = edges; + + Py_INCREF(edges); + + + + + + // TODO: MT or GPU + for(Index i=0; inode_count+1; i++){ + graph->pre_neighbor_offsets[i]=0; + } + + Index edge_count = (Index)PyArray_DIM(edges, 1); + + for(Index e=0; epre_neighbor_offsets[Node_To_Index(dst_node)+1]++; + } + + neighbor_counts_to_offsets(graph->node_count, graph->pre_neighbor_offsets); + + return 0; +} + +static Node src_node_at(Graph* g, Index i){ + ASSERT(i < g->pre_neighbor_offsets[g->node_count]); + + return *((Node*)PyArray_GETPTR2(g->edge_list, 0, i)); +} + +static Node dst_node_at(Graph* g, Index i){ + ASSERT(i < g->pre_neighbor_offsets[g->node_count]); + return *((Node*)PyArray_GETPTR2(g->edge_list, 1, i)); +} + +static PyObject* Graph_print(Graph* graph, PyObject *Py_UNUSED(ignored)){ + for(Index i=0;inode_count;i++){ + Index c = graph->pre_neighbor_offsets[i+1]-graph->pre_neighbor_offsets[i]; + Index o=graph->pre_neighbor_offsets[i]; + + for(Index ii=0; iipre_neighbor_offsets[Node_To_Index(n)+1]-graph->pre_neighbor_offsets[Node_To_Index(n)]; + + return PyLong_FromIndex(pre_neighbor_count); +} + + + +static PyMethodDef Graph_methods[] = { + {"print", (PyCFunction)Graph_print, METH_NOARGS, "print the graph"}, + {"preneighborhood_count", (PyCFunction)Graph_preneighborhood_count, METH_VARARGS, "get the size of the pre-neighborhood of a node within the graph"}, + {NULL} +}; + +static PyTypeObject GraphType = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "GMSamplers.Graph", + .tp_doc = PyDoc_STR("GMSamplers graph"), + .tp_basicsize = sizeof(Graph), + .tp_itemsize = 0, + .tp_flags = Py_TPFLAGS_DEFAULT, + .tp_new = Graph_new, + .tp_init = (initproc) Graph_init, + .tp_dealloc = (destructor) Graph_dealloc, + .tp_methods = Graph_methods +};