0

I would like to remove some edges from a graph generated using Boost graph library.

I use Boost's boost::mt19937 to generate random numbers from 1 to N(number of vertices) as shown below, and add random edges.

#include "stdafx.h"
#include <ctime>
#include <iostream>
#include <utility>                   // for std::pair
#include <algorithm> 
#include <time.h>
#include <boost/graph/adjacency_list.hpp>
#include "boost/graph/topological_sort.hpp"
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/graphviz.hpp>
#include "boost/generator_iterator.hpp"
#include "boost/random.hpp"

// ----------------------------------------------
// Reading the number of vertices from the user.
//-----------------------------------------------

int read_int(std::string const & initmsg, std::string const & repeatmsg)
{
    std::cout << initmsg;

    for (std::string line; std::getline(std::cin, line); )
    {
        std::istringstream iss(line);
        int res;

        if (iss >> res >> std::ws && iss.get() == EOF) { return res; }

        std::cout << repeatmsg;
    }

    std::cerr << "Unexpected end of input! Aborting.\n";
    std::exit(1);
}

int main()
{
    using namespace std;
    using namespace boost;
    typedef boost::mt19937 RNGType;


    //Assignign a property value to first vertex, (i.e) the name
    typedef property<vertex_name_t, std::string> VertexNameProperty;

    // Defifning the type of gprah(undirected)
    typedef adjacency_list< listS, vecS, undirectedS, VertexNameProperty > undigraph;

    // a vertex iterator to iterate through the vertex to get the property vale
    typedef graph_traits<undigraph>::vertex_iterator vertex_iter;
    std::pair<vertex_iter, vertex_iter> vp;

    int const N = read_int("Number of vertices: ",
        "I did not understand, try again. Number of vertices: ");   

    // Creating a instance g of unigraph undirected graph
    undigraph g;

    //Assigining property(name) to graph vertex
    property_map<undigraph, vertex_name_t>::type
        name = get(vertex_name, g);
    typedef graph_traits<undigraph>::vertex_descriptor Vertex;
    Vertex u1;
    u1=add_vertex(g);
    name[u1] = "Controller";

    // Creatng other vertices in the graph by iterating
    for(Vertex p = 1; p <= N-1; ++p)
    {
        p=add_vertex(g);
    }

    // Priting out the controller
    vp = vertices(g);
    std::cout << "The name of the first vertex is " << name[*vp.first]<<" and the output graph is:" <<std::endl;

    // --------------------------------------------------------------
    // Generating a random edges from a vertex, maximum edges are four
    //    Using Mersenne twister- A Pseudo random generator algorithm
    //     Mersenne twister gives un-distributed random numbers
    //----------------------------------------------------------------

    RNGType rng( time(0) );
    boost::uniform_int<> one_to_four( 1, (N-1) );
    boost::variate_generator< RNGType, boost::uniform_int<> >gen(rng, one_to_four);
    for(int i =0; i<(N-1); i++)
    {
        int k = 0;
        while(k<(N-1))
        {  
            int n  = gen();
            // Adding edges onto graph

            if(!boost::edge(i, n, g).second && !boost::edge(n, i, g).second)
                {
                add_edge(i, n, g);
                k++;
                }

        }
        // removing edges that direct to same vertex graph
    }   

    write_graphviz(cout, g);
    return 0;
}

But I get the output for the above if I have 4 vertices as follow:

graph G
0;
1;
2;
3;
4;
0--1 ;
0--2 ;
0--2 ;
0--2 ;
1--3 ;
2--1 ;
2--4 ;
3--2 ;
3--2 ;
3--4 ;
}

But as it can be seen, the edges, (0,2) and (3,2) are repeated. And for larger graphs, sometimes for ex: (1,3) and (3,1) exists and they both are same as it is undirected graph. How can I remove these vertices. I know Boost has something called remove_edge_if(), But I didn't find any precise example to support my case.

TylerH
  • 20,799
  • 66
  • 75
  • 101
Spaniard89
  • 2,359
  • 4
  • 34
  • 55

1 Answers1

3

As it should. You're taking a bunch of random numbers and adding edges for them without checking the source and end nodes, so it's no surprise that there are some repeats and some circular paths.

I would suggest changing

add_edge(i, n, g)
k++

to

if(!has_edge(i,n,g))
{
    add_edge(i, n, g)
    k++
}

and if you only ever want one edge between a pair of nodes regardless of direction:

if(!has_edge(i,n,g) && !has_edge(n,i,g))
{
    add_edge(i, n, g)
    k++
}

I would also advise against adding edges and then removing them later. So I'd remove your check for (i == i) (which can never be false, anyway), and add (i != n) to the condition before the call to add_edge.

After edit

This:

for(Vertex p = 1; p <= N-1; ++p)
{
    p=add_vertex(g);
}

could well go wrong. You're iterating over p but also editing p as you go through. it might not be though. Also, are you outputting N at any stage, to check its value?

After trying to run it

It doesn't have no elements, it's hanging while generating the graph. I think that's because of your while(k<(N-1)). You're trying to have each node have N-1 connections to other nodes. But at the same time, you won't accept connections to nodes that already connect to the current node. By the time you try to generate the edges for the second node, it can't connect to itself or the first node (which already connects to it), so has a maximum of (N-2) connections. But you're waiting until it's found N-1, which never happens.

I tried changing it to while(k<(N/2)) and that seemed to work for me.

hcarver
  • 7,126
  • 4
  • 41
  • 67
  • Hi mate, thanks for replying. But when I ran your code, i get and error `has_edge': identifier not found`. I have included all the required headers. – Spaniard89 Sep 21 '12 at 09:14
  • Yeah, sorry. Instead of `has_edge(i, n, g)`, I think you have to do `boost::edge(i, n, g).second`. Bit of an ugly syntax but I think it's the best there is. – hcarver Sep 21 '12 at 09:39
  • Thanks again, but when i run the above code, i don't get any output, my graph is null. :( There isn't any edges or vertices. – Spaniard89 Sep 21 '12 at 09:45
  • But I can't post it here in the comment, cause i am not allowed to enter more than 500 characters, hence i would edit, the code above in my question. Thanks in advance. – Spaniard89 Sep 21 '12 at 09:51
  • I removed those line from my code and inserted vertex using digraph g(N), but still my output is blank. – Spaniard89 Sep 21 '12 at 10:18
  • Incidentally, your current code omits the "can't connect to self condition". Change `if(!has_edge(i,n,g) && !has_edge(n,i,g))` to `if(i!=n && !has_edge(i,n,g) && !has_edge(n,i,g))` if you want that. – hcarver Sep 21 '12 at 10:26
  • I tried changing the code accordingly as you said above, as follow: `while(k<(N/2)) { int n = gen(); // Adding edges onto graph if(i!=n && !boost::edge(i, n, g).second && !boost::edge(n, i, g).second) { add_edge(i, n, g); k++; } }` But still, I am not getting any output. I would really appreciate for any help. – Spaniard89 Sep 21 '12 at 10:59
  • Without `i!=n` I am getting the desired output. :) But with that term added I am not getting the graph. :( – Spaniard89 Sep 21 '12 at 11:02
  • It's going to depend on your choice of N. E.g. if N==2, there's no way for each node to make 1 connection without there being 2 connections between a pair of nodes. `while(k<(N/2 - 1))` would make it work for any `N`, I think. – hcarver Sep 21 '12 at 11:05
  • got it working :) Added i!=n before the add_edge. Thanks a lot mate. It was really helpful. – Spaniard89 Sep 21 '12 at 11:06
  • I just have a last question, What if I want to restrict the number of edges from each node to 4 and not more than that, it can be less though. – Spaniard89 Sep 21 '12 at 11:11
  • Hi, I still didn't figure out how to restrict the number of edges from each vertex to 4(both incoming and out going). Could you please help me in this? I would be really glad if you can help. – Spaniard89 Sep 21 '12 at 13:29
  • I think that's worth starting a second question for. Start by having a go yourself, and then post the code when you're truly stuck. As a hint, try initialising k to the number of edges already coming into the node from other nodes. Then `while(k<5)` should probably do the trick. – hcarver Sep 21 '12 at 17:24
  • Thanks for replying and helping. But how can i count the number of edges coming inside a vertex? do in_edges() function does it? if not what are my other options? – Spaniard89 Sep 22 '12 at 09:58
  • 1
    I think you should try looking this kind of thing up yourself from the Boost API. I'm not an expert, but I think `in_degree(vertex, graph)` should get you what you want. – hcarver Sep 22 '12 at 15:35