From a51ac444173c4ca44cd957fa11ee460ce4d186e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Zurcher?= Date: Thu, 26 Dec 2013 14:52:39 +0100 Subject: add Eina_Graph_DFS --- src/Makefile_lib.am | 6 +- src/lib/Eina_Graph.h | 1 + src/lib/eina_graph_dfs.c | 184 +++++++++++++++++++++++++++++++++++++++++++ src/lib/eina_graph_dfs.h | 96 ++++++++++++++++++++++ src/lib/eina_graph_private.h | 8 ++ 5 files changed, 293 insertions(+), 2 deletions(-) create mode 100644 src/lib/eina_graph_dfs.c create mode 100644 src/lib/eina_graph_dfs.h diff --git a/src/Makefile_lib.am b/src/Makefile_lib.am index 79b3b8a..0e806d3 100644 --- a/src/Makefile_lib.am +++ b/src/Makefile_lib.am @@ -3,11 +3,13 @@ includesdir = $(includedir)/eina_graph-@VMAJ@ includes_HEADERS = \ lib/Eina_Graph.h \ - lib/eina_graph.h + lib/eina_graph.h \ + lib/eina_graph_dfs.h lib_libeina_graph_la_SOURCES = \ lib/eina_graph_main.c \ - lib/eina_graph.c + lib/eina_graph.c \ + lib/eina_graph_dfs.c EXTRA_DIST += lib/eina_graph_private.h diff --git a/src/lib/Eina_Graph.h b/src/lib/Eina_Graph.h index e5dbf0b..84e4abf 100644 --- a/src/lib/Eina_Graph.h +++ b/src/lib/Eina_Graph.h @@ -58,5 +58,6 @@ EAPI int eina_graph_shutdown(void); #include +#include #endif /* _EINA_GRAPH_MAIN_H */ diff --git a/src/lib/eina_graph_dfs.c b/src/lib/eina_graph_dfs.c new file mode 100644 index 0000000..3fa08a6 --- /dev/null +++ b/src/lib/eina_graph_dfs.c @@ -0,0 +1,184 @@ +/* EINA_GRAPH - EFL graph processing library + * Copyright (C) 2013 Jérémy Zurcher + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of the Software and its Copyright notices. In addition publicly + * documented acknowledgment must be given that this software has been used if no + * source code of this software is made available publicly. This includes + * acknowledgments in either Copyright notices, Manuals, Publicity and Marketing + * documents or any documentation provided with any product containing this + * software. This License does not apply to any software that links to the + * libraries provided by this software (statically or dynamically), but only to + * the software provided. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include "eina_graph_private.h" + +static void +_eina_graph_dfs_swalk(_Eina_Graph *_g, _Eina_Graph_DFS *_dfs, unsigned int v) +{ + Eina_List *stack = NULL; + Eina_Graph_Adjacents *adjs; + unsigned int p, w, n, i; + + p = v; + stack = eina_list_prepend(stack, (void *) v); + + while (eina_list_count(stack) > 0) + { + w = (unsigned int) eina_list_data_get(stack); + stack = eina_list_remove(stack, (void *) w); + + if(_dfs->marked[w]) continue; + _dfs->marked[w] = EINA_TRUE; + _dfs->edge_to[w] = p; + p = w; + + adjs = &_g->adjs[w]; + n = adjs->count; + for (i = 0; i < n; i++) + { + w = adjs->data[i]; + if (!_dfs->marked[w]) + { + stack = eina_list_prepend(stack, (void *) w); + } + } + } +} + +static void +_eina_graph_dfs_rwalk(_Eina_Graph *_g, _Eina_Graph_DFS *_dfs, unsigned int v) +{ + Eina_Graph_Adjacents *adjs; + unsigned int i, n, w; + + _dfs->marked[v] = EINA_TRUE; + + adjs = &_g->adjs[v]; + n = adjs->count; + for (i = 0; i < n; i++) + { + w = adjs->data[i]; + if (!_dfs->marked[w]) + { + _eina_graph_dfs_rwalk(_g, _dfs, w); + _dfs->edge_to[w] = v; + } + } +} + +EAPI Eina_Graph_DFS * +eina_graph_dfs_new(Eina_Graph *g, unsigned int s, Eina_Bool r) +{ + _Eina_Graph_DFS *_dfs; + _Eina_Graph * _g = (_Eina_Graph *) g; + + _dfs = calloc(1, sizeof(_Eina_Graph_DFS)); + if (!_dfs) + goto error_dfs; + + _dfs->marked = calloc(_g->vertices, sizeof(Eina_Bool)); + if (!_dfs->marked) + goto error_marked; + + _dfs->edge_to = calloc(_g->vertices, sizeof(unsigned int)); + if (!_dfs->edge_to) + goto error_edge_to; + + _dfs->s = s; + _dfs->vertices = _g->vertices; + + if (r) + _eina_graph_dfs_rwalk(_g, _dfs, s); + else + _eina_graph_dfs_swalk(_g, _dfs, s); + + return (Eina_Graph_DFS *) _dfs; + +error_edge_to: + free(_dfs->marked); +error_marked: + free(_dfs); +error_dfs: + ERR("calloc failed : %s", strerror(errno)); + return NULL; +} + +EAPI void +eina_graph_dfs_free(Eina_Graph_DFS *dfs) +{ + _Eina_Graph_DFS *_dfs = (_Eina_Graph_DFS *) dfs; + + free(_dfs->marked); + free(_dfs->edge_to); + free(_dfs); +} + +EAPI unsigned int +eina_graph_dfs_source(Eina_Graph_DFS *dfs) +{ + _Eina_Graph_DFS *_dfs = (_Eina_Graph_DFS *) dfs; + + return _dfs->s; +} + +EAPI Eina_Bool +eina_graph_dfs_has_path_to(Eina_Graph_DFS *dfs, unsigned int v) +{ + _Eina_Graph_DFS *_dfs = (_Eina_Graph_DFS *) dfs; + + if (v >= _dfs->vertices) + { + ERR("%u is out of [0;%u[", v, _dfs->vertices); + return EINA_FALSE; + } + + return _dfs->marked[v]; +} + +EAPI Eina_List * +eina_graph_dfs_path_to(Eina_Graph_DFS *dfs, unsigned int v) +{ + unsigned int w = v; + Eina_List *path = NULL; + _Eina_Graph_DFS *_dfs = (_Eina_Graph_DFS *) dfs; + + if (v >= _dfs->vertices) + { + ERR("%u is out of [0;%u[", v, _dfs->vertices); + return NULL; + } + + if (!_dfs->marked[v]) + return NULL; + + while (w != _dfs->s) + { + path = eina_list_prepend(path, (void *) w); + w = _dfs->edge_to[w]; + } + path = eina_list_prepend(path, (void *) _dfs->s); + + return path; +} + diff --git a/src/lib/eina_graph_dfs.h b/src/lib/eina_graph_dfs.h new file mode 100644 index 0000000..7e596d6 --- /dev/null +++ b/src/lib/eina_graph_dfs.h @@ -0,0 +1,96 @@ +/* EINA_GRAPH - EFL graph processing library + * Copyright (C) 2013 Jérémy Zurcher + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of the Software and its Copyright notices. In addition publicly + * documented acknowledgment must be given that this software has been used if no + * source code of this software is made available publicly. This includes + * acknowledgments in either Copyright notices, Manuals, Publicity and Marketing + * documents or any documentation provided with any product containing this + * software. This License does not apply to any software that links to the + * libraries provided by this software (statically or dynamically), but only to + * the software provided. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef _EINA_GRAPH_DFS_H +#define _EINA_GRAPH_DFS_H + +#include +#include + +/** + * @typedef Eina_Graph_DFS + * The basic Eina_Graph DFS type. + */ +typedef struct _Eina_Graph_DFS_Opaque Eina_Graph_DFS; + +/** + * returns a Depth First Search of the given graph. + * + * @param g the graph to build the DFS from. + * @param s the source vertex of the DFS. + * @param r if est to EINA_TRUE, use recursive instead of stack based algo. + * + * @return a new Depth First Search. + */ +EAPI Eina_Graph_DFS * +eina_graph_dfs_new(Eina_Graph *g, unsigned int s, Eina_Bool r); + +/** + * free the given graph DFS. + * + * @param dfs the graph DFS to free. + */ +EAPI void +eina_graph_dfs_free(Eina_Graph_DFS *dfs); + +/** + * get the source vertex of the graph DFS. + * + * @param dfs the graph DFS to consider. + * + * @return the source vertex of the DFS. + */ +EAPI unsigned int +eina_graph_dfs_source(Eina_Graph_DFS *dfs); + +/** + * is there a path from the source to the given vertex. + * + * @param dfs the graph DFS to consider. + * @param v the vertex to test if there is a path to. + * + * @return EINA_TRUE if the vertex is reachable from the source. + */ +EAPI Eina_Bool +eina_graph_dfs_has_path_to(Eina_Graph_DFS *dfs, unsigned int v); + +/* + * return the path to reach the given vertex from the source. + * + * the Eina_list returned must be freed by the user code. + * + * @param dfs the graph DFS to consider. + * @param v the vertex to test if there is a path to. + * + * @return a list of vertices to follwo from source to reach v, + * NULL if v is not reachable. + */ +EAPI Eina_List * +eina_graph_dfs_path_to(Eina_Graph_DFS *dfs, unsigned int v); + +#endif /* _EINA_GRAPH_DFS_H */ diff --git a/src/lib/eina_graph_private.h b/src/lib/eina_graph_private.h index 75dfffb..d7a676c 100644 --- a/src/lib/eina_graph_private.h +++ b/src/lib/eina_graph_private.h @@ -98,4 +98,12 @@ typedef struct _Eina_Graph Eina_Graph_Adjacents *adjs; } _Eina_Graph; +typedef struct _Eina_Graph_DFS +{ + unsigned int s; + unsigned int vertices; + Eina_Bool *marked; + unsigned int *edge_to; +} _Eina_Graph_DFS; + #endif /* _EINA_GRAPH_PRIVATE_H */ -- cgit v1.1-2-g2b99