Skip to content

Commit

Permalink
Merge branch 'master' of github.com:skramm/udgcd
Browse files Browse the repository at this point in the history
  • Loading branch information
skramm committed Jul 4, 2023
2 parents dd0ea5a + 7970872 commit c405a2b
Show file tree
Hide file tree
Showing 5 changed files with 30 additions and 15 deletions.
31 changes: 21 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# udgcd (UnDirected Graph Cycle Detection)


C++ wrapper over Boost Graph Library (aka BGL), provides a mean to detect cycles in a planar undirected graph.
C++ wrapper over Boost Graph Library (aka BGL), provides a mean to detect cycles in an undirected graph.

For example, with the following graph generated by the included sample program:

Expand All @@ -20,17 +20,18 @@ These are sorted with the smallest vertex in first position, and such as the sec
<a name="s_stat"></a>

- Home page: https://github.com/skramm/udgcd
- beta, may produce a result, no guarantee at all (this is a stalled project)
- Author: Sebastien Kramm
- Latest news:
- 2020-06-09: experimental code and preliminar release, source is pretty messy, but it works fine, give it a try (instructions below).
- Released under the Boost licence.

### Features

- Single-file, header only.
- Single-file, header only, OS agnostic
- Works for graphs holding unconnected sub-graphs.
- Works for non-planar graphs
- Modern C++ design (RAII).
- Modern C++ design (RAII), basic C++11.
- Fairly generic, should be suited for pretty much all types of undirected graphs, as long as you can [order the vertices](#s_notes).
- Intended audience: Any C++ app having a graph cycle detection issue and whose licence is compatible with the Boost licence.

Expand Down Expand Up @@ -83,7 +84,16 @@ Some additional apps are included, that are build by the makefile:
- `make runsam` : builds and runs the `read_graph.cpp` program and runs it on all provided data samples, in folder `samples/`
- `make doc` : builds the doxygen reference file (needs doxygen installed). Useful if you want to dive into the code...

To run a single demo, run `build/bin/sample_X`.

** Demos **

- To run a single demo, run `build/bin/sample_X`.
- To run more significant stuff, you can try:
```
$ build/bin/random_test 15 25
```
This will generate a random graph with 15 nodes and 25 vertices, and will check for cycles. Print a lot of additional info.


The program `read_graph.cpp` (build an run by `make runsam`) will generate a dot file that can be rendered as an image with Graphviz.
So if Graphviz/Dot is installed, you can try `make svg`: this will call Graphivz on all the dot files in the `out` folder.
Expand All @@ -100,7 +110,7 @@ Thus it is **not** thread safe, neither can it handle multiple graphs simultaneo
### How does it work ?
<a name="s_inside"></a>

The algorithm involved here is pretty simple, but probably not very efficient, thus slow for large graphs.
The algorithm involved here is pretty simple, but probably not very efficient, thus slow for large graphs.
Three steps are involved: first we need to check if there **is** at least one cycle.
Is this is true, we explore the graph to find it/them.
It can be considered as a variant of the Horton Algorithm.
Expand All @@ -113,7 +123,8 @@ If this happens, it means that a cycle *has* been encountered.

- The second step is done by exploring recursively the graph, by starting from each of the vertices that have been identified as part of a "back edge".

- The third steps does some post-processing: sort cycles by decreasing length, and do Gaussian Elimination to retain a Minimal Cycle Basis (MCB).
- The third steps does some post-processing:
sort cycles by decreasing length, and do Gaussian Elimination to retain a Minimal Cycle Basis (MCB).

### References
<a name="s_ref"></a>
Expand Down Expand Up @@ -144,11 +155,11 @@ As an example, say you have a raw cycle expressed as
You can use whatever edge and vertices types, the coloring needed by the algorithm is handled by providing color maps as external properties.
So if you have no special needs on vertices and edge properties, you can use something as trivial as this:
```C++
typedef boost::adjacency_list<
using graph_t = boost::adjacency_list<
boost::vecS,
boost::vecS,
boost::undirectedS
> graph_t;
>;
```
But you can also have some user properties, defines as bundled properties. For example:
```C++
Expand All @@ -166,11 +177,11 @@ struct my_Edge
```
Then your graph type definition will become:
```C++
typedef boost::adjacency_list<
using graph_t = boost::adjacency_list<
boost::vecS, // edge container
boost::vecS, // vertex container
boost::undirectedS, // type of graph
my_Vertex, // vertex type
my_Edge
> graph_t;
>;
```
3 changes: 2 additions & 1 deletion demo/common_sample.h
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,8 @@ void printVertices( std::ofstream& f, const Graph_t& gr, std::true_type )
/// Print vertices in file \c f, for general type graphs (i.e. NOT having the \c NodePos as vertex property)
/// See printVertices( std::ofstream& f, const Graph_t& gr )
template <typename Graph_t>
void printVertices( std::ofstream& f, const Graph_t& gr, std::false_type )
void
printVertices( std::ofstream& f, const Graph_t& gr, std::false_type )
{
// print_graph(g, std::cout << "Graph with other/missing properties: ");
for( auto p_vert = boost::vertices( gr ); p_vert.first != p_vert.second; p_vert.first++ )
Expand Down
8 changes: 4 additions & 4 deletions demo/random_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,14 @@ std::string prog_id = "random";

//-------------------------------------------------------------------------------------------
/// Some typedefs for readability... ;-)
typedef boost::adjacency_list<
using graph_t = boost::adjacency_list<
boost::vecS,
boost::vecS,
boost::undirectedS
> graph_t;
>;

typedef boost::graph_traits<graph_t>::vertex_descriptor vertex_t;
typedef boost::graph_traits<graph_t>::edge_descriptor edge_t;
using vertex_t = boost::graph_traits<graph_t>::vertex_descriptor;
using edge_t = boost::graph_traits<graph_t>::edge_descriptor;

//-------------------------------------------------------------------
/// Saves graph \c g in a text file, in folder \c out
Expand Down
2 changes: 2 additions & 0 deletions makefile
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ help:
@echo "Available targets:"
@echo " -run: runs once all the produced binaries"
@echo " -runsam: runs cycle detection process on all provided samples"
@echo " -svg: build svg renderings of all the samples produced by target 'runsam', with cycles as colored edges (see folder 'out')"

@echo " -clean: erase obj files"
@echo " -cleanout: erase produced output"
@echo " -cleandoc: erase produced (doxygen-build) documentation"
Expand Down
1 change: 1 addition & 0 deletions udgcd.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ edge: 0 0 0 0 1 1 1 2 2 3
--------------------------------------
vector: 0 0 0 0 0 1 1 0 0 1
\endverbatim
Each edge part of the path has a '1' at the corresponding potential edge. In this case, edges 1-3, 1-4 and 3-4.
*/
typedef boost::dynamic_bitset<> BinaryVec;

Expand Down

0 comments on commit c405a2b

Please sign in to comment.