Change edge target in boost graph

Viewed 35

Assume I have a simple graph with three vertices, How could I change output edge of 0 to 2 instead of 1

enter image description here

Note: I don't want to do it while creating the graph.

1 Answers

Assuming the simple graph that you left out of the question:

auto simple_graph() {
    boost::adjacency_list<> g;
    add_edge(0, 1, g);
    add_edge(1, 2, g);
    return g;
}

Now the absolute simplest you can do for this graph model is

// change (0,1) to (0,2):
remove_edge(0, 1, g);
add_edge(0, 2, g);

Demo

Live On Compiler Explorer

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

auto simple_graph() {
    boost::adjacency_list<> g;
    add_edge(0, 1, g);
    add_edge(1, 2, g);
    return g;
}

int main() {
    auto g = simple_graph();
    write_graphviz(std::cout, g);

    // change (0,1) to (0,2):
    remove_edge(0, 1, g);
    add_edge(0, 2, g);

    write_graphviz(std::cout, g);
}

Prints

digraph G {
0;
1;
2;
0->1 ;
1->2 ;
}
digraph G {
0;
1;
2;
0->2 ;
1->2 ;
}

So indeed becomes

Other Graph Types

In case you had other graph types, other approaches become natural:

Live: edge list

#include <boost/graph/edge_list.hpp>
#include <boost/graph/graphviz.hpp>

int main() {
    std::vector edges{std::pair{0, 1}, {1, 2}};
    boost::edge_list g(edges.begin(), edges.end());

    // change (0,1) to (0,2):
    edges[0].second = 2;
}

UPDATE: Bonus Preserving Properties

I'd write a 5-line helper function:

template <typename V, typename G>
void update_edge_target(V source, V target, V new_target, G& g) {
    if (auto [e, exists] = edge(source, target, g); exists) {
        auto prop = std::move(g[e]);
        remove_edge(e, g);
        add_edge(source, new_target, prop, g);
    }
}

Note: I don't think BGL supports move semantics, so splitting the last line could improve efficiency:

    e = add_edge(source, new_target, g);
    g[e] = std::move(prop);

See it Live On Compiler Explorer

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

struct EdgeProps {
    std::map<int, std::string> lots;
    std::string more;
};

auto simple_graph() {
    using namespace boost;
    adjacency_list<vecS, vecS, directedS, no_property, EdgeProps> g;
    add_edge(0, 1,
            {{
                {1, "one"},
                {2, "two"},
                {3, "three"},
            },
            "very heavy data!"},
            g);
    add_edge(1, 2,
            {{
                {4, "four"},
                {5, "five"},
                {6, "size"},
            },
            "needs preserving"},
            g);
    return g;
}

template <typename V, typename G>
void update_edge_target(V source, V target, V new_target, G& g) {
    if (auto [e, exists] = edge(source, target, g); exists) {
        auto prop = std::move(g[e]);
        remove_edge(e, g);
        add_edge(source, new_target, prop, g);
    }
}

// for debug output
#include <fmt/ranges.h>
template <typename G> struct writer : boost::default_writer {
    G const& g;
    explicit writer(G const& g) : g(g) {}

    void operator()(std::ostream& os, auto const& desc) const { handle(os, g[desc]); }

private:
    void handle(std::ostream& os, boost::no_property) const { os << "[]"; }
    void handle(std::ostream& os, EdgeProps const& ep) const {
        os << "[label=" << boost::escape_dot_string(ep.more)
        << ",extra=" << boost::escape_dot_string(fmt::format("{}", ep.lots))
        << "]";
    }
};

int main() {
    auto g = simple_graph();

    writer w{g};
    write_graphviz(std::cout, g, w, w);

    // change (0,1) to (0,2):
    update_edge_target(0, 1, 2, g);

    write_graphviz(std::cout, g, w, w);
}

Prints

digraph G {
0[];
1[];
2[];
0->1 [label="very heavy data!",extra="{1: \"one\", 2: \"two\", 3: \"three\"}"];
1->2 [label="needs preserving",extra="{4: \"four\", 5: \"five\", 6: \"size\"}"];
}
digraph G {
0[];
1[];
2[];
0->2 [label="very heavy data!",extra="{1: \"one\", 2: \"two\", 3: \"three\"}"];
1->2 [label="needs preserving",extra="{4: \"four\", 5: \"five\", 6: \"size\"}"];
}

Which renders: to

Related