How to copy one boost graph into another ( Deep Copy ) with all custom properties?

75 Views Asked by At

I have a boost graph with custom properties. I want to make a copy of it. I tried it by following way but got many compilation error.

Here is what I did :

using BGType = boost::adjacency_list<boost::vecS, boost::vecS, boost::bidirectionalS,
                                     // Vertex Properties...
                                     vertexProps,
                                     // Edge Propereties...
                                     edgeProps,
                                     // Graph Properties
                                     graphProps>;

vertexProps.h

class vertexProps {
   public:
    explicit vertexProps(const std::string *moduleName = nullptr, const std::string *name = nullptr,
                            long refPtr = 0 )
     : _refPtr(refPtr),
    {
        _moduleName = moduleName ? *moduleName : "";
        _name = name ? *name : "";
    };


struct CustomVertexCopy {
    void operator()(const vertexProps& source_vertex, vertexProps& target_vertex) const {
        target_vertex._refPtr = source_vertex._refPtr;
        target_vertex._moduleName = source_vertex._moduleName;
        target_vertex._name = source_vertex._name;
}

edgeProps.h

class edgeProps {
   public:
    explicit edgeProps(std::string name = "")
        : _name(name){};
    std::string _name;
};

struct CustomEdgeCopy {
    void operator()(const edgeProps& source_edge, edgeProps& target_edge) const {
        target_edge._name = source_edge._name;
    }
};

someFunction.cpp

OnClick(BGType* bGraph)
{
   // some code
  BGType* oldBg = new BGType;
  boost::copy_graph(bGraph, oldBg, boost::vertex_copy(CustomVertexCopy()));
  boost::copy_graph(bGraph, oldBg, boost::edge_copy(CustomEdgeCopy()));
  // some code
}

Where am I wrong ?

I have a one more doubt.
Will such deep copying impact on performance if grpah is big ? If yes, is there any way to avoid it ?

@sehe : I tried your answer, but I was getting compilation error. So I tried to change code little bit and now there is no compilation error. But please look into my changes and suggest me whther changes are right or wrong.

OnClick(BGType* bGraph)
{
   // some code
   BGType* oldBg = new BGType;
   boost::copy_graph(*bGraph, *oldBg,
                      boost::vertex_copy(CustomVertexCopy{*bGraph,*oldBg})
                            .edge_copy(CustomEdgeCopy{*bGraph, *oldBg}));
   // some code
}

@sehe: I have graph properties also along with vertex and edge property. How to copy that properties also ?

class graphProps {
   public:
    explicit graphProps(std::string *name = nullptr) { _name = name ? *name : ""; };

    std::string _name;
    std::map<std::string, std::tuple<std::vector<schPinInfo *>,  // input Pins
                                     std::vector<schPinInfo *>,  // inout pins
                                     std::vector<schPinInfo *>>  // output pins
             >
      _modInfo;
    std::map<std::string, std::vector<std::string>> _altNames;
    std::map<std::string, schSymbol> _modSymbol;
}
1

There are 1 best solutions below

12
sehe On BEST ANSWER

Named parameters are chained so you can pass arbitrary number of arguments in one place:

boost::copy_graph(                         //
    g1, g2,                                //
    boost::vertex_copy(CustomVertexCopy{}) //
        .edge_copy(CustomEdgeCopy{}));

Note that .edge_copy is chained on the vertex_copy() named parameter object.

Then, still things wouldn't compiler because the custom copiers should take descriptors, not bundle references:

struct CustomVertexCopy {
    BGType const& g1;
    BGType&       g2;

    void operator()(BGType::vertex_descriptor v1, BGType::vertex_descriptor v2) const {
        vertexProps const& p1 = g1[v1];
        vertexProps&       p2 = g2[v2];

        p2._refPtr     = p1._refPtr;
        p2._moduleName = p1._moduleName;
        p2._name       = p1._name;
    }
};

Now it will all work:

Live On Coliru

#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/copy.hpp>
#include <boost/graph/graphviz.hpp>

class vertexProps {
  public:
    explicit vertexProps(std::string const* mn = nullptr, std::string const* n = nullptr, long refPtr = 0)
        : _refPtr(refPtr) {
        _moduleName = mn ? *mn : "";
        _name       = n ? *n : "";
    }

    std::string _moduleName;
    std::string _name;
    long        _refPtr;
};

class edgeProps {
   public:
     explicit edgeProps(std::string name = "") : _name(name){};
     std::string _name;
};

struct graphProps {};

using BGType = boost::adjacency_list<                //
    boost::vecS, boost::vecS, boost::bidirectionalS, //
    vertexProps, edgeProps, graphProps>;

struct CustomVertexCopy {
    BGType const& g1;
    BGType&       g2;

    void operator()(BGType::vertex_descriptor v1, BGType::vertex_descriptor v2) const {
        vertexProps const& p1 = g1[v1];
        vertexProps&       p2 = g2[v2];

        p2._refPtr     = p1._refPtr;
        p2._moduleName = p1._moduleName;
        p2._name       = p1._name;
    }
};

struct CustomEdgeCopy {
    BGType const& g1;
    BGType&       g2;

    void operator()(BGType::edge_descriptor e1, BGType::edge_descriptor e2) const {
        g2[e2]._name = g1[e1]._name;
    }
};

int main() {
    BGType g1(3);
    std::string const names[] {"Hello", "world", "Goodbye", "moon", "Greetings", "Cosmos"};
    g1[0] = vertexProps{names + 0, names + 1, 111};
    g1[1] = vertexProps{names + 2, names + 3, 222};
    g1[2] = vertexProps{names + 4, names + 5, 333};
    add_edge(0, 1, edgeProps{"one"}, g1);
    add_edge(2, 0, edgeProps{"two"}, g1);

    BGType g2;

    boost::copy_graph(                               //
        g1, g2,                                      //
        boost::vertex_copy(CustomVertexCopy{g1, g2}) //
            .edge_copy(CustomEdgeCopy{g1, g2}));

    boost::dynamic_properties dp;
    dp.property("node_id",    get(boost::vertex_index,       g2));
    dp.property("moduleName", get(&vertexProps::_moduleName, g2));
    dp.property("name",       get(&vertexProps::_name,       g2));
    dp.property("ref",        get(&vertexProps::_refPtr,     g2));
    dp.property("name",       get(&edgeProps::_name,         g2));
    write_graphviz_dp(std::cout, g2, dp);
}

Prints

digraph G {
0 [moduleName=Hello, name=world, ref=111];
1 [moduleName=Goodbye, name=moon, ref=222];
2 [moduleName=Greetings, name=Cosmos, ref=333];
0->1  [name=one];
2->0  [name=two];
}

BONUS

Simplify! Just make the properties copyable, and you're done, with 20 fewer lines of code, which is roughly 30% less room for error/pessimizations:

Live On Coliru

#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/copy.hpp>
#include <boost/graph/graphviz.hpp>

class vertexProps {
  public:
    vertexProps(vertexProps const&) = default;
    vertexProps& operator=(vertexProps const&) = default;

    explicit vertexProps(std::string const* mn = nullptr, std::string const* n = nullptr, long refPtr = 0)
        : _refPtr(refPtr) {
        _moduleName = mn ? *mn : "";
        _name       = n ? *n : "";
    }

    std::string _moduleName;
    std::string _name;
    long        _refPtr;
};

class edgeProps {
   public:
     edgeProps(edgeProps const&)            = default;
     edgeProps& operator=(edgeProps const&) = default;
     explicit edgeProps(std::string name = "") : _name(name){};

     std::string _name;
};

struct graphProps {};

using BGType = boost::adjacency_list<                //
    boost::vecS, boost::vecS, boost::bidirectionalS, //
    vertexProps, edgeProps, graphProps>;

int main() {
    BGType g1(3);
    std::string const names[] {"Hello", "world", "Goodbye", "moon", "Greetings", "Cosmos"};
    g1[0] = vertexProps{names + 0, names + 1, 111};
    g1[1] = vertexProps{names + 2, names + 3, 222};
    g1[2] = vertexProps{names + 4, names + 5, 333};
    add_edge(0, 1, edgeProps{"one"}, g1);
    add_edge(2, 0, edgeProps{"two"}, g1);

    BGType g2;

    boost::copy_graph(g1, g2);

    boost::dynamic_properties dp;
    dp.property("node_id",    get(boost::vertex_index,       g2));
    dp.property("moduleName", get(&vertexProps::_moduleName, g2));
    dp.property("name",       get(&vertexProps::_name,       g2));
    dp.property("ref",        get(&vertexProps::_refPtr,     g2));
    dp.property("name",       get(&edgeProps::_name,         g2));
    write_graphviz_dp(std::cout, g2, dp);
}

Still printing

digraph G {
0 [moduleName=Hello, name=world, ref=111];
1 [moduleName=Goodbye, name=moon, ref=222];
2 [moduleName=Greetings, name=Cosmos, ref=333];
0->1  [name=one];
2->0  [name=two];
}