如何将一个Boost图的图形属性复制到另一个Boost图?

问题描述 投票:0回答:1

我有一个带有顶点、边和图属性的增强图。我想复制一份 boost braph。我将一个增强图的顶点和边属性(使用

copy_graph
)复制到另一个增强图中,但无法复制图属性。

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

我有图形属性:

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

我的copy_graph是这样的:

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
}

如何复制图表属性?

c++ boost c++17 boost-graph
1个回答
0
投票

简单来说

  • boost::copy_graph
    不支持。

  • 只需复制分配就可以了:

    boost::get_property(g2) = boost::get_property(g1)
    

改编自您之前的演示问题:

住在Coliru

#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graphviz.hpp>
#include <fmt/ranges.h>

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

    explicit vertexProps(std::string mn = {}, std::string n = {}, long refPtr = 0)
        : _moduleName(std::move(mn))
        , _name(std::move(n))
        , _refPtr(refPtr) {}

    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 schPinInfo { std::string id; };
schPinInfo const wellknownPins[] = {
    {"i1"}, {"i2"}, {"i3"}, {"o4"}, {"o5"}, {"i6"}, {"i7"}, {"i8"}, {"o9"}, {"o10"},
};

static schPinInfo const* const i1  = wellknownPins + 0;
static schPinInfo const* const i2  = wellknownPins + 1;
static schPinInfo const* const i3  = wellknownPins + 2;
static schPinInfo const* const o4  = wellknownPins + 3;
static schPinInfo const* const o5  = wellknownPins + 4;
static schPinInfo const* const i6  = wellknownPins + 5;
static schPinInfo const* const i7  = wellknownPins + 6;
static schPinInfo const* const i8  = wellknownPins + 7;
static schPinInfo const* const o9  = wellknownPins + 8;
static schPinInfo const* const o10 = wellknownPins + 9;

using Pins = std::vector<schPinInfo const*>;
struct Layout {
    Pins input, inout, output;
};
struct schSymbol {};

struct graphProps {
    graphProps& operator=(graphProps const&) = default;
    explicit graphProps(std::string name = {}) : _name(std::move(name)) {}

    std::string                                     _name;
    std::map<std::string, Layout>                   _modInfo;
    std::map<std::string, std::vector<std::string>> _altNames;
    std::map<std::string, schSymbol>                _modSymbol;
};

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

int main() {
    BGType g2;

    {
        BGType g1{3, graphProps{"name"}};
        {
            boost::get_property(g1)._modInfo = {
                {"mod1", Layout{{i1, i2, i3}, {}, {o4, o5}}},
                {"mod2", Layout{{i6, i7, i8}, {}, {o9, o10}}},
            };
            boost::get_property(g1)._altNames = {
                {"mod1", {"MOD1", "MOD_1"}},
                {"mod2", {"MOD2", "MOD_2"}},
            };
            boost::get_property(g1)._modSymbol = {
                {"mod1", schSymbol{}},
                {"mod2", schSymbol{}},
            };

            g1[0] = vertexProps{"Hello", "world", 111};
            g1[1] = vertexProps{"Goodbye", "moon", 222};
            g1[2] = vertexProps{"Greetings", "Cosmos", 333};

            add_edge(0, 1, edgeProps{"one"}, g1);
            add_edge(2, 0, edgeProps{"two"}, g1);
        }

        g2 = g1; // FULL COPY
        // copy_graph(g1, g2); // doesn't copy graph property
    }

    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));
    dp.property("name", get(&edgeProps::_name, g2));
    write_graphviz_dp(std::cout, g2, dp);

    fmt::print("Copied _altNames: {}\n", boost::get_property(g2)._altNames);
}

打印

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, name=one];
2->0  [name=two, name=two];
}
Copied _altNames: {"mod1": ["MOD1", "MOD_1"], "mod2": ["MOD2", "MOD_2"]}

深度克隆动态数据

如果您希望

schPinInfo
对象也被深度复制怎么办?为了正确进行对象跟踪,以便重复的引脚不会被多次序列化(反序列化),我建议使用 Boost Serialization:

住在Coliru

#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/graph/adj_list_serialize.hpp>
#include <boost/serialization/map.hpp>
#include <boost/serialization/vector.hpp>

#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graphviz.hpp>
#include <fmt/ranges.h>

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

    explicit vertexProps(std::string mn = {}, std::string n = {}, long refPtr = 0)
        : _moduleName(std::move(mn))
        , _name(std::move(n))
        , _refPtr(refPtr) {}

    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 schPinInfo { std::string id; };
schPinInfo const wellknownPins[] = {
    {"i1"}, {"i2"}, {"i3"}, {"o4"}, {"o5"}, {"i6"}, {"i7"}, {"i8"}, {"o9"}, {"o10"},
};

static schPinInfo const* const i1  = wellknownPins + 0;
static schPinInfo const* const i2  = wellknownPins + 1;
static schPinInfo const* const i3  = wellknownPins + 2;
static schPinInfo const* const o4  = wellknownPins + 3;
static schPinInfo const* const o5  = wellknownPins + 4;
static schPinInfo const* const i6  = wellknownPins + 5;
static schPinInfo const* const i7  = wellknownPins + 6;
static schPinInfo const* const i8  = wellknownPins + 7;
static schPinInfo const* const o9  = wellknownPins + 8;
static schPinInfo const* const o10 = wellknownPins + 9;

using Pins = std::vector<schPinInfo const*>;
struct Layout {
    Pins input, inout, output;
};
struct schSymbol {};

struct graphProps {
    graphProps& operator=(graphProps const&) = default;
    explicit graphProps(std::string name = {}) : _name(std::move(name)) {}

    std::string                                     _name;
    std::map<std::string, Layout>                   _modInfo;
    std::map<std::string, std::vector<std::string>> _altNames;
    std::map<std::string, schSymbol>                _modSymbol;
};

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

void serialize(auto& ar, vertexProps& p, unsigned) { ar& p._moduleName& p._name& p._refPtr;              } 
void serialize(auto& ar, edgeProps& p, unsigned)   { ar& p._name;                                        } 
void serialize(auto& ar, graphProps& p, unsigned)  { ar& p._name& p._modInfo& p._altNames& p._modSymbol; } 
void serialize(auto&, schSymbol&, unsigned)        {                                                     } 
void serialize(auto& ar, schPinInfo& i, unsigned)  { ar& i.id;                                           } 
void serialize(auto& ar, Layout& l, unsigned)      { ar& l.input& l.inout& l.output;                     } 

BGType deep_copy(BGType const& g1) {
    std::stringstream ss;
    boost::archive::binary_oarchive(ss) << g1;

    BGType g2;
    boost::archive::binary_iarchive(ss) >> g2; 
    return g2;
}

int main() {
    BGType g2;

    {
        BGType g1{3, graphProps{"name"}};
        {
            boost::get_property(g1)._modInfo = {
                {"mod1", Layout{{i1, i2, i3}, {}, {o4, o5}}},
                {"mod2", Layout{{i6, i7, i8}, {}, {o9, o10}}},
            };
            boost::get_property(g1)._altNames = {
                {"mod1", {"MOD1", "MOD_1"}},
                {"mod2", {"MOD2", "MOD_2"}},
            };
            boost::get_property(g1)._modSymbol = {
                {"mod1", schSymbol{}},
                {"mod2", schSymbol{}},
            };

            g1[0] = vertexProps{"Hello", "world", 111};
            g1[1] = vertexProps{"Goodbye", "moon", 222};
            g1[2] = vertexProps{"Greetings", "Cosmos", 333};

            add_edge(0, 1, edgeProps{"one"}, g1);
            add_edge(2, 0, edgeProps{"two"}, g1);

            assert(boost::get_property(g1)._modInfo["mod2"].input.at(0) == i6);
            assert(boost::get_property(g1)._modInfo["mod2"].input.at(1) == i7);
            assert(boost::get_property(g1)._modInfo["mod2"].input.at(2) == i8);
            assert(boost::get_property(g1)._modInfo["mod2"].output.at(0) == o9);
            assert(boost::get_property(g1)._modInfo["mod2"].output.at(1) == o10);
        }

        g2 = deep_copy(g1); // even deeply copied schPinInfo const* objects!

        assert(boost::get_property(g2)._modInfo["mod2"].input.at(0) != i6);
        assert(boost::get_property(g2)._modInfo["mod2"].input.at(1) != i7);
        assert(boost::get_property(g2)._modInfo["mod2"].input.at(2) != i8);
        assert(boost::get_property(g2)._modInfo["mod2"].output.at(0) != o9);
        assert(boost::get_property(g2)._modInfo["mod2"].output.at(1) != o10);
    }

    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));
    dp.property("name", get(&edgeProps::_name, g2));
    write_graphviz_dp(std::cout, g2, dp);

    fmt::print("Copied _altNames: {}\n", boost::get_property(g2)._altNames);

    // note the deeply allocated schPinInfo are leaked!
}

印刷

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, name=one];
2->0  [name=two, name=two];
}
Copied _altNames: {"mod1": ["MOD1", "MOD_1"], "mod2": ["MOD2", "MOD_2"]}

备注:

  • 断言全部通过 - 使深度克隆

    schPinInfo
    变得有形。

  • schPinInfo
    的反序列化实例现已泄漏,这就是为什么您不应该使用原始指针:

    ==794912==ERROR: LeakSanitizer: detected memory leaks
    
    Direct leak of 320 byte(s) in 10 object(s) allocated from:
        #0 0x7f11ffec21e7 in operator new(unsigned long) ../../../../src/libsanitizer/asan/asan_new_delete.cpp:99
        #1 0x55698a066997 in boost::archive::detail::heap_allocation<schPinInfo>::doesnt_have_new_operator::invoke_new() /home/sehe/custom/superboost/boost/archive/detail/iserializer.hpp:243
        #2 0x55698a066997 in boost::archive::detail::heap_allocation<schPinInfo>::invoke_new() /home/sehe/custom/superboost/boost/archive/detail/iserializer.hpp:257
        #3 0x55698a066997 in boost::archive::detail::heap_allocation<schPinInfo>::heap_allocation() /home/sehe/custom/superboost/boost/archive/detail/iserializer.hpp:270
        #4 0x55698a066997 in boost::archive::detail::pointer_iserializer<boost::archive::binary_iarchive, schPinInfo>::heap_allocation() const /home/sehe/custom/superboost/boost/archive/detail/iserializer.hpp:295
    
    SUMMARY: AddressSanitizer: 320 byte(s) leaked in 10 allocation(s).
    
© www.soinside.com 2019 - 2024. All rights reserved.