Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Karps Minimum Cycle Algorithm #281

Open
wants to merge 7 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added doc/figs/mcm.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
83 changes: 83 additions & 0 deletions doc/karp_minimum_cycle_mean.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=iso-8859-1">
<TITLE>Boost Graph Library: Karps Minimum Cycle Mean</TITLE>
<META NAME="CREATED BY" CONTENT="G YUVAN SHANKAR">


<!--Use, modification and distribution is subject to the Boost Software
License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt)

Authors: G Yuvan Shankar
-->
<!--
<STYLE>
@page { size: 3.5cm 2.5cm }
TD P { color: #000000 }
H1 { color: #000000 }
P { color: #000000 }
PRE { color: #000000 }
H3 { color: #000000 }
BLOCKQUOTE { color: #000000 }
A:link { color: #0000ee }
A:visited { color: #551a8b }
</STYLE>
-->
</HEAD>
<BODY TEXT="#000000" LINK="#0000ee" VLINK="#551a8b" BGCOLOR="#ffffff" DIR="LTR">
<P><IMG SRC="../../..//boost.png" NAME="graphics1" ALT="C++ Boost" ALIGN=BOTTOM WIDTH=277 HEIGHT=86 BORDER=0>
</P>
<H1><TT>karp_minimum_cycle_mean</TT></H1>
<P>
<PRE>
template &lt;typename Graph&gt;
double karp_minimum_cycle_mean(Graph g);
</PRE>
</P>


The <tt>karp_minimum_cycle_mean()</tt> function calculates minimum cycle mean of a
weighted directed graph <I>G=(V,E,W)</I>, where <i>V</i> is a vertex set,
<i>E</i> is an edge set, <I>W: E -> R</I> is an edge weight function .
</P>

<P>We define the mean weight of a cycle <I>C=&lte<sub>1</sub>,e<sub>1</sub>,e<sub>2</sub>..,e<sub>k</sub>&gt</I> of edges in E to be</P>
<P>
<IMG SRC="figs/mcm.jpg" ALT="mean weight of cycle" BORDER=0>
</P>

The <I>minimum cycle mean</I> is the minimum cycle mean
of all cycles of the graph. The <tt>karp_minimum_cycle_mean()</tt> returns the
calculated minimum cycle mean. Returns -1 if the graph has no cycles.

</P>
<P>
This algorithm was described by Richard M. Karp in his paper
<A HREF="./dasdan-dac99.pdf">A characterization of the minimum cycle mean in a digraph</A></P>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please give a proper citation of the paper.



<H3>Where Defined</H3>
<P STYLE="background: transparent"><TT><A HREF="../../../boost/graph/karp_minimum_cycle_mean.hpp">boost/graph/karp_minimum_cycle_mean.hpp</A></TT>
</P>
<H3>Parameters</H3>

<P>IN: <tt>const Graph g </tt>
</P>
<BLOCKQUOTE>A weighted directed graph.
</BLOCKQUOTE>

<P>
OUT: double <tt>minimum_mean_weight</tt>
</P>

<H3>Complexity</H3>
<P>The implemented algorithm runs in O(|V||E|) time. Where V and E are vertex set and edge set respectively.
</P>

<H3>Example</H3>
<P>The program in <A HREF="../example/minimum_cycle_mean_example.cpp">libs/graph/example/minimum_cycle_mean_example.cpp</A>
finds the minimum cycle mean of the defined graph.
</P>

28 changes: 28 additions & 0 deletions example/minimum_cycle_mean_example.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#include <iostream>
#include <boost/graph/karp_minimum_cycle_mean.hpp>
typedef boost::property<boost::edge_weight_t, double> EdgeWeight;
typedef boost::adjacency_list<boost::listS, boost::vecS, boost::directedS, boost::no_property, EdgeWeight> DirectedGraph;
int main() {

DirectedGraph g;
/**
* Create the graph drawn below.
*
*
* 10
* ________
* / 1 3 \
* 1-->2--->3
^ ^ /
* 8\0| /2
* \|/
* 4
**/
boost::add_edge(0, 1, 1, g);
boost::add_edge(1, 2, 3, g);
boost::add_edge(2, 3, 2, g);
boost::add_edge(3, 1, 0, g);
boost::add_edge(3, 0, 8, g);
boost::add_edge(0, 2, 10, g);
std::cout<<boost::karp_minimum_cycle_mean(g);
}
79 changes: 79 additions & 0 deletions include/boost/graph/karp_minimum_cycle_mean.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
#ifndef BOOST_GRAPH_KARP_MINIMUM_CYCLE_MEAN_HPP
#define BOOST_GRAPH_KARP_MINIMUM_CYCLE_MEAN_HPP

#include <iostream>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't allow <iostream> in header files: it brings in a lot of names and static objects, etc.

#include <boost/graph/graph_traits.hpp>
#include <boost/graph/adjacency_list.hpp>

namespace boost
{
template<typename Graph>
double karp_minimum_cycle_mean(Graph g)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you'll want to take g by const reference.

{
typedef typename boost::graph_traits<Graph>::vertex_iterator vertex_iterator;
typedef typename boost::graph_traits<Graph>::vertex_descriptor vertex_descriptor;
typename property_map<Graph, edge_weight_t>::type weight = get(edge_weight,g);
typedef typename boost::graph_traits<Graph>::out_edge_iterator out_edge_iterator;
BOOST_CONCEPT_ASSERT((GraphConcept< Graph >));

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A comment about this file in general, we don't have automatic Clang format running (yet), so please follow the convention in the rest of the library:

  • whitespace around operators: a + b, a = b, etc.

int n = num_vertices(g);
double distance_matrix[n+1][n];
std::fill(distance_matrix[0],distance_matrix[0]+(n+1)*(n), -1.0);
distance_matrix[0][0] = 0;

std::pair <vertex_iterator ,vertex_iterator> vertex_iterator_pair= vertices(g);
std::vector<vertex_descriptor> vertices_vector;
for(vertex_iterator a=vertex_iterator_pair.first; a!=vertex_iterator_pair.second;a++)
{
vertices_vector.push_back(*a);;
}

for (int i=1; i<=n; i++)
{
for (int j=0; j<n; j++)
{
std::pair <out_edge_iterator ,out_edge_iterator> edge_iterator_pair= boost::out_edges(vertices_vector[j],g);
std::vector<typename boost::graph_traits<Graph>::edge_descriptor> incident_edges;
for(out_edge_iterator b=edge_iterator_pair.first;b!=edge_iterator_pair.second;b++)
{
incident_edges.push_back(*b);
}
for (int k=0; k< out_degree(vertices_vector[j],g); k++)
{
vertex_descriptor t=target(incident_edges[k],g);
auto it = find(vertices_vector.begin(), vertices_vector.end(), t);
int index = it - vertices_vector.begin();
if (distance_matrix[i-1][index] != -1)
{
double curr_wt = distance_matrix[i-1][index] +
get(weight,incident_edges[k]);
if (distance_matrix[i][j] == -1)
distance_matrix[i][j] = curr_wt;
else
distance_matrix[i][j] = std::min(distance_matrix[i][j], curr_wt);
}
}
}
}
double avg[n];
std::fill(avg,avg+n,-1.0);

for (int i=0; i<n; i++)
{
if (distance_matrix[n][i] != -1)
{
for (int j=0; j<n; j++)
if (distance_matrix[j][i] != -1)
avg[i] = std::max(avg[i],(double)(distance_matrix[n][i]-distance_matrix[j][i])/(n-j));
}
}
double minimum_mean_weight = avg[0];
for (int i=0; i<n; i++)
if (avg[i] != -1 && avg[i] < minimum_mean_weight)
minimum_mean_weight = avg[i];

return minimum_mean_weight;
}

}
#endif
48 changes: 48 additions & 0 deletions test/minimum_cycle_mean_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#include <iostream>
#include <boost/graph/karp_minimum_cycle_mean.hpp>
#include <boost/core/lightweight_test.hpp>
typedef boost::property<boost::edge_weight_t, double> EdgeWeight;
typedef boost::adjacency_list<boost::listS, boost::vecS, boost::directedS, boost::no_property, EdgeWeight> DirectedGraph;
int main() {
const double epsilon = 0.005;
{
DirectedGraph g1;
/**
* Create the graph drawn below.
*
*
* 10
* ________
* / 1 3 \
* 1-->2--->3
^ ^ /
* 8\0| /2
* \|/
* 4
**/
boost::add_edge(0, 1, 1, g1);
boost::add_edge(1, 2, 3, g1);
boost::add_edge(2, 3, 2, g1);
boost::add_edge(3, 1, 0, g1);
boost::add_edge(3, 0, 8, g1);
boost::add_edge(0, 2, 10, g1);
double min_cycle_mean = boost::karp_minimum_cycle_mean(g1);
std::cout << min_cycle_mean << std::endl;
BOOST_TEST(std::abs(min_cycle_mean - 1.666666666) < epsilon);
}
{
DirectedGraph g2;
/**
* Create the graph drawn below.
* 1
* 1-->2
*
**/
boost::add_edge(0, 1, 1, g2);
double min_cycle_mean = boost::karp_minimum_cycle_mean(g2);
std::cout << min_cycle_mean << std::endl;
BOOST_TEST(std::abs(min_cycle_mean +1) < epsilon);
}

return boost::report_errors();
}