-1

I have a directed graph, which I know doesn't have any circular dependencies and have "termination" nodes i.e they have a custom vertex property, which is a bool that I can check. Each edge is weighted using the BGL built-in edge weight property.

What I want to do is walk from any vertex along all possible paths, until it hits all the termination nodes that can be reached and track the "weighted" edge weights of each termination node reached. By this I mean the following is best explained by the following simple example.

Say from node 4 there are following out edges with weights and if T (a termination)

4->1 : 0.25 : T
4->5 : 0.45
4->6 : 0.5
5->2 : 0.65 : T
6->3 : 0.18 
6->7 : 0.44 : T
3->1 : 0.33 : T

I want to return a vector of pairs which is the termination nodes / "weighted" combination of edge weights that were walked on its way to each node, which in this case would be :

{1, 0.25 + (0.5*0.18*0.33) }
{2, (0.45*0.65)}
{7, (0.5*0.44)}
Final Result : [ {1, 0.2797}, {2, 0.2925}, {7, 0.22}]

By "weighted", i mean each new step is weighted by the product of all previous edge weights walked on a particular path.

So from 4 to termination node 1, there are two paths. An direct edge to 1, weighted by 0.25. There is also a path that goes 4->6->3->1, so that is 0.5*0.18*0.33. Therefore, for node 1, we have a total resultant weight of 0.25 + (0.5*0.18*0.33) = 0.2797.

Again from 4 to termination node 2, there is an path to 4->5->2 (0.45*0.65), so node 2 = 0.2925

And finally 4 to termination node 7, path 4->6->7, (0.5*0.44), so node 7 = 0.22

Is this possible in BGL, I presume I need some sort of custom visitor / predecessor?

Any help much appreciated.

oracle3001
  • 1,090
  • 19
  • 31
  • How do 0.5*0.18*0.33 come in on 4->1? 1 is a leaf node, and there's the direct edge to it, so it would seem that no other edges would be traversed? Even more confusing to me, 0.5 appears to come from the 4->6 edge, 0.18 from the 6->3 edge and 0.33 from the 3->1 edge. I'm not sure how any of these edges would be involved when starting from vertex 4, and having vertex 1 as the terminal vertex. Perhaps you can clarify the procedure/logic a little? – sehe Feb 06 '19 at 13:36
  • I suspect you're describing something in roundabout terms that might be a "standard" algorithm (is there a name for the algorithm you're trying to achieve?) – sehe Feb 06 '19 at 13:37
  • I just caught your edit. Reading. – sehe Feb 06 '19 at 13:38

1 Answers1

-1

Your example calculations are pretty confusing. I'm assuming you meant to do what your description says: "sum of weighted edge weights that were walked on its way to each node", so:

{1, 0.25}
{2, (0.45+0.65)}
{7, (0.5+0.44)}
Final Result : [ {1, 0.25}, {2, 1.1}, {7, 0.94}]

This is a shortest-paths problem. If you e.g. use dijkstra_shortest_paths the result you are looking for would be in distance_map. Simply select the "termination vertices" from that map and you're done:

Live On Coliru

//#include <boost/spirit/home/x3.hpp>
#include <boost/graph/adjacency_list.hpp>

using Weight = double;
struct EdgeProps { Weight weight = 0; };

using Graph = boost::adjacency_list<
    boost::vecS, boost::vecS, boost::directedS, boost::no_property, EdgeProps>;

Graph make_sample();

#include <boost/graph/dijkstra_shortest_paths.hpp>
#include <boost/graph/graph_utility.hpp>

int main() {

    auto const g     = make_sample();
    auto const start = vertex(4, g);

    print_graph(g);

    // property-maps maps for dijkstra:
    auto constexpr INF = std::numeric_limits<Weight>::infinity();
    std::vector<Graph::vertex_descriptor> pred(num_vertices(g));
    std::vector<Weight> dist(num_vertices(g), INF);

    dijkstra_shortest_paths(g, start, boost::predecessor_map(pred.data())
            .distance_map(dist.data())
            .weight_map(get(&EdgeProps::weight, g))
            .distance_inf(INF));

    // print results
    std::cout << "Final Result : [ ";

    for (auto vd : boost::make_iterator_range(vertices(g))) {
        if (INF != dist[vd] && 0 == out_degree(vd, g)) {         // if reachable and leaf,
            std::cout << "{" << vd << ", " << dist[vd] << "}, "; // print total distance from start
        }
    }

    std::cout << "}\n";
}

Graph make_sample() {
    Graph g(8);
    add_edge(4, 1, EdgeProps{0.25}, g); // : T
    add_edge(4, 5, EdgeProps{0.45}, g);
    add_edge(4, 6, EdgeProps{0.5},  g);
    add_edge(5, 2, EdgeProps{0.65}, g); // : T
    add_edge(6, 3, EdgeProps{0.18}, g);
    add_edge(6, 7, EdgeProps{0.44}, g); // : T
    add_edge(3, 1, EdgeProps{0.33}, g); // : T
    return g;
}

Prints

0 --> 
1 --> 
2 --> 
3 --> 1 
4 --> 1 5 6 
5 --> 2 
6 --> 3 7 
7 --> 
Final Result : [ {1, 0.25}, {2, 1.1}, {7, 0.94}, }
sehe
  • 374,641
  • 47
  • 450
  • 633
  • NO, I don't mean "sum of weighted edge weights that were walked on its way to each node". The required weighting as shown in the example are what I want. Taking the example, node 1 weighting, is the combination of the edge 4->1 (0.25), plus the walk from 4->6 (0.5), 6->3 (0.18), 3->1 (0.33) hence, 1= 0.25 + (0.5*0.18*0.33). Each new step is weighted by previous steps. – oracle3001 Feb 06 '19 at 13:14
  • Hey. It's exactly what your description said. So, excuse me for not understanding your seemingly contradicting example. I would be willing to look at your clarification (do edit your question as well!) but I'm confused by the downvote. If that's yours, I'll leave it at this, I guess. – sehe Feb 06 '19 at 13:25
  • I am not trying to summing edge weights in the way you suggest. Each step along an edge is weighted by the previous steps. It is a little hard to describe, hence why I tried with an example. I have double checked what I put for the result I want, and it is correct in terms of the numbers. – oracle3001 Feb 06 '19 at 13:29
  • Okay, I'll find a moment to try and understand it again – sehe Feb 06 '19 at 13:31
  • I have edited the original post, hopefully it makes it clearer. – oracle3001 Feb 06 '19 at 13:38