I'm trying to create a graph where lanes represent vertices and edges connections between. The idea is to later on use a_star algorithm to traverse the graph and find the best route.
My question is how can I get vertex (descriptor?) by using just (town_id, road_id, lane_id)?
I tryied battling with the examples that are shipped with boost and basically lost. In them they always traverse thru all the vertices and then get the vertex_descriptor, but I want to do that in constant time.
What is need is something like boost::get_vertex(std::tuple(1, 2, 3), graph).
My situation is marked as PROBLEM bellow in the code. The code bellow compiles because there is 12 that I guess corresponds to the index in boost::vecS, but I want to use a tuple (or something else that can hold the triplet) that could get me the vertex descriptor as my starting location.
using TRL = std::tuple<int, int, int>;
struct TRL_VProp {
/// For some reason this object has to be default constructable
/// use invalid data to flag it as invalid
TRL_VProp()
: trl(-1, -1, 0) {}
TRL_VProp(TRL trl)
: trl(trl) {}
TRL_VProp(int town_id, int road_id, int lane_id)
: trl(town_id, road_id, lane_id) {}
TRL trl;
};
using DirectedGraph = boost::adjacency_list<boost::listS,
boost::vecS,
boost::directedS,
RSL_VProp>;
using Vertex = boost::graph_traits<DirectedGraph>::vertex_descriptor;
using VertexI = boost::graph_traits<DirectedGraph>::vertex_iterator;
using EdgeI = boost::graph_traits<DirectedGraph>::edge_iterator;
using Edge = boost::graph_traits<DirectedGraph>::edge_descriptor;
using AdjI = boost::graph_traits<DirectedGraph>::adjacency_iterator;
using Route = std:vector<TRL>;
Route BuildRoute(Map & map) {
Route result;
DirectedGraph graph;
const boost::property_map<DirectedGraph, RSL RSL_VProp:: *>::type trl =
boost::get(&TRL_VProp::rsl, graph);
bool is_inserted;
Edge e_desc;
for (auto & town: map.GetTowns()) {
for (auto & road: town.GetRoads()) {
for (auto & lane: road.GetLanes()) {
auto vtx_1 = boost::add_vertex(
RSL_VProp(town.GetId(), road.GetId(), lane.GetId()),
graph);
const auto next_lanes = map.GetNextLanes(town.GetId(), road.GetId(), lane.GetId());
for(const auto & next_lane : next_lanes) {
auto vtx_2 = boost::add_vertex(
TRL_VProp(lane.GetTown().GetId(), lane.GetRoad().GetId(), lane.GetId()),
graph);
std::tie(e_desc, is_inserted) = boost::add_edge(vtx_1, vtx_2, graph);
assert(is_inserted);
}
}
}
}
// debug part
TRL temp_trl;
std::pair<AdjI, AdjI> adj_i = boost::adjacent_vertices(12, graph); // <--- PROBLEM
for( auto i = adj_i.first; i != adj_i.second; i++) {
temp_trl = trl[*i]; // trl prop map
std:: cout << "\Town id: " << std::get<0>(temp_trl)
<< "\nRoad id: " << std::get<1>(temp_trl)
<< "\nLane id: " << std::get<2>(temp_trl);
result.push_back(
std::make_tuple(
std::get<0>(temp_trl),
std::get<1>(temp_trl),
std::get<2>(temp_trl)));
}
return result;
}
For completeness, I don't plan to change data inside the property or the graph itself. Once thing is created it will probably stay that way. Maybe lateron I'll probably have to add the weight or whatever is necessary to get the traversing algorithm to work.
Edit: I forgot to mention that there is a bug in the code because I'm adding vertices before checking was vertex with identical (town, road, lane) already been created. I wonder is there a builtin boost::graph way to not insert duplicated so I won't have to use a std::unordered_map or something.
Related
Objective
Generate a random spanning tree on a randomly generated graph.
Why: because I don't know yet if I can directly generate random trees with specific number of nodes or leaves in BGL.
My problem
I think it boils down to struggling initializing the Auxillary Property Maps to a sensical default.
As you will see I've tried a number of combination of solutions, in the current state the code fails to compile with a cannot form a reference to 'void'.
What I tried
template<class Graph, class Generator>
auto generate_random_spanning_tree(int n_vertices, int n_edges, Generator& rng)
{
// create empty graph
Graph g;
using vertex_t = typename Graph::vertex_descriptor;
using edge_t = typename Graph::edge_descriptor;
// The key and value types of the map must both be the graph's vertex type.
using predecessor_map_t = boost::static_property_map<vertex_t, vertex_t>;
predecessor_map_t predecessor_map = boost::make_static_property_map<vertex_t,vertex_t>(vertex_t());
// unweighted version selected by passing an object of type static_property_map<double> as the weight map, so let's go
using weight_map_t = boost::static_property_map< double >;
// weight_map_t weight_map = boost::make_transform_value_property_map([](edge_t& e) { return 1.0; }, get(boost::edge_bundle, g)); // nope
//weight_map_t weight_map = boost::make_static_property_map<double>(1.0); // yes but complicated
// weight_map_t weight_map; // nope: why isn't it default constructible?
double my_constant_weight = 1.0;
weight_map_t weight_map(my_constant_weight);
using color_map_t = typename boost::property_map<Graph, boost::vertex_color_t>::type;
color_map_t color_map ; // i suspect this is faulty
// mutate graph
boost::generate_random_graph(g, n_vertices, n_edges, rng);
// pick root, I guess we could as well pick 1st vertex
auto root = boost::random_vertex(g, rng);
boost::random_spanning_tree(g, rng, root, predecessor_map, weight_map, color_map);
return g;
}
First: Your own suspect
using color_map_t = typename boost::property_map<Graph, boost::vertex_color_t>::type;
color_map_t color_map; // i suspect this is faulty
Yes. PropertyMaps map properties. They are like references. Here, color_map
is essentially an unitialized reference. You need something like
color_map_t color_map = get(boost::vertex_color, g);
This, of course, assumes that a vertex_color_t property map has been
associated with the graph by traits. In other words, this assumes that the
property is an iternal property of the graph. Internal properties are often
used by default.
Second: A constant cannot be modified
You use a static property map:
auto predecessor_map =
boost::make_static_property_map<vertex_t, vertex_t>(vertex_t());
That just creates a "virtual" property map (without a backing data structure)
that returns the construction parameter on every key. Logically, the return
value is constant. However, predecessor map is an output parameter:
You will need an LValuePropertyMap there. E.g.
std::map<vertex_t, vertex_t> predecessors;
auto predecessor_map =boost::make_assoc_property_map(predecessors);
Or even
auto vindex = get(boost::vertex_index, g);
auto predecessors = std::vector<vertex_t>(num_vertices(g));
auto predecessor_map = boost::make_safe_iterator_property_map(
predecessors.begin(), predecessors.size(), vindex);
Which uses a vertex index to (optionally) translate descriptors into vector
indices. Note that the second is fixed-size, so initialize it after creating
all vertices.
Other Points Of Interest
// weight_map_t weight_map; // nope: why isn't it default constructible?
What would it do? Surely it won't default to what you think is a good default
(1.0). So I'd just write
auto weight_map = boost::static_property_map(1.0);
Simplified
I'd write the entire function as:
template <class Graph, class Generator>
auto generate_random_spanning_tree(int n_vertices, int n_edges, Generator& rng) {
using vertex_t = typename Graph::vertex_descriptor;
Graph g;
generate_random_graph(g, n_vertices, n_edges, rng);
std::map<vertex_t, vertex_t> predecessors;
random_spanning_tree(g, rng, random_vertex(g, rng),
boost::make_assoc_property_map(predecessors),
boost::static_property_map(1.0), // unweighted
get(boost::vertex_color, g));
return g;
}
Functional Problems
You're asking some good questions yourself. But let me start with some observations.
You have Unspecified/Undefined
Behaviour because your
input graph doesn't conform to the requirements:
There must be a path from every non-root vertex of the graph to the
root; the algorithm typically enters an infinite loop when given a
graph that does not satisfy this property, but may also throw the
exception loop_erased_random_walk_stuck if the search reaches a vertex
with no outgoing edges
Indeed, running your code only completes for a few random seeds, and fails
or runs infinitely for others (this is even increasing the chance of
satisfying the requirements by using undirectedS):
Listing
while true; do (set -x; time ./build/sotest& sleep 3; kill %1); done
You are creating the random spanning tree only to completely forget about
it. Did you intend to return the predecessor map as well (or a derived path
representation)?
Your own questions:
"cannot form a reference to 'void'"
Usually indicates an associated property map could not be found (e.g.
what happens if you fail to supply the vertex_color interior
property. In
this case the remedy is simply to use the default color
map:
random_spanning_tree(
g, rng,
boost::root_vertex(random_vertex(g, rng))
.predecessor_map(boost::make_assoc_property_map(predecessors))
.weight_map(boost::static_property_map(1.0)) // unweighted
);
"I don't know yet if I can directly generate random trees with specific
number of nodes or leaves in BGL."
You can generate random graphs with specific number of nodes and leaves -
as you already demonstrate.
trees.
You can also find random spanning trees (given a graph satisfying the preconditions).
To adhere to the preconditions the simplest way would be to generate
undirected graphs, whilst additionally making sure that the result is
connected. A simple, possible inefficient(?) way to ensure it would be to
explicitly connect components:
if (int n = boost::connected_components(ug, cmap); n > 1) {
std::cout << "Connecting " << n << " components:\n";
for (int c = 1; c < n; ++c)
std::cout << "Added " << add_edge(from(c - 1), from(c), ug).first << "\n";
}
It might be more effective to write your own generating algorithm.
BONUS EXAMPLE
Showing the use of connected_components to make sure the graph is fully
connected, and even building a directed tree from undirected source graph. Also
writing graphviz representations of the "raw" (undirected) source and "tree"
(directed spanning tree), it seems to work pretty well.
Live On Coliru
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/connected_components.hpp>
#include <boost/graph/graph_utility.hpp>
#include <boost/graph/graphviz.hpp>
#include <boost/graph/random.hpp>
#include <boost/graph/random_spanning_tree.hpp>
#include <boost/property_map/function_property_map.hpp>
#include <iomanip>
#include <random>
namespace detail {
template <typename T> struct make_undirected { using type = void; };
template <typename A, typename B, typename C, typename D, typename E, typename F>
struct make_undirected<boost::adjacency_list<A, B, C, D, E, F>> {
using type = boost::adjacency_list<A, B, boost::undirectedS, D, E, F>;
};
} // namespace detail
template <typename T> using Undirect = typename detail::make_undirected<T>::type;
template <class Graph, class Generator>
auto generate_random_spanning_tree(int n_vertices, int n_edges, Generator& rng) {
using UG = Undirect<Graph>;
using vertex_t = typename UG::vertex_descriptor;
// assuming integral vertex index for simplicity
static_assert(std::is_same_v<vertex_t, size_t>);
static_assert(std::is_same_v<typename UG::vertex_descriptor,
typename Graph::vertex_descriptor>);
UG ug;
generate_random_graph(ug, n_vertices, n_edges, rng);
vertex_t const root = random_vertex(ug, rng);
print_graph(ug, std::cout << "Raw root: " << root << ", graph:\n");
{ // make connected
std::map<vertex_t, int> components;
auto from = [&](int component) { // just picking the first...
for (auto& [v, c] : components) if (c == component) return v;
throw std::range_error("component");
};
auto cmap = boost::make_assoc_property_map(components);
if (int n = connected_components(ug, cmap); n > 1) {
std::cout << "Connecting " << n << " components:\n";
for (int c = 1; c < n; ++c)
std::cout << "Added " << add_edge(from(c - 1), from(c), ug).first << "\n";
}
}
std::map<vertex_t, vertex_t> predecessors;
random_spanning_tree(
ug, rng,
boost::root_vertex(root) //
.predecessor_map(boost::make_assoc_property_map(predecessors)));
Graph tree(num_vertices(ug)); // build a tree copy
for (auto v : boost::make_iterator_range(vertices(ug)))
if (predecessors.contains(v))
if (auto pred = predecessors.at(v); ug.null_vertex() != pred)
add_edge(predecessors.at(v), v, tree);
auto save = [&predecessors](auto& g, auto name) {
using edge_t = typename std::decay_t<decltype(g)>::edge_descriptor;
auto tree_edge = [&predecessors](auto s, auto t) {
auto it = predecessors.find(s);
return it != end(predecessors) && it->second == t;
};
boost::dynamic_properties dp;
dp.property("node_id", get(boost::vertex_index, g));
dp.property("color",
boost::make_function_property_map<edge_t>([tree_edge, &g](edge_t e) {
auto s = source(e, g), t = target(e, g);
return tree_edge(s, t) || tree_edge(t, s) ? "red" : "gray";
}));
std::ofstream os(name);
write_graphviz_dp(os, g, dp);
};
save(ug, "raw.dot");
save(tree, "tree.dot");
return std::pair(std::move(tree), root);
}
int main(int argc, char** argv) {
using G = boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS>;
auto const seed = argc > 1 ? std::stoull(argv[1]) : std::random_device{}();
std::cout << "seed: " << seed << std::endl;
std::mt19937 prng(seed);
auto [tree, root] = generate_random_spanning_tree<G>(10, 20, prng);
print_graph(tree, std::cout << "From root: " << root << ", tree:\n");
}
Prints the sample seed: 1577455792
Raw root: 7, graph:
0 <--> 7 2 3 7 5 2 8
1 <-->
2 <--> 8 0 4 0 4 9
3 <--> 9 5 0 8
4 <--> 7 7 2 2 5
5 <--> 8 3 0 4
6 <-->
7 <--> 4 4 0 8 0
8 <--> 2 5 7 9 0 3
9 <--> 3 8 2
Connecting 3 components:
Added (0,1)
Added (1,6)
From root: 7, tree:
0 --> 1 3
1 --> 6
2 --> 9
3 --> 5
4 --> 2
5 --> 4 8
6 -->
7 --> 0
8 -->
9 -->
Running locally with:
watch './build/sotest; for a in raw tree; do (set -x ; dot -Tpng -o $a.png $a.dot); done'
Shows random solutions like:
First off, I'm aware of the CGAL GIS tutorial, but I just can't seem to copy properties from Point_set to surface mesh.
Any way, I'm loading the LIDAR point cloud to the point set as follows:
using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel;
using Point = Kernel::Point_3;
using Point_set = CGAL::Point_set_3<Point>;
std::ifstream ifile("input.ply", std::ios_base::binary);
ifile >> point_set;
std::cerr << point_set.size() << " point(s) read" << std::endl;
ifile.close();
I can get the properties via
auto props = point_set.properties();
for (const auto& item : props)
std::cerr << item << std::endl;
// I do know that there exist property "classification" that is of unsigned char type
Point_set::Property_map<unsigned char> original_class_map
= point_set.property_map<unsigned char>("classification").first;
Then, I had tried to set the mesh and had added vertex property, using the code from above mentioned CGAL tutorial. The code below set the point's z coordinate as a property.
auto idx_to_point_with_info
= [&](const Point_set::Index& idx) -> std::pair<Point, Point_set::Index> {
return std::make_pair(point_set.point(idx), idx);
};
using Vbi = CGAL::Triangulation_vertex_base_with_info_2<Point_set::Index, Projection_traits>;
using Fbi = CGAL::Triangulation_face_base_with_info_2<int, Projection_traits>;
using TDS = CGAL::Triangulation_data_structure_2<Vbi, Fbi>;
using TIN_with_info = CGAL::Delaunay_triangulation_2<Projection_traits, TDS>;
TIN_with_info tin_with_info(
boost::make_transform_iterator(point_set.begin(), idx_to_point_with_info),
boost::make_transform_iterator(point_set.end(), idx_to_point_with_info));
auto classification_value = [&](const TIN_with_info::Vertex_handle vh) -> double
{
return vh->point().z();
};
for (TIN_with_info::Vertex_handle vh : tin_with_info.all_vertex_handles())
{ // should work without classification_value, just plain vh->info() = vh->point().z();
vh->info() = classification_value(vh);
}
using Mesh = CGAL::Surface_mesh<Point>;
Mesh tin_class_mesh;
Mesh::Property_map<Mesh::Vertex_index, double> class_map
= tin_class_mesh.add_property_map<Mesh::Vertex_index, double>("v:class").first;
CGAL::copy_face_graph(tin_with_info, tin_class_mesh,
CGAL::parameters::vertex_to_vertex_output_iterator(
boost::make_function_output_iterator(class_lambda)));
std::cerr << tin_class_mesh.number_of_vertices() << " vs " << point_set.size() <<std::endl;
Now, this works just fine, I had successfully set the z coordinate as a property on a mesh.
But, I just can't figure out how can I copy the classification property from the point_set to the tin_class_mesh. I know that I'd need to change double to unsigned char in the code, but I don't know how to access the property from the point_set and assign it to the corresponding vertex in tin_class_mesh. What am I doing wrong?
As a side note, the interesting part here is that the number of tin_colored_mesh.number_of_vertices() differs slightly from the point_set.size(). Why is that?
I have my custom vertex and edge properties
namespace boost {
enum vertex_diagonal_t{vertex_diagonal = 999};
BOOST_INSTALL_PROPERTY(vertex, diagonal);
}
namespace boost {
enum edge_dominance_t{edge_dominance = 998};
BOOST_INSTALL_PROPERTY(edge, dominance);
}
I create my adjacency list with boost::property
typedef boost::adjacency_list<
boost::listS,
boost::vecS,
boost::bidirectionalS,
boost::property<boost::vertex_diagonal_t, const khut::diagonal*>,
boost::property<boost::edge_dominance_t, float>
> diagonal_dominance_graph;
typedef boost::property_map<diagonal_dominance_graph, boost::vertex_diagonal_t>::type diagonal_map_type;
typedef boost::property_map<diagonal_dominance_graph, boost::edge_dominance_t>::type dominance_map_type;
Now I want to loop through my own containers and add vertex
diagonal_dominance_graph graph;
for(storage_type::const_iterator i = repo_begining.begin(); i != repo_begining.end(); ++i){
diagonal_dominance_graph::vertex_descriptor dia_vertex = boost::add_vertex(graph);
//>> ?? HOW CAN I write Properties to dia_vertex HERE ?
//boost::property<boost::vertex_diagonal_t, const khut::diagonal*> p;
//boost::put(p, dia_vertex);
}
What I am not getting is How can I set properties of a vertex through vertex_descriptor. may be I am missing a simple function.
Please I don't need anything that makes BGL even more complex, or something that cleans and restructures the types in my example. I just need to know how to read/write properties through a vertex_descriptor or edge_descriptor
You're using property lists: they're documented here.
So in your example, you'd use
diagonal_map_type vp = get(boost::vertex_diagonal, graph);
using storage_type = std::vector<int>;
storage_type repo_begining(10);
for(storage_type::const_iterator i = repo_begining.begin(); i != repo_begining.end(); ++i) {
diagonal_dominance_graph::vertex_descriptor dia_vertex = boost::add_vertex(graph);
khut::diagonal* v = nullptr;
boost::put(vp, dia_vertex, v);
}
// likewise for edges
dominance_map_type ep = get(boost::edge_dominance, graph);
See it Live On Coliru
Bundled Properties
The very same documentation page says:
NOTE: The Boost Graph Library supports two interchangeable methods for specifying interior properties: bundled properties and property lists. The former is easier to use and requires less effort, whereas the latter is compatible with older, broken compilers and is backward-compatible with Boost versions prior to 1.32.0. If you absolutely require these compatibility features, read on to learn about property lists. Otherwise, we strongly suggest that you read about the bundled properties mechanism.
Boost 1.32 dates over 10 years ago! So, I'd suggest bundled properties:
Live On Coliru
#include <boost/graph/adjacency_list.hpp>
namespace khut {
struct diagonal { };
struct MyVertexProperties {
diagonal const* diag_ptr;
};
struct MyEdgeProperties {
float dominance;
};
}
typedef boost::adjacency_list<
boost::listS,
boost::vecS,
boost::bidirectionalS,
khut::MyVertexProperties,
khut::MyEdgeProperties
> diagonal_dominance_graph;
#include <iostream>
int main() {
using namespace boost;
diagonal_dominance_graph g;
khut::diagonal d1, d2;
{
auto v1 = add_vertex(khut::MyVertexProperties { &d1 }, g);
auto v2 = add_vertex(khut::MyVertexProperties { &d2 }, g);
/*auto e1 = */add_edge(v1, v2, khut::MyEdgeProperties { 42.31415926 }, g);
}
for(diagonal_dominance_graph::vertex_descriptor vd : make_iterator_range(vertices(g)))
std::cout << "Is diagonal d1? " << std::boolalpha << (&d1 == g[vd].diag_ptr) << "\n";
for(diagonal_dominance_graph::edge_descriptor ed : make_iterator_range(edges(g)))
std::cout << "Edge dominance: " << g[ed].dominance << "\n";
}
Prints
Is diagonal d1? true
Is diagonal d1? false
Edge dominance: 42.3142
I have my custom vertex and edge properties
namespace boost {
enum vertex_diagonal_t{vertex_diagonal = 999};
BOOST_INSTALL_PROPERTY(vertex, diagonal);
}
namespace boost {
enum edge_dominance_t{edge_dominance = 998};
BOOST_INSTALL_PROPERTY(edge, dominance);
}
I create my adjacency list with boost::property
typedef boost::adjacency_list<
boost::listS,
boost::vecS,
boost::bidirectionalS,
boost::property<boost::vertex_diagonal_t, const khut::diagonal*>,
boost::property<boost::edge_dominance_t, float>
> diagonal_dominance_graph;
typedef boost::property_map<diagonal_dominance_graph, boost::vertex_diagonal_t>::type diagonal_map_type;
typedef boost::property_map<diagonal_dominance_graph, boost::edge_dominance_t>::type dominance_map_type;
Now I want to loop through my own containers and add vertex
diagonal_dominance_graph graph;
for(storage_type::const_iterator i = repo_begining.begin(); i != repo_begining.end(); ++i){
diagonal_dominance_graph::vertex_descriptor dia_vertex = boost::add_vertex(graph);
//>> ?? HOW CAN I write Properties to dia_vertex HERE ?
//boost::property<boost::vertex_diagonal_t, const khut::diagonal*> p;
//boost::put(p, dia_vertex);
}
What I am not getting is How can I set properties of a vertex through vertex_descriptor. may be I am missing a simple function.
Please I don't need anything that makes BGL even more complex, or something that cleans and restructures the types in my example. I just need to know how to read/write properties through a vertex_descriptor or edge_descriptor
You're using property lists: they're documented here.
So in your example, you'd use
diagonal_map_type vp = get(boost::vertex_diagonal, graph);
using storage_type = std::vector<int>;
storage_type repo_begining(10);
for(storage_type::const_iterator i = repo_begining.begin(); i != repo_begining.end(); ++i) {
diagonal_dominance_graph::vertex_descriptor dia_vertex = boost::add_vertex(graph);
khut::diagonal* v = nullptr;
boost::put(vp, dia_vertex, v);
}
// likewise for edges
dominance_map_type ep = get(boost::edge_dominance, graph);
See it Live On Coliru
Bundled Properties
The very same documentation page says:
NOTE: The Boost Graph Library supports two interchangeable methods for specifying interior properties: bundled properties and property lists. The former is easier to use and requires less effort, whereas the latter is compatible with older, broken compilers and is backward-compatible with Boost versions prior to 1.32.0. If you absolutely require these compatibility features, read on to learn about property lists. Otherwise, we strongly suggest that you read about the bundled properties mechanism.
Boost 1.32 dates over 10 years ago! So, I'd suggest bundled properties:
Live On Coliru
#include <boost/graph/adjacency_list.hpp>
namespace khut {
struct diagonal { };
struct MyVertexProperties {
diagonal const* diag_ptr;
};
struct MyEdgeProperties {
float dominance;
};
}
typedef boost::adjacency_list<
boost::listS,
boost::vecS,
boost::bidirectionalS,
khut::MyVertexProperties,
khut::MyEdgeProperties
> diagonal_dominance_graph;
#include <iostream>
int main() {
using namespace boost;
diagonal_dominance_graph g;
khut::diagonal d1, d2;
{
auto v1 = add_vertex(khut::MyVertexProperties { &d1 }, g);
auto v2 = add_vertex(khut::MyVertexProperties { &d2 }, g);
/*auto e1 = */add_edge(v1, v2, khut::MyEdgeProperties { 42.31415926 }, g);
}
for(diagonal_dominance_graph::vertex_descriptor vd : make_iterator_range(vertices(g)))
std::cout << "Is diagonal d1? " << std::boolalpha << (&d1 == g[vd].diag_ptr) << "\n";
for(diagonal_dominance_graph::edge_descriptor ed : make_iterator_range(edges(g)))
std::cout << "Edge dominance: " << g[ed].dominance << "\n";
}
Prints
Is diagonal d1? true
Is diagonal d1? false
Edge dominance: 42.3142
I am trying to create a graph of objects which I need to traverse using some traversal algorithm. At this very moment I am stuck trying to create the graph using my custom objects. The way I am trying to accomplish it is as follows:
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/depth_first_search.hpp>
#include <iostream>
using namespace std;
typedef boost::adjacency_list<boost::vecS,boost::vecS,boost::directedS> CustomGraph;
typedef boost::graph_traits<CustomGraph>::vertex_descriptor CustomVertex;
class CustomVisitor:public boost::default_dfs_visitor
{
public:
void discover_vertex(CustomVertex v,const CustomGraph& taskGraph) const
{
cerr<<v<<endl;
return;
}
};
class CustomObject{
private:
int currentId;
public:
CustomObject(int id){
currentId = id;
}
};
int main()
{
CustomGraph customGraph;
CustomObject* obj0 = new CustomObject(0);
CustomObject* obj1 = new CustomObject(1);
CustomObject* obj2 = new CustomObject(2);
CustomObject* obj3 = new CustomObject(3);
typedef std::pair<CustomObject*,CustomObject*> Edge;
std::vector<Edge> edgeVec;
edgeVec.push_back(Edge(obj0,obj1));
edgeVec.push_back(Edge(obj0,obj2));
edgeVec.push_back(Edge(obj1,obj2));
edgeVec.push_back(Edge(obj1,obj3));
customGraph(edgeVec.begin(),edgeVec.end());
CustomVisitor vis;
boost::depth_first_search(customGraph,boost::visitor(vis));
return 0;
}
But this doesn't seem to be the right way to create objects within the vertices. Can somebody guide me as to what is the correct way to create nodes such that I can retrieve my objects while traversing the graph.
Thanks
Hi I know this is a rather old question, but there might others that can benefit from an answer.
It seems as if you have forgotten to define that your Graph will have a custom class as vertices. You have to add a fourth parameter to your typedef and add a typedef for your edge:
typedef boost::adjacency_list<boost::vecS,boost::vecS,boost::directedS, CustomObject> CustomGraph;
typedef boost::graph_traits<CustomGraph>::vertex_descriptor CustomVertex;
typedef boost::graph_traits<CustomGraph>::edge_descriptor CustomEdge;
Then I usually add my nodes before connecting them with edges:
// Create graph and custom obj's
CustomGraph customGraph
CustomObject obj0(0);
CustomObject obj1(1);
CustomObject obj2(2);
CustomObject obj3(3);
// Add custom obj's to the graph
// (Creating boost vertices)
CustomVertex v0 = boost::add_vertex(obj0, customGraph);
CustomVertex v1 = boost::add_vertex(obj1, customGraph);
CustomVertex v2 = boost::add_vertex(obj2, customGraph);
CustomVertex v3 = boost::add_vertex(obj3, customGraph);
// Add edge
CustomEdge edge;
bool edgeExists;
// check if edge allready exist (only if you don't want parallel edges)
boost::tie(edge, edgeExists) = boost::edge(v0 , v1, customGraph);
if(!edgeExists)
boost::add_edge(v0 , v1, customGraph);
// write graph to console
cout << "\n-- graphviz output START --" << endl;
boost::write_graphviz(cout, customGraph);
cout << "\n-- graphviz output END --" << endl;