|
Boost Users : |
Subject: [Boost-users] [Graph] Newbie on A*
From: Sensei (senseiwa_at_[hidden])
Date: 2014-05-28 03:30:13
Dear all,
I am fiddling with the A* example on cities in order to learn how to use
the A* search. Obviously, I cannot make it work :)
The main goal is this, but I'm way too far from this: make A* fail when
the path is longer, **not costlier**, than a constant.
But right now I'd just like to have A* working on a graph. :)
In order to see the different results, I've paired it with a Dijkstra
search, and my A* heuristics is quite simple: constant. Dijkstra works
fine, but A* stops at the first node, and the target isn't reached (but
a path is available).
What am I doing wrong? Forgive me if I'm making a stupid mistake bu I'm
completely a newbie!
If you need the graph, here's the link:
https://dl.dropboxusercontent.com/u/15635416/g.txt
Thanks!
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <utility>
#include <algorithm>
#include <numeric>
#include <deque>
#include <unordered_set>
#include <vector>
#include <fstream>
#include <list>
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/compressed_sparse_row_graph.hpp>
#include <boost/graph/dijkstra_shortest_paths.hpp>
#include <boost/graph/breadth_first_search.hpp>
#include <boost/graph/depth_first_search.hpp>
#include <boost/pending/indirect_cmp.hpp>
#include <boost/range/irange.hpp>
#include <boost/property_map/property_map.hpp>
#include <boost/graph/astar_search.hpp>
// Properties: weights are int
typedef boost::property<boost::edge_weight_t, int> edge_weight;
// The graph itself as a compressed sparse row matrix
typedef boost::compressed_sparse_row_graph<boost::bidirectionalS,
boost::no_property, edge_weight> boost_graph;
// Vertex iterator
typedef boost::graph_traits<boost_graph>::vertex_iterator vertex_iterator;
// Edge iterator
typedef boost::graph_traits<boost_graph>::edge_iterator edge_iterator;
// Adjacent nodes iterator
typedef boost::graph_traits<boost_graph>::adjacency_iterator
adjacency_iterator;
typedef boost::graph_traits<boost_graph>::out_edge_iterator
outward_iterator;
typedef boost::graph_traits<boost_graph>::in_edge_iterator
inward_iterator;
// Property maps
typedef boost::property_map<boost_graph, boost::vertex_index_t>::type
index_map;
//typedef boost::property_map<boost_graph, boost::vertex_name_t> name_map;
// Property iterators
typedef boost::iterator_property_map<std::size_t*, index_map,
std::size_t, std::size_t&> predecessor_map;
typedef boost::iterator_property_map<std::size_t*, index_map,
std::size_t, std::size_t&> distance_map;
bool isValid(std::size_t index)
{
return (index >= 0) && (index <= 12);
}
//
****************************************************************************
// A* heuristics
template <class graph_type>
class astar_heuristic : public boost::astar_heuristic<graph_type,
std::size_t>
{
public:
typedef typename boost::graph_traits<graph_type>::vertex_descriptor
vertex_type;
astar_heuristic(vertex_type goal) : goal_(goal) { };
std::size_t operator()(vertex_type u)
{
return 3;
}
private:
vertex_type goal_;
};
// Class to be used to terminate the A* algorithm
class exit_astar
{
public:
exit_astar(bool found) { };
};
// A* visitor that terminates when we find the goal
template <class vertex_type>
class astar_visitor : public boost::default_astar_visitor
{
public:
astar_visitor(vertex_type goal) : goal_(goal) { };
template <class Graph>
void examine_vertex(vertex_type u, Graph& g)
{
//std::cout << "EXAM: " << u << std::endl;
if (u == goal_) throw exit_astar(true);
}
private:
vertex_type goal_;
};
//
****************************************************************************
int main(int argc, const char * argv[])
{
std::vector<std::pair<std::size_t, std::size_t>> graph_edges;
std::vector<int> edge_weight;
int n_nodes;
int read_a, read_b, read_w;
n_nodes = -1;
std::ifstream
igraph("/Users/senseiwa/Documents/Projects/scratch/tbb/g.txt");
while(igraph >> read_a >> read_b >> read_w)
{
if (read_a > n_nodes) n_nodes = read_a;
if (read_b > n_nodes) n_nodes = read_b;
read_a--; read_b--;
graph_edges.push_back(std::make_pair(read_a, read_b));
edge_weight.push_back(read_w);
}
std::cout << "+++ READ # NODES: " << n_nodes << std::endl;
// Create the graph
boost_graph graph(boost::edges_are_unsorted_multi_pass,
graph_edges.begin(), graph_edges.end(), edge_weight.data(), n_nodes);
std::cout << "Graph statistics: " << std::endl;
std::cout << "Nodes: " << boost::num_vertices(graph) << std::endl;
std::cout << "Edges: " << graph_edges.size() << std::endl;
edge_iterator ei, ee;
std::size_t source_node = std::stoul(argv[1]);
std::size_t destination_node = std::stoul(argv[2]);
std::cout << ">> SOURCE NODE " << source_node << std::endl;
std::cout << "Degrees in/out: " << source_node << std::endl;
std::cout << boost::in_degree(boost::vertex(source_node, graph),
graph) << std::endl;
std::cout << boost::out_degree(boost::vertex(source_node, graph),
graph) << std::endl;
std::cout << "Degrees in/out: " << destination_node << std::endl;
std::cout << boost::in_degree(boost::vertex(destination_node,
graph), graph) << std::endl;
std::cout << boost::out_degree(boost::vertex(destination_node,
graph), graph) << std::endl;
std::vector<std::size_t> preds(boost::num_vertices(graph));
std::vector<std::size_t> dists(boost::num_vertices(graph));
index_map idx_map = boost::get(boost::vertex_index, graph);
predecessor_map pred_map(preds.data(), idx_map);
distance_map dist_map(dists.data(), idx_map);
boost::dijkstra_shortest_paths(graph, source_node,
boost::distance_map(dist_map).predecessor_map(pred_map));
typedef std::vector<boost_graph::edge_descriptor> path_type;
path_type spath;
std::cout << ">> SOURCE NODE " << source_node << std::endl;
std::cout << ">> DESTINATION NODE " << destination_node << std::endl;
// ******* DIJKSTRA
********************************************************
std::size_t v = destination_node; // We want to start at the
destination and work our way back to the source
for(std::size_t u = pred_map[v]; // Start by setting 'u' to
the destintaion node's predecessor
u != v; // Keep tracking the path
until we get to the source
v = u, u = pred_map[v]) // Set the current vertex
to the current predecessor, and the predecessor to one level up
{
std::pair<boost_graph::edge_descriptor, bool> edgePair =
boost::edge(u, v, graph);
boost_graph::edge_descriptor edge = edgePair.first;
spath.push_back(edge);
}
// Write shortest path
int totalDistance = 0;
for(path_type::reverse_iterator pathIterator = spath.rbegin();
pathIterator != spath.rend(); ++pathIterator)
{
std::cout << boost::source(*pathIterator, graph) << " - " <<
boost::target(*pathIterator, graph)
<< " = " << boost::get(boost::edge_weight, graph,
*pathIterator) << std::endl;
totalDistance += boost::get(boost::edge_weight, graph,
*pathIterator);
}
std::cout << "Shortest Dijkstra path from " << source_node << " to
" << destination_node << " cost " << totalDistance << std::endl;
// ******* A*
**************************************************************
// A* search predecessor and cost
std::vector<std::size_t> p(boost::num_vertices(graph));
std::vector<std::size_t> d(boost::num_vertices(graph));
try
{
// A* parameter interface
astar_search(graph, source_node,
astar_heuristic<boost_graph>(destination_node),
boost::predecessor_map(&p[0]).distance_map(&d[0]).visitor(astar_visitor<std::size_t>(destination_node)));
}
catch(exit_astar fg)
{
std::list<std::size_t> shortest_path;
for(std::size_t v = source_node; ; v = p[v])
{
shortest_path.push_front(v);
if(p[v] == v)
break;
}
auto spi = shortest_path.begin();
std::cout << "node " << source_node << std::endl;
for(++spi; spi != shortest_path.end(); ++spi)
std::cout << "node " << *spi << std::endl;
std::cout << "Shortest A* path from " << source_node << " to "
<< destination_node << " cost " << d[destination_node] << std::endl;
std::cout << shortest_path.size() << std::endl;
return 0;
}
std::cout << "Didn't find a path from " << source_node << "to" <<
destination_node << "!" << std::endl;
return 0;
}
+++ READ # NODES: 200
Graph statistics:
Nodes: 200
Edges: 4000
>> SOURCE NODE 1
Degrees in/out: 1
0
35
Degrees in/out: 192
39
1
>> SOURCE NODE 1
>> DESTINATION NODE 192
1 - 47 = 2
47 - 91 = 3
91 - 120 = 1
120 - 175 = 1
175 - 192 = 10
Shortest Dijkstra path from 1 to 192 cost 17
node 1
Shortest A* path from 1 to 192 cost 17
1
Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net