Search code examples
c++c++11graphboost-graph

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


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;
}

Solution

  • 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];
    }