Question

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.

Was it helpful?

Solution

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top