I'm writing code for graph mining using boost library and I want to know how to test:
if two graphs are equal using isomorphism (return true only if graphs have the same structure and same labels)
if a graph is a subgraph of another?
This is the graphs file: 3test.txt
and Here is some parts of the source code that I have make:
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/vf2_sub_graph_iso.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <boost/config.hpp>
#include <boost/graph/isomorphism.hpp>
#include <boost/graph/graph_utility.hpp>
#include <fstream>
#include <iostream>
#include <vector>
//for mmap:
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
using namespace std;
using namespace boost;
//==========STRUCTURES==========
// vertex
struct VertexProperties {
int id;
int label;
VertexProperties(unsigned i = 0, unsigned l = 0) : id(i), label(l) {}
};
// edge
struct EdgeProperties {
unsigned label;
EdgeProperties(unsigned l = 0) :label(l) {}
};
// Graph
struct GraphProperties {
unsigned id;
unsigned label;
GraphProperties(unsigned i = 0, unsigned l = 0) : id(i), label(l) {}
};
// adjency list
typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS, VertexProperties, EdgeProperties,
GraphProperties> Graph;
// descriptors
typedef boost::graph_traits<Graph>::vertex_descriptor vertex_t;
typedef std::pair<boost::graph_traits<Graph>::edge_descriptor, bool> edge_t;
// iterators
typedef graph_traits<Graph>::vertex_iterator vertex_iter;
typedef graph_traits<Graph>::edge_iterator edge_iter;
typedef std::pair<edge_iter, edge_iter> edge_pair;
//*********global variables*************
vector<Graph> dataG;
//=================callback used fro subgraph_iso=================================================================
// Default print_callback
template <typename Graph1,typename Graph2>
struct my_callback {
my_callback(const Graph1& graph1, const Graph2& graph2)
: graph1_(graph1), graph2_(graph2) {}
template <typename CorrespondenceMap1To2,
typename CorrespondenceMap2To1>
bool operator()(CorrespondenceMap1To2 f, CorrespondenceMap2To1) const {
return true;
}
private:
const Graph1& graph1_;
const Graph2& graph2_;
};
//==========handle_error==========
void handle_error(const char *msg) {
perror(msg);
exit(255);
}
//============READ ALL THE FILE AND RETURN A STRING===================
const char *readfromfile(const char *fname, size_t &length) {
int fd = open(fname, O_RDONLY);
if (fd == -1)
handle_error("open");
// obtain file size
struct stat sb;
if (fstat(fd, &sb) == -1)
handle_error("fstat");
length = sb.st_size;
const char *addr = static_cast<const char *>(mmap(NULL, length, PROT_READ, MAP_PRIVATE, fd, 0u));
if (addr == MAP_FAILED)
handle_error("mmap");
// TODO close fd at some point in time, call munmap(...)
return addr;
}
//==========SPLIT THE STRING BY NEWLINE (\n) ==========
vector<string> splitstringtolines(string const& str) {
std::vector<string> split_vector;
split(split_vector, str, is_any_of("\n"));
return split_vector;
}
//============Get a string starting from pos============
string getpos(int const& pos, string const& yy) {
size_t i = pos;
string str;
for (; ((yy[i] != ' ') && (i < yy.length())); i++) {str += yy[i];}
return str;
}
//==================read string vector and return graphs vector===================
std::vector<Graph> creategraphs(std::vector<string> const& fichlines) {
for (string yy : fichlines) {
switch (yy[0]) {
case 't': {
string str2 = getpos(4, yy);
unsigned gid = atoi(str2.c_str());
dataG.emplace_back(GraphProperties(gid, gid));
} break;
case 'v': {
assert(!dataG.empty()); // assert will terminate the program if its argument turns out to be false
// cout<<yy<<endl;
int vId, vLabel;
string vvv = getpos(2, yy);
vId = atoi(vvv.c_str());
string vvvv = getpos((int)vvv.length() + 3, yy);
// cout<<vvvv<<endl;
vLabel = atoi(vvvv.c_str());
boost::add_vertex(VertexProperties(vId, vLabel), dataG.back());
}
break;
case 'e': { // cout<<yy<<endl;
assert(!dataG.empty()); // assert will terminate the program if its argument turns out to be false
int fromId, toId, eLabel;
string eee = getpos(2, yy);
// cout<<eee<<endl;
fromId = atoi(eee.c_str());
string eee2 = getpos((int)eee.length() + 3, yy);
// cout<<eee2<<endl;
toId = atoi(eee2.c_str());
int c = (int)eee.length() + (int)eee2.length() + 4;
// cout<<c<<endl;
string eee3 = getpos(c, yy);
// cout<<eee3<<endl;
eLabel = atoi(eee3.c_str());
for (size_t i = 0; i < num_vertices(dataG.back()); ++i) // size_t vertice number in the graph
{
if(dataG.back()[i].id==fromId) fromId=i;
else if(dataG.back()[i].id==toId) toId=i;
}
boost::add_edge(fromId, toId, EdgeProperties(eLabel), dataG.back());
} break;
}
}
return dataG;
}
//==============================M A I N P R O G R A M =======================================
int main()
{
size_t length;
std::vector<Graph> dataG =creategraphs(splitstringtolines(readfromfile("3test.txt", length)));
cout<<"***PS***\n dataG[0] is a subgraph of dataG[1]\n dataG[2] is the same as dataG[0]\n dataG[3] is the same as dataG[0] but with other labels.\n"<<endl;
my_callback<Graph, Graph> my_callback(dataG[0], dataG[3]);
cout<<"equal(dataG[0], dataG[3],my_callback)="<<vf2_graph_iso(dataG[0], dataG[3],my_callback)<<endl;
mcgregor_common_subgraphs(dataG[0], dataG[3], true, my_callback);
}
Unfortunately when I run it I got these errors:
/usr/include/boost/graph/mcgregor_common_subgraphs.hpp||In instantiation of ‘bool boost::detail::mcgregor_common_subgraphs_internal(const GraphFirst&, const GraphSecond&, const VertexIndexMapFirst&, const VertexIndexMapSecond&, CorrespondenceMapFirstToSecond, CorrespondenceMapSecondToFirst, VertexStackFirst&, EdgeEquivalencePredicate, VertexEquivalencePredicate, bool, SubGraphInternalCallback) [with GraphFirst = boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS, VertexProperties, EdgeProperties, GraphProperties>; GraphSecond = boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS, VertexProperties, EdgeProperties, GraphProperties>; VertexIndexMapFirst = boost::vec_adj_list_vertex_id_map<VertexProperties, unsigned int>; VertexIndexMapSecond = boost::vec_adj_list_vertex_id_map<VertexProperties, unsigned int>; CorrespondenceMapFirstToSecond = boost::shared_array_property_map<unsigned int, boost::vec_adj_list_vertex_id_map<VertexProperties, unsigned int> >; CorrespondenceMapSecondToFirst = boost::shared_array_property_map<unsigned int, boost::vec_adj_list_vertex_id_map<VertexProperties, unsigned int> >; VertexStackFirst = std::stack<unsigned int, std::deque<unsigned int, std::allocator<unsigned int> > >; EdgeEquivalencePredicate = boost::always_equivalent; VertexEquivalencePredicate = boost::always_equivalent; SubGraphInternalCallback = my_callback<boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS, VertexProperties, EdgeProperties, GraphProperties>, boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS, VertexProperties, EdgeProperties, GraphProperties> >]’:|
/usr/include/boost/graph/mcgregor_common_subgraphs.hpp|433|required from ‘void boost::detail::mcgregor_common_subgraphs_internal_init(const GraphFirst&, const GraphSecond&, VertexIndexMapFirst, VertexIndexMapSecond, EdgeEquivalencePredicate, VertexEquivalencePredicate, bool, SubGraphInternalCallback) [with GraphFirst = boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS, VertexProperties, EdgeProperties, GraphProperties>; GraphSecond = boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS, VertexProperties, EdgeProperties, GraphProperties>; VertexIndexMapFirst = boost::vec_adj_list_vertex_id_map<VertexProperties, unsigned int>; VertexIndexMapSecond = boost::vec_adj_list_vertex_id_map<VertexProperties, unsigned int>; EdgeEquivalencePredicate = boost::always_equivalent; VertexEquivalencePredicate = boost::always_equivalent; SubGraphInternalCallback = my_callback<boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS, VertexProperties, EdgeProperties, GraphProperties>, boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS, VertexProperties, EdgeProperties, GraphProperties> >]’|
/usr/include/boost/graph/mcgregor_common_subgraphs.hpp|484|required from ‘void boost::mcgregor_common_subgraphs(const GraphFirst&, const GraphSecond&, bool, SubGraphCallback) [with GraphFirst = boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS, VertexProperties, EdgeProperties, GraphProperties>; GraphSecond = boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS, VertexProperties, EdgeProperties, GraphProperties>; SubGraphCallback = my_callback<boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS, VertexProperties, EdgeProperties, GraphProperties>, boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS, VertexProperties, EdgeProperties, GraphProperties> >]’|
/home/mohsenuss91/Bureau/NouvelleApprocheBOOST/stackoverflow.cpp|211|required from here|
/usr/include/boost/graph/mcgregor_common_subgraphs.hpp|337|error: no match for call to ‘(my_callback<boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS, VertexProperties, EdgeProperties, GraphProperties>, boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS, VertexProperties, EdgeProperties, GraphProperties> >) (boost::shared_array_property_map<unsigned int, boost::vec_adj_list_vertex_id_map<VertexProperties, unsigned int> >&, boost::shared_array_property_map<unsigned int, boost::vec_adj_list_vertex_id_map<VertexProperties, unsigned int> >&, VertexSizeFirst&)’|
/home/mohsenuss91/Bureau/NouvelleApprocheBOOST/stackoverflow.cpp|69|note: candidate is:|
/home/mohsenuss91/Bureau/NouvelleApprocheBOOST/stackoverflow.cpp|76|note: template<class CorrespondenceMap1To2, class CorrespondenceMap2To1> bool my_callback<Graph1, Graph2>::operator()(CorrespondenceMap1To2, CorrespondenceMap2To1) const [with CorrespondenceMap1To2 = CorrespondenceMap1To2; CorrespondenceMap2To1 = CorrespondenceMap2To1; Graph1 = boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS, VertexProperties, EdgeProperties, GraphProperties>; Graph2 = boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS, VertexProperties, EdgeProperties, GraphProperties>]|
/home/mohsenuss91/Bureau/NouvelleApprocheBOOST/stackoverflow.cpp|76|note: template argument deduction/substitution failed:|
/usr/include/boost/graph/mcgregor_common_subgraphs.hpp|337|note: candidate expects 2 arguments, 3 provided|
||=== Build failed: 1 error(s), 4 warning(s) (0 minute(s), 6 second(s)) ===|
Docs:
OUT: SubGraphCallback user_callback
A function object that will be invoked when a subgraph has been discovered. The operator() must have the following form:
template <typename CorrespondenceMapFirstToSecond,
typename CorrespondenceMapSecondToFirst>
bool operator()(
CorrespondenceMapFirstToSecond correspondence_map_1_to_2,
CorrespondenceMapSecondToFirst correspondence_map_2_to_1,
typename graph_traits<GraphFirst>::vertices_size_type subgraph_size
);
So at the very least make the functor take the extra argument:
template <typename Graph1, typename Graph2>
struct my_callback {
my_callback(const Graph1 &graph1, const Graph2 &graph2) : graph1_(graph1), graph2_(graph2) {}
template <typename CorrespondenceMap1To2, typename CorrespondenceMap2To1>
bool operator()(CorrespondenceMap1To2 f, CorrespondenceMap2To1) const {
// vf2_graph_iso
return true;
}
template <typename CorrespondenceMap1To2, typename CorrespondenceMap2To1, typename X>
bool operator()(CorrespondenceMap1To2 f, CorrespondenceMap2To1, X) const {
// mcgregor_common_subgraphs
return true;
}
private:
const Graph1 &graph1_;
const Graph2 &graph2_;
};
Of course, this /just/ fixes the compilation error. It doesn't look like the callbacks do useful work.
Output:
***PS***
dataG[0] is a subgraph of dataG[1]
dataG[2] is the same as dataG[0]
dataG[3] is the same as dataG[0] but with other labels.
equal(dataG[0], dataG[3],my_callback)=1
Working sample:
Live On Coliru
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/vf2_sub_graph_iso.hpp>
#include <boost/graph/mcgregor_common_subgraphs.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <boost/config.hpp>
#include <boost/graph/isomorphism.hpp>
#include <boost/graph/graph_utility.hpp>
#include <fstream>
#include <iostream>
#include <vector>
// for mmap:
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
using namespace std;
using namespace boost;
//==========STRUCTURES==========
// vertex
struct VertexProperties {
int id;
int label;
VertexProperties(unsigned i = 0, unsigned l = 0) : id(i), label(l) {}
};
// edge
struct EdgeProperties {
unsigned label;
EdgeProperties(unsigned l = 0) : label(l) {}
};
// Graph
struct GraphProperties {
unsigned id;
unsigned label;
GraphProperties(unsigned i = 0, unsigned l = 0) : id(i), label(l) {}
};
// adjency list
typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS, VertexProperties, EdgeProperties,
GraphProperties> Graph;
// descriptors
typedef boost::graph_traits<Graph>::vertex_descriptor vertex_t;
typedef std::pair<boost::graph_traits<Graph>::edge_descriptor, bool> edge_t;
// iterators
typedef graph_traits<Graph>::vertex_iterator vertex_iter;
typedef graph_traits<Graph>::edge_iterator edge_iter;
typedef std::pair<edge_iter, edge_iter> edge_pair;
//*********global variables*************
vector<Graph> dataG;
//=================callback used fro subgraph_iso=================================================================
// Default print_callback
template <typename Graph1, typename Graph2>
struct my_callback {
my_callback(const Graph1 &graph1, const Graph2 &graph2) : graph1_(graph1), graph2_(graph2) {}
template <typename CorrespondenceMap1To2, typename CorrespondenceMap2To1>
bool operator()(CorrespondenceMap1To2 f, CorrespondenceMap2To1) const {
// vf2_graph_iso
return true;
}
template <typename CorrespondenceMap1To2, typename CorrespondenceMap2To1, typename X>
bool operator()(CorrespondenceMap1To2 f, CorrespondenceMap2To1, X) const {
// mcgregor_common_subgraphs
return true;
}
private:
const Graph1 &graph1_;
const Graph2 &graph2_;
};
//==========handle_error==========
void handle_error(const char *msg) {
perror(msg);
exit(255);
}
//============READ ALL THE FILE AND RETURN A STRING===================
const char *readfromfile(const char *fname, size_t &length) {
int fd = open(fname, O_RDONLY);
if (fd == -1)
handle_error("open");
// obtain file size
struct stat sb;
if (fstat(fd, &sb) == -1)
handle_error("fstat");
length = sb.st_size;
const char *addr = static_cast<const char *>(mmap(NULL, length, PROT_READ, MAP_PRIVATE, fd, 0u));
if (addr == MAP_FAILED)
handle_error("mmap");
// TODO close fd at some point in time, call munmap(...)
return addr;
}
//==========SPLIT THE STRING BY NEWLINE (\n) ==========
vector<string> splitstringtolines(string const &str) {
std::vector<string> split_vector;
split(split_vector, str, is_any_of("\n"));
return split_vector;
}
//============Get a string starting from pos============
string getpos(int const &pos, string const &yy) {
size_t i = pos;
string str;
for (; ((yy[i] != ' ') && (i < yy.length())); i++) {
str += yy[i];
}
return str;
}
//==================read string vector and return graphs vector===================
std::vector<Graph> creategraphs(std::vector<string> const &fichlines) {
for (string yy : fichlines) {
switch (yy[0]) {
case 't': {
string str2 = getpos(4, yy);
unsigned gid = atoi(str2.c_str());
dataG.emplace_back(GraphProperties(gid, gid));
} break;
case 'v': {
assert(!dataG.empty()); // assert will terminate the program if its argument turns out to be false
// cout<<yy<<endl;
int vId, vLabel;
string vvv = getpos(2, yy);
vId = atoi(vvv.c_str());
string vvvv = getpos((int)vvv.length() + 3, yy);
// cout<<vvvv<<endl;
vLabel = atoi(vvvv.c_str());
boost::add_vertex(VertexProperties(vId, vLabel), dataG.back());
}
break;
case 'e': { // cout<<yy<<endl;
assert(!dataG.empty()); // assert will terminate the program if its argument turns out to be false
int fromId, toId, eLabel;
string eee = getpos(2, yy);
// cout<<eee<<endl;
fromId = atoi(eee.c_str());
string eee2 = getpos((int)eee.length() + 3, yy);
// cout<<eee2<<endl;
toId = atoi(eee2.c_str());
int c = (int)eee.length() + (int)eee2.length() + 4;
// cout<<c<<endl;
string eee3 = getpos(c, yy);
// cout<<eee3<<endl;
eLabel = atoi(eee3.c_str());
for (size_t i = 0; i < num_vertices(dataG.back()); ++i) // size_t vertice number in the graph
{
if (dataG.back()[i].id == fromId)
fromId = i;
else if (dataG.back()[i].id == toId)
toId = i;
}
boost::add_edge(fromId, toId, EdgeProperties(eLabel), dataG.back());
} break;
}
}
return dataG;
}
//==============================M A I N P R O G R A M =======================================
int main() {
size_t length;
std::vector<Graph> dataG = creategraphs(splitstringtolines(readfromfile("3test.txt", length)));
cout << "***PS***\n dataG[0] is a subgraph of dataG[1]\n dataG[2] is the same as dataG[0]\n dataG[3] is the same "
"as dataG[0] but with other labels.\n" << endl;
my_callback<Graph, Graph> my_callback(dataG[0], dataG[3]);
cout << "equal(dataG[0], dataG[3],my_callback)=" << vf2_graph_iso(dataG[0], dataG[3], my_callback) << endl;
mcgregor_common_subgraphs(dataG[0], dataG[3], true, my_callback);
}
Related
I'm learning how to use Boost-graph library for a university project. I have a graph where I need to add and remove vertices, so I declared my adjacency list with listS as vertex list. I have a big problem with the call of depth_first_search() function: because of listS, I need to provide a Indexes Property Map, but I don't understand how I need to procedes. Here's the code:
#include <iostream>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graph_utility.hpp>
#include <boost/graph/depth_first_search.hpp>
struct VertexProperties {
int value;
};
typedef boost::adjacency_list<boost::vecS, // OutEdgeList
boost::listS, // VertexList
boost::bidirectionalS, // Directed
VertexProperties // VertexProperties
>
MyGraph;
typedef boost::graph_traits<MyGraph>::vertex_descriptor MyVertex;
typedef boost::graph_traits<MyGraph>::edge_descriptor MyEdge;
class dfs_visitor : public boost::default_dfs_visitor {
public:
dfs_visitor();
dfs_visitor(const dfs_visitor& other);
void initialize_vertex(MyVertex s, MyGraph g);
void start_vertex(MyVertex s, MyGraph g);
void discover_vertex(MyVertex s, MyGraph g);
void finish_vertex(MyVertex s, MyGraph g);
void examine_edge(MyEdge e, MyGraph g);
void tree_edge(MyEdge e, MyGraph g);
void back_edge(MyEdge e, MyGraph g);
void forward_or_cross_edge(MyEdge e, MyGraph g);
void finish_edge(MyEdge e, MyGraph g);
};
dfs_visitor::dfs_visitor() {}
dfs_visitor::dfs_visitor(const dfs_visitor& other) {}
void dfs_visitor::initialize_vertex(MyVertex s, MyGraph g){
std::cout << "Initialize: " << g[s].value << std::endl;
}
void dfs_visitor::start_vertex(MyVertex s, MyGraph g) {
std::cout << "Start: " << g[s].value << std::endl;
}
void dfs_visitor::discover_vertex(MyVertex s, MyGraph g) {
std::cout << "Discover: " << g[s].value << std::endl;
}
void dfs_visitor::finish_vertex(MyVertex s, MyGraph g) {
std::cout << "Finished: " << g[s].value << std::endl;
}
void dfs_visitor::examine_edge(MyEdge e, MyGraph g) {}
void dfs_visitor::tree_edge(MyEdge e, MyGraph g) {}
void dfs_visitor::back_edge(MyEdge e, MyGraph g) {}
void dfs_visitor::forward_or_cross_edge(MyEdge e, MyGraph g) {}
void dfs_visitor::finish_edge(MyEdge e, MyGraph g) {}
int main(){
MyGraph g{};
for(int i = 0; i < 10; i++) {
MyVertex v = boost::add_vertex(g);
g[v].value = i;
}
MyGraph::vertex_iterator v, v_end;
std::tie(v, v_end) = boost::vertices(g);
auto u = v;
u++;
while(v != v_end && u != v_end) {
boost::add_edge(*u, *v, g);
u++;
v++;
}
/* INDEX MAP CREATION*/
typedef std::map<MyVertex, size_t> MyIndexMap;
MyIndexMap i_map;
auto ipmap = boost::make_assoc_property_map(i_map);
std::tie(v, v_end) = boost::vertices(g);
while(v != v_end) {
i_map[*v] = i_map.size();
v++;
}
/* COLOR MAP CREATION */
typedef std::map<size_t, boost::default_color_type> ColorMap;
ColorMap c_map;
auto cpmap = boost::make_assoc_property_map(c_map);
std::tie(v, v_end) = boost::vertices(g);
while(v != v_end) {
c_map[ipmap[*v]] = boost::color_traits<boost::default_color_type>::white();
v++;
}
dfs_visitor vis{};
boost::depth_first_search(g,
boost::visitor(vis)),
boost::color_map(cpmap);
boost::vertex_index_map(ipmap);
}
When I'm going to compile this, this is the output:
In file included from /usr/include/boost/graph/adjacency_list.hpp:223,
from test.cpp:2:
/usr/include/boost/graph/detail/adjacency_list.hpp: In instantiation of ‘struct boost::adj_list_any_vertex_pa::bind_<boost::vertex_index_t, boost::adjacency_list<boost::vecS, boost::listS, boost::bidirectionalS, VertexProperties>, VertexProperties>’:
/usr/include/boost/graph/detail/adjacency_list.hpp:2618:12: required from ‘struct boost::detail::adj_list_choose_vertex_pa<boost::vertex_index_t, boost::adjacency_list<boost::vecS, boost::listS, boost::bidirectionalS, VertexProperties>, VertexProperties>’
/usr/include/boost/graph/detail/adjacency_list.hpp:2755:12: required from ‘struct boost::adj_list_vertex_property_selector::bind_<boost::adjacency_list<boost::vecS, boost::listS, boost::bidirectionalS, VertexProperties>, VertexProperties, boost::vertex_index_t>’
/usr/include/boost/graph/properties.hpp:201:12: required from ‘struct boost::detail::vertex_property_map<boost::adjacency_list<boost::vecS, boost::listS, boost::bidirectionalS, VertexProperties>, boost::vertex_index_t>’
/usr/include/boost/graph/properties.hpp:212:10: required from ‘struct boost::property_map<boost::adjacency_list<boost::vecS, boost::listS, boost::bidirectionalS, VertexProperties>, boost::vertex_index_t, void>’
/usr/include/boost/graph/named_function_params.hpp:416:69: [ skipping 2 instantiation contexts, use -ftemplate-backtrace-limit=0 to disable ]
/usr/include/boost/graph/named_function_params.hpp:605:41: required from ‘struct boost::detail::map_maker<boost::adjacency_list<boost::vecS, boost::listS, boost::bidirectionalS, VertexProperties>, boost::parameter::aux::arg_list<boost::parameter::aux::tagged_argument<boost::graph::keywords::tag::visitor, const dfs_visitor>, boost::parameter::aux::empty_arg_list>, boost::graph::keywords::tag::color_map, boost::default_color_type>’
/usr/include/boost/graph/named_function_params.hpp:621:7: required by substitution of ‘template<class Graph, class ArgPack> typename boost::detail::map_maker<Graph, ArgPack, boost::graph::keywords::tag::color_map, boost::default_color_type>::map_type boost::detail::make_property_map_from_arg_pack_gen<boost::graph::keywords::tag::color_map, boost::default_color_type>::operator()<Graph, ArgPack>(const Graph&, const ArgPack&) const [with Graph = boost::adjacency_list<boost::vecS, boost::listS, boost::bidirectionalS, VertexProperties>; ArgPack = boost::parameter::aux::arg_list<boost::parameter::aux::tagged_argument<boost::graph::keywords::tag::visitor, const dfs_visitor>, boost::parameter::aux::empty_arg_list>]’
/usr/include/boost/graph/depth_first_search.hpp:337:80: required from ‘void boost::graph::detail::depth_first_search_impl<Graph>::operator()(const Graph&, const ArgPack&) const [with ArgPack = boost::parameter::aux::arg_list<boost::parameter::aux::tagged_argument<boost::graph::keywords::tag::visitor, const dfs_visitor>, boost::parameter::aux::empty_arg_list>; Graph = boost::adjacency_list<boost::vecS, boost::listS, boost::bidirectionalS, VertexProperties>]’
/usr/include/boost/graph/depth_first_search.hpp:342:5: required from ‘typename boost::result_of<boost::graph::detail::depth_first_search_impl<Param0>(Param0, const ArgPack&)>::type boost::graph::depth_first_search_with_named_params(const Param0&, const ArgPack&) [with Param0 = boost::adjacency_list<boost::vecS, boost::listS, boost::bidirectionalS, VertexProperties>; ArgPack = boost::parameter::aux::arg_list<boost::parameter::aux::tagged_argument<boost::graph::keywords::tag::visitor, const dfs_visitor>, boost::parameter::aux::empty_arg_list>; typename boost::result_of<boost::graph::detail::depth_first_search_impl<Param0>(Param0, const ArgPack&)>::type = void]’
/usr/include/boost/graph/depth_first_search.hpp:345:3: required from ‘typename boost::result_of<boost::graph::detail::depth_first_search_impl<Param0>(Param0, const typename boost::detail::convert_bgl_params_to_boost_parameter<boost::bgl_named_params<T, Tag, Base> >::type&)>::type boost::depth_first_search(const Param0&, const boost::bgl_named_params<T, Tag, Base>&) [with Param0 = boost::adjacency_list<boost::vecS, boost::listS, boost::bidirectionalS, VertexProperties>; P = dfs_visitor; T = boost::graph_visitor_t; R = boost::no_property; typename boost::result_of<boost::graph::detail::depth_first_search_impl<Param0>(Param0, const typename boost::detail::convert_bgl_params_to_boost_parameter<boost::bgl_named_params<T, Tag, Base> >::type&)>::type = void]’
test.cpp:100:50: required from here
/usr/include/boost/graph/detail/adjacency_list.hpp:2548:29: error: forming reference to void
2548 | typedef value_type& reference;
| ^~~~~~~~~
/usr/include/boost/graph/detail/adjacency_list.hpp:2549:35: error: forming reference to void
2549 | typedef const value_type& const_reference;
| ^~~~~~~~~~~~~~~
/usr/include/boost/graph/detail/adjacency_list.hpp:2552:47: error: forming reference to void
2552 | <Graph, value_type, reference, Tag> type;
| ^~~~
/usr/include/boost/graph/detail/adjacency_list.hpp:2554:53: error: forming reference to void
2554 | <Graph, value_type, const_reference, Tag> const_type;
| ^~~~~~~~~~
In file included from /usr/include/boost/graph/graph_utility.hpp:24,
from test.cpp:3:
/usr/include/boost/graph/depth_first_search.hpp: In instantiation of ‘void boost::graph::detail::depth_first_search_impl<Graph>::operator()(const Graph&, const ArgPack&) const [with ArgPack = boost::parameter::aux::arg_list<boost::parameter::aux::tagged_argument<boost::graph::keywords::tag::visitor, const dfs_visitor>, boost::parameter::aux::empty_arg_list>; Graph = boost::adjacency_list<boost::vecS, boost::listS, boost::bidirectionalS, VertexProperties>]’:
/usr/include/boost/graph/depth_first_search.hpp:342:5: required from ‘typename boost::result_of<boost::graph::detail::depth_first_search_impl<Param0>(Param0, const ArgPack&)>::type boost::graph::depth_first_search_with_named_params(const Param0&, const ArgPack&) [with Param0 = boost::adjacency_list<boost::vecS, boost::listS, boost::bidirectionalS, VertexProperties>; ArgPack = boost::parameter::aux::arg_list<boost::parameter::aux::tagged_argument<boost::graph::keywords::tag::visitor, const dfs_visitor>, boost::parameter::aux::empty_arg_list>; typename boost::result_of<boost::graph::detail::depth_first_search_impl<Param0>(Param0, const ArgPack&)>::type = void]’
/usr/include/boost/graph/depth_first_search.hpp:345:3: required from ‘typename boost::result_of<boost::graph::detail::depth_first_search_impl<Param0>(Param0, const typename boost::detail::convert_bgl_params_to_boost_parameter<boost::bgl_named_params<T, Tag, Base> >::type&)>::type boost::depth_first_search(const Param0&, const boost::bgl_named_params<T, Tag, Base>&) [with Param0 = boost::adjacency_list<boost::vecS, boost::listS, boost::bidirectionalS, VertexProperties>; P = dfs_visitor; T = boost::graph_visitor_t; R = boost::no_property; typename boost::result_of<boost::graph::detail::depth_first_search_impl<Param0>(Param0, const typename boost::detail::convert_bgl_params_to_boost_parameter<boost::bgl_named_params<T, Tag, Base> >::type&)>::type = void]’
test.cpp:100:50: required from here
/usr/include/boost/graph/depth_first_search.hpp:337:80: error: no match for call to ‘(const boost::detail::make_property_map_from_arg_pack_gen<boost::graph::keywords::tag::color_map, boost::default_color_type>) (const boost::adjacency_list<boost::vecS, boost::listS, boost::bidirectionalS, VertexProperties>&, const boost::parameter::aux::arg_list<boost::parameter::aux::tagged_argument<boost::graph::keywords::tag::visitor, const dfs_visitor>, boost::parameter::aux::empty_arg_list>&)’
337 | boost::detail::make_color_map_from_arg_pack(g, arg_pack),
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~
In file included from /usr/include/boost/graph/depth_first_search.hpp:21,
from /usr/include/boost/graph/graph_utility.hpp:24,
from test.cpp:3:
/usr/include/boost/graph/named_function_params.hpp:621:7: note: candidate: ‘template<class Graph, class ArgPack> typename boost::detail::map_maker<Graph, ArgPack, MapTag, ValueType>::map_type boost::detail::make_property_map_from_arg_pack_gen<MapTag, ValueType>::operator()(const Graph&, const ArgPack&) const [with Graph = Graph; ArgPack = ArgPack; MapTag = boost::graph::keywords::tag::color_map; ValueType = boost::default_color_type]’
621 | operator()(const Graph& g, const ArgPack& ap) const {
| ^~~~~~~~
/usr/include/boost/graph/named_function_params.hpp:621:7: note: substitution of deduced template arguments resulted in errors seen above
I think this is a kind of template error. Can someone explain me where is the mistake?
The named parameters are not given correctly. They use Fluent Syntax:
boost::depth_first_search(g,
boost::visitor(vis)
.vertex_index_map(ipmap)
.color_map(cpmap));
Now, you can simplify the rest of the code significantly.
classes where eerything is public, can be struct
exercise Rule Of Zero when possible
visitor member could be marked const
take the graph by const reference to avoid copying the graph on EVERY event
use c++ type aliases (using) instead of legacy typedef
add VertexProperties with add_vertex at once
prefer ranges over iterator pairs (e.g. boost::make_iterator_range)
no need to value-initialize default_color_type, std::vector or std::map would already do that
Everything at once: Live On Coliru
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/depth_first_search.hpp>
#include <boost/graph/graph_utility.hpp>
#include <iostream>
struct VertexProperties {
int value;
};
using MyGraph = boost::adjacency_list<boost::vecS, // OutEdgeList
boost::listS, // VertexList
boost::bidirectionalS, // Directed
VertexProperties // VertexProperties
>;
using MyVertex = boost::graph_traits<MyGraph>::vertex_descriptor;
using MyEdge = boost::graph_traits<MyGraph>::edge_descriptor;
struct dfs_visitor : boost::default_dfs_visitor {
void initialize_vertex(MyVertex s, MyGraph const& g) const { std::cout << "Initialize: " << g[s].value << std::endl; }
void start_vertex(MyVertex s, MyGraph const& g) const { std::cout << "Start: " << g[s].value << std::endl; }
void discover_vertex(MyVertex s, MyGraph const& g) const { std::cout << "Discover: " << g[s].value << std::endl; }
void finish_vertex(MyVertex s, MyGraph const& g) const { std::cout << "Finished: " << g[s].value << std::endl; }
};
int main() {
MyGraph g{};
for (int i = 0; i < 10; i++) {
add_vertex(VertexProperties{i}, g);
}
{
boost::optional<MyVertex> prev;
for (auto v : boost::make_iterator_range(vertices(g))) {
if (prev)
add_edge(v, *prev, g);
prev = v;
}
}
/* INDEX MAP CREATION*/
std::map<MyVertex, size_t> i_map;
for (auto v : boost::make_iterator_range(vertices(g))) {
i_map.emplace(v, i_map.size());
}
auto ipmap = boost::make_assoc_property_map(i_map);
/* COLOR MAP CREATION */
std::vector<boost::default_color_type> c_map(num_vertices(g));
auto cpmap = boost::make_iterator_property_map(c_map.begin(), ipmap);
dfs_visitor vis{};
boost::depth_first_search(g,
boost::visitor(vis)
.vertex_index_map(ipmap)
.color_map(cpmap));
}
Prints
Initialize: 0
Initialize: 1
Initialize: 2
Initialize: 3
Initialize: 4
Initialize: 5
Initialize: 6
Initialize: 7
Initialize: 8
Initialize: 9
Start: 0
Discover: 0
Finished: 0
Start: 1
Discover: 1
Finished: 1
Start: 2
Discover: 2
Finished: 2
Start: 3
Discover: 3
Finished: 3
Start: 4
Discover: 4
Finished: 4
Start: 5
Discover: 5
Finished: 5
Start: 6
Discover: 6
Finished: 6
Start: 7
Discover: 7
Finished: 7
Start: 8
Discover: 8
Finished: 8
Start: 9
Discover: 9
Finished: 9
I am using boost::copy_graph to copy an adjacency_list into another adjacency_list with a different VertexProperties template. To do this, I am trying to use the vertex_copy parameter (doc here). I am running into a compiler error that tells the I have a wrong type for the vertex properties of the second (to-be-copied) graph.
Minimal Example
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/copy.hpp>
typedef boost::adjacency_list<boost::vecS,
boost::vecS,
boost::undirectedS,
uint32_t,
float> AdjacencyList;
typedef AdjacencyList::vertex_descriptor VertexID;
struct custom_property
{
uint32_t label;
float f;
};
typedef boost::adjacency_list<boost::vecS,
boost::vecS,
boost::undirectedS,
custom_property,
float> AdjacencyListCustom;
struct vertex_copier
{
void operator() (uint32_t &input, custom_property &output)
{
output.label = input;
output.f = 0.;
}
};
int main(int argc, char** argv)
{
AdjacencyList adj;
VertexID id_0 = boost::add_vertex(0, adj);
VertexID id_1 = boost::add_vertex(1, adj);
VertexID id_2 = boost::add_vertex(2, adj);
VertexID id_3 = boost::add_vertex(4, adj);
boost::add_edge(id_0, id_1, 1.0f, adj);
boost::add_edge(id_2, id_3, 2.0f, adj);
AdjacencyListCustom adj_custom;
boost::copy_graph(adj, adj_custom, boost::vertex_copy(vertex_copier()));
}
g++ compilation error
...
/usr/include/boost/graph/copy.hpp:164:22: error: no match for call to '(vertex_copier) (boost::iterators::detail::iterator_facade_base<boost::range_detail::integer_iterator<long unsigned int>, long unsigned int, boost::iterators::random_access_traversal_tag, long unsigned int, long int, false, false>::reference, boost::graph_traits<boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS, custom_property, float> >::vertex_descriptor&)'
copy_vertex(*vi, new_v);
~~~~~~~~~~~^~~~~~~~~~~~
/path/to/file.cpp: note: candidate: void vertex_copier::operator()(uint32_t&, custom_property&)
void operator() (uint32_t &input, custom_property &output)
^~~~~~~~
/path/to/file.cpp: note: no known conversion for argument 2 from 'boost::graph_traits<boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS, custom_property, float> >::vertex_descriptor {aka long unsigned int}' to 'custom_property&'
This tells me that that vertex_copy is actually trying to copy the vertex_descriptor, which is a long unsigned int, not a custom_property. This seems to go against what is stated in the docs:
This is a Binary Function that copies the properties of a vertex in the original graph into the corresponding vertex in the copy.
How does vertex_copy work? Can it be used to set/define vertex properties in the copied graph that are not in the original? If not, do these properties have to be set after the copying by iterating through the graph? Can I apply a mapping en masse or does each vertex have to be visited and updated?
EDIT:
If I attempt to use copy_graph without specifying vertex_copy, then there is an error because the = operator does not exist between custom_property and uint32_t.
Sidestepping the question for a second, the simplest way to achieve things would be to add the appropriate conversion constructor to the custom property:
struct custom_property {
custom_property(uint32_t label = 0, float f = 0) : label(label), f(f) {}
uint32_t label;
float f;
};
In which case, a simple copy will work:
boost::copy_graph(adj, adj_custom);
See it Live On Coliru
Regarding the vertex copier, it receives the vertex decriptors. To access the vertex properties, you need to have the graph reference:
struct vertex_copier {
AdjacencyList& from;
AdjacencyListCustom& to;
void operator()(AdjacencyList::vertex_descriptor input, AdjacencyListCustom::vertex_descriptor output) const {
to[output] = { from[input], 0.f };
}
};
In which case you'd invoke things:
boost::copy_graph(adj, adj_custom, boost::vertex_copy(vertex_copier{adj, adj_custom}));
Again, Live On Coliru
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/copy.hpp>
#include <iostream>
typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS, uint32_t, float> AdjacencyList;
typedef AdjacencyList::vertex_descriptor VertexID;
struct custom_property {
//custom_property(uint32_t label = 0, float f = 0) : label(label), f(f) {}
uint32_t label;
float f;
};
typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS, custom_property, float> AdjacencyListCustom;
struct vertex_copier {
AdjacencyList& from;
AdjacencyListCustom& to;
void operator()(AdjacencyList::vertex_descriptor input, AdjacencyListCustom::vertex_descriptor output) const {
to[output] = { from[input], 0.f };
}
};
int main(int argc, char **argv) {
AdjacencyList adj;
VertexID id_0 = boost::add_vertex(0, adj);
VertexID id_1 = boost::add_vertex(1, adj);
VertexID id_2 = boost::add_vertex(2, adj);
VertexID id_3 = boost::add_vertex(4, adj);
boost::add_edge(id_0, id_1, 1.0f, adj);
boost::add_edge(id_2, id_3, 2.0f, adj);
AdjacencyListCustom adj_custom;
boost::copy_graph(adj, adj_custom, boost::vertex_copy(vertex_copier{adj, adj_custom}));
}
I'm writing code for graph mining using boost library and I want to use the vf2_sub_graph_iso function, in general vf2_subgraph_iso returns true if a graph-subgraph isomorphism exists and false otherwise, but in my case I want to make it return true only if the graphs are exactly the same (structure and labels), as mentioned in the official documentation: EdgeEquivalencePredicate and VertexEquivalencePredicate predicates are used to test whether edges and vertices are equivalent.
This is the graphs file: 3test.txt and here is some part of my code:
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/vf2_sub_graph_iso.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <boost/config.hpp>
#include <boost/graph/isomorphism.hpp>
#include <boost/graph/graph_utility.hpp>
#include <fstream>
#include <iostream>
#include <vector>
//for mmap:
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
using namespace std;
using namespace boost;
//==========STRUCTURES==========
// vertex
struct VertexProperties {
int id;
int label;
VertexProperties(unsigned i = 0, unsigned l = 0) : id(i), label(l) {}
};
// edge
struct EdgeProperties {
unsigned label;
EdgeProperties(unsigned l = 0) :label(l) {}
};
// Graph
struct GraphProperties {
unsigned id;
unsigned label;
GraphProperties(unsigned i = 0, unsigned l = 0) : id(i), label(l) {}
};
// adjency list
typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS, VertexProperties, EdgeProperties,
GraphProperties> Graph;
// descriptors
typedef boost::graph_traits<Graph>::vertex_descriptor vertex_t;
typedef std::pair<boost::graph_traits<Graph>::edge_descriptor, bool> edge_t;
// iterators
typedef graph_traits<Graph>::vertex_iterator vertex_iter;
typedef graph_traits<Graph>::edge_iterator edge_iter;
typedef std::pair<edge_iter, edge_iter> edge_pair;
//*********global variables*************
vector<Graph> dataG;
//=================callback used fro subgraph_iso=================================================================
// Default print_callback
template <typename Graph1,typename Graph2>
struct my_callback {
my_callback(const Graph1& graph1, const Graph2& graph2)
: graph1_(graph1), graph2_(graph2) {}
template <typename CorrespondenceMap1To2,
typename CorrespondenceMap2To1>
bool operator()(CorrespondenceMap1To2 f, CorrespondenceMap2To1) const {
return true;
}
private:
const Graph1& graph1_;
const Graph2& graph2_;
};
//==========handle_error==========
void handle_error(const char *msg) {
perror(msg);
exit(255);
}
//============READ ALL THE FILE AND RETURN A STRING===================
const char *readfromfile(const char *fname, size_t &length) {
int fd = open(fname, O_RDONLY);
if (fd == -1)
handle_error("open");
// obtain file size
struct stat sb;
if (fstat(fd, &sb) == -1)
handle_error("fstat");
length = sb.st_size;
const char *addr = static_cast<const char *>(mmap(NULL, length, PROT_READ, MAP_PRIVATE, fd, 0u));
if (addr == MAP_FAILED)
handle_error("mmap");
// TODO close fd at some point in time, call munmap(...)
return addr;
}
//==========SPLIT THE STRING BY NEWLINE (\n) ==========
vector<string> splitstringtolines(string const& str) {
std::vector<string> split_vector;
split(split_vector, str, is_any_of("\n"));
return split_vector;
}
//============Get a string starting from pos============
string getpos(int const& pos, string const& yy) {
size_t i = pos;
string str;
for (; ((yy[i] != ' ') && (i < yy.length())); i++) {str += yy[i];}
return str;
}
//==================read string vector and return graphs vector===================
std::vector<Graph> creategraphs(std::vector<string> const& fichlines) {
for (string yy : fichlines) {
switch (yy[0]) {
case 't': {
string str2 = getpos(4, yy);
unsigned gid = atoi(str2.c_str());
dataG.emplace_back(GraphProperties(gid, gid));
} break;
case 'v': {
assert(!dataG.empty()); // assert will terminate the program if its argument turns out to be false
// cout<<yy<<endl;
int vId, vLabel;
string vvv = getpos(2, yy);
vId = atoi(vvv.c_str());
string vvvv = getpos((int)vvv.length() + 3, yy);
// cout<<vvvv<<endl;
vLabel = atoi(vvvv.c_str());
boost::add_vertex(VertexProperties(vId, vLabel), dataG.back());
}
break;
case 'e': { // cout<<yy<<endl;
assert(!dataG.empty()); // assert will terminate the program if its argument turns out to be false
int fromId, toId, eLabel;
string eee = getpos(2, yy);
// cout<<eee<<endl;
fromId = atoi(eee.c_str());
string eee2 = getpos((int)eee.length() + 3, yy);
// cout<<eee2<<endl;
toId = atoi(eee2.c_str());
int c = (int)eee.length() + (int)eee2.length() + 4;
// cout<<c<<endl;
string eee3 = getpos(c, yy);
// cout<<eee3<<endl;
eLabel = atoi(eee3.c_str());
for (size_t i = 0; i < num_vertices(dataG.back()); ++i) // size_t vertice number in the graph
{
if(dataG.back()[i].id==fromId) fromId=i;
else if(dataG.back()[i].id==toId) toId=i;
}
boost::add_edge(fromId, toId, EdgeProperties(eLabel), dataG.back());
} break;
}
}
return dataG;
}
//==============================M A I N P R O G R A M =======================================
int main()
{
size_t length;
std::vector<Graph> dataG =creategraphs(splitstringtolines(readfromfile("3test.txt", length)));
my_callback<Graph, Graph> my_callback(dataG[0], dataG[3]);
cout<<"equal(dataG[0], dataG[3],my_callback)="<<vf2_sub_graph_iso(dataG[0], dataG[3],my_callback)<<endl;
}
How to use property maps for equivalence in my_callback function for my case?
Update
This is a simple graph file that countain only 2 graphs:
t # 0
v 0 35
v 1 47
v 2 15
v 3 14
v 4 86
e 0 1 10
e 1 2 77
e 1 3 17
e 4 2 43
t # 1
v 0 35
v 1 47
v 2 15
v 3 14
v 4 86
e 0 1 10
e 1 2 7
e 1 3 17
e 4 2 4
The graphs are have same structure but not the same labels, so this code must return false and not true:
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/vf2_sub_graph_iso.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <boost/config.hpp>
#include <boost/graph/isomorphism.hpp>
#include <boost/graph/graph_utility.hpp>
#include <boost/tuple/tuple_comparison.hpp>
#include <fstream>
#include <iostream>
#include <vector>
//for mmap:
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
using namespace boost;
//==========STRUCTURES==========
// vertex
struct VertexProperties {
int id;
int label;
VertexProperties(unsigned i = 0, unsigned l = 0) : id(i), label(l) {}
bool operator==(VertexProperties const& other) const {
return tie(id, label) == tie(other.id, other.label);
}
};
// edge
struct EdgeProperties {
unsigned label;
EdgeProperties(unsigned l = 0) :label(l) {}
bool operator==(EdgeProperties const& other) const {
return tie(label) == tie(other.label);
}
};
// Graph
struct GraphProperties {
unsigned id;
unsigned label;
GraphProperties(unsigned i = 0, unsigned l = 0) : id(i), label(l) {}
};
// adjency list
typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS, VertexProperties, EdgeProperties,
GraphProperties> Graph;
// descriptors
typedef boost::graph_traits<Graph>::vertex_descriptor vertex_t;
typedef std::pair<boost::graph_traits<Graph>::edge_descriptor, bool> edge_t;
// iterators
typedef graph_traits<Graph>::vertex_iterator vertex_iter;
typedef graph_traits<Graph>::edge_iterator edge_iter;
typedef std::pair<edge_iter, edge_iter> edge_pair;
//*********global variables*************
std::vector<Graph> dataG;
//=================callback used fro subgraph_iso=================================================================
// Default print_callback
template <typename Graph1,typename Graph2>
struct my_callback {
my_callback(const Graph1& graph1, const Graph2& graph2)
: graph1_(graph1), graph2_(graph2) {}
template <typename CorrespondenceMap1To2,
typename CorrespondenceMap2To1>
bool operator()(CorrespondenceMap1To2 /*f*/, CorrespondenceMap2To1) const {
return true;
}
private:
const Graph1& graph1_;
const Graph2& graph2_;
};
//==========handle_error==========
void handle_error(const char *msg) {
perror(msg);
exit(255);
}
//============READ ALL THE FILE AND RETURN A STRING===================
const char *readfromfile(const char *fname, size_t &length) {
int fd = open(fname, O_RDONLY);
if (fd == -1)
handle_error("open");
// obtain file size
struct stat sb;
if (fstat(fd, &sb) == -1)
handle_error("fstat");
length = sb.st_size;
const char *addr = static_cast<const char *>(mmap(NULL, length, PROT_READ, MAP_PRIVATE, fd, 0u));
if (addr == MAP_FAILED)
handle_error("mmap");
// TODO close fd at some point in time, call munmap(...)
return addr;
}
//==========SPLIT THE STRING BY NEWLINE (\n) ==========
std::vector<std::string> splitstringtolines(std::string const& str) {
std::vector<std::string> split_vector;
split(split_vector, str, is_any_of("\n"));
return split_vector;
}
//============Get a string starting from pos============
std::string getpos(int const& pos, std::string const& yy) {
size_t i = pos;
std::string str;
for (; ((yy[i] != ' ') && (i < yy.length())); i++) {str += yy[i];}
return str;
}
//==================read string vector and return graphs vector===================
std::vector<Graph> creategraphs(std::vector<std::string> const& fichlines) {
for (std::string yy : fichlines) {
switch (yy[0]) {
case 't': {
std::string str2 = getpos(4, yy);
unsigned gid = atoi(str2.c_str());
dataG.emplace_back(GraphProperties(gid, gid));
} break;
case 'v': {
assert(!dataG.empty()); // assert will terminate the program if its argument turns out to be false
// std::cout<<yy<<std::endl;
int vId, vLabel;
std::string vvv = getpos(2, yy);
vId = atoi(vvv.c_str());
std::string vvvv = getpos((int)vvv.length() + 3, yy);
// std::cout<<vvvv<<std::endl;
vLabel = atoi(vvvv.c_str());
boost::add_vertex(VertexProperties(vId, vLabel), dataG.back());
}
break;
case 'e': { // std::cout<<yy<<std::endl;
assert(!dataG.empty()); // assert will terminate the program if its argument turns out to be false
int fromId, toId, eLabel;
std::string eee = getpos(2, yy);
// std::cout<<eee<<std::endl;
fromId = atoi(eee.c_str());
std::string eee2 = getpos((int)eee.length() + 3, yy);
// std::cout<<eee2<<std::endl;
toId = atoi(eee2.c_str());
int c = (int)eee.length() + (int)eee2.length() + 4;
// std::cout<<c<<std::endl;
std::string eee3 = getpos(c, yy);
// std::cout<<eee3<<std::endl;
eLabel = atoi(eee3.c_str());
for (size_t i = 0; i < num_vertices(dataG.back()); ++i) // size_t vertice number in the graph
{
if(dataG.back()[i].id==fromId) fromId=i;
else if(dataG.back()[i].id==toId) toId=i;
}
boost::add_edge(fromId, toId, EdgeProperties(eLabel), dataG.back());
} break;
}
}
return dataG;
}
template <typename Graph1, typename Graph2>
bool my_bundled_graph_iso(Graph1 const& graph_small, Graph2 const& graph_large) {
auto const vos = boost::copy_range<std::vector<Graph::vertex_descriptor> >(vertices(graph_small));
return vf2_subgraph_iso(graph_small, graph_large, my_callback<Graph, Graph>(graph_small, graph_large), vos,
edges_equivalent (make_property_map_equivalent(boost::get(edge_bundle, graph_small), boost::get(edge_bundle, graph_large))).
vertices_equivalent(make_property_map_equivalent(boost::get(vertex_bundle, graph_small), boost::get(vertex_bundle, graph_large)))
);
}
//==============================M A I N P R O G R A M =======================================
int main() {
size_t length;
std::vector<Graph> dataG = creategraphs(splitstringtolines(readfromfile("2.txt", length)));
std::cout << std::boolalpha << my_bundled_graph_iso(dataG[0], dataG[1]) << std::endl;
}
update2
I didn't mentionned in the question and the little precedent example that vertices can be the same even if there id's are not (in different graphs).
Ok, let's dissect the documentation.
In order to pass non-default implementations for EdgeEquivalencePredicate and VertexEquivalencePredicate you need the second overload:
bool vf2_subgraph_iso(const GraphSmall& graph_small,
const GraphLarge& graph_large,
SubGraphIsoMapCallback user_callback,
const VertexOrderSmall& vertex_order_small,
const bgl_named_params<Param, Tag, Rest>& params)
This means you need at least a parameter to match vertex_order_small and params. Let's do the minimum amount of work and supply only vertex_order_small first:
The ordered vertices of the smaller (first) graph graph_small. During the matching process the vertices are examined in the order given by vertex_order_small. Type VertexOrderSmall must be a model of ContainerConcept with value type graph_traits<GraphSmall>::vertex_descriptor.
Default The vertices are ordered by multiplicity of in/out degrees.
Let's pass a vector of vertex descriptors in default order:
auto const& graph_small = dataG[0];
auto const& graph_large = dataG[3];
auto vos = boost::copy_range<std::vector<Graph::vertex_descriptor> >(vertices(graph_small));
bool iso = vf2_graph_iso(graph_small, graph_large, my_callback, vos, no_named_parameters());
Next step, you add the named parameters, e.g.: [¹]
bool iso = vf2_graph_iso(graph_small, graph_large, my_callback, vos,
edges_equivalent ([&graph_small, &graph_large](Graph::edge_descriptor small_ed, Graph::edge_descriptor large_ed) {
return graph_small[small_ed] == graph_large[large_ed];
}).
vertices_equivalent([&graph_small, &graph_large](Graph::vertex_descriptor small_vd, Graph::vertex_descriptor large_vd) {
return graph_small[small_vd] == graph_large[large_vd];
})
);
As the final topping use make_property_map_equivalent documented here:
bool iso = vf2_graph_iso(graph_small, graph_large, my_callback, vos,
edges_equivalent (make_property_map_equivalent(boost::get(edge_bundle, graph_small), boost::get(edge_bundle, graph_large))).
vertices_equivalent(make_property_map_equivalent(boost::get(vertex_bundle, graph_small), boost::get(vertex_bundle, graph_large)))
);
See all three steps Live On Coliru
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/vf2_sub_graph_iso.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <boost/config.hpp>
#include <boost/graph/isomorphism.hpp>
#include <boost/graph/graph_utility.hpp>
#include <boost/tuple/tuple_comparison.hpp>
#include <fstream>
#include <iostream>
#include <vector>
//for mmap:
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
using namespace boost;
//==========STRUCTURES==========
// vertex
struct VertexProperties {
int id;
int label;
VertexProperties(unsigned i = 0, unsigned l = 0) : id(i), label(l) {}
bool operator==(VertexProperties const& other) const {
return tie(id, label) == tie(other.id, other.label);
}
};
// edge
struct EdgeProperties {
unsigned label;
EdgeProperties(unsigned l = 0) :label(l) {}
bool operator==(EdgeProperties const& other) const {
return tie(label) == tie(other.label);
}
};
// Graph
struct GraphProperties {
unsigned id;
unsigned label;
GraphProperties(unsigned i = 0, unsigned l = 0) : id(i), label(l) {}
};
// adjency list
typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS, VertexProperties, EdgeProperties,
GraphProperties> Graph;
// descriptors
typedef boost::graph_traits<Graph>::vertex_descriptor vertex_t;
typedef std::pair<boost::graph_traits<Graph>::edge_descriptor, bool> edge_t;
// iterators
typedef graph_traits<Graph>::vertex_iterator vertex_iter;
typedef graph_traits<Graph>::edge_iterator edge_iter;
typedef std::pair<edge_iter, edge_iter> edge_pair;
//*********global variables*************
std::vector<Graph> dataG;
//=================callback used fro subgraph_iso=================================================================
// Default print_callback
template <typename Graph1,typename Graph2>
struct my_callback {
my_callback(const Graph1& graph1, const Graph2& graph2)
: graph1_(graph1), graph2_(graph2) {}
template <typename CorrespondenceMap1To2,
typename CorrespondenceMap2To1>
bool operator()(CorrespondenceMap1To2 /*f*/, CorrespondenceMap2To1) const {
return true;
}
private:
const Graph1& graph1_;
const Graph2& graph2_;
};
//==========handle_error==========
void handle_error(const char *msg) {
perror(msg);
exit(255);
}
//============READ ALL THE FILE AND RETURN A STRING===================
const char *readfromfile(const char *fname, size_t &length) {
int fd = open(fname, O_RDONLY);
if (fd == -1)
handle_error("open");
// obtain file size
struct stat sb;
if (fstat(fd, &sb) == -1)
handle_error("fstat");
length = sb.st_size;
const char *addr = static_cast<const char *>(mmap(NULL, length, PROT_READ, MAP_PRIVATE, fd, 0u));
if (addr == MAP_FAILED)
handle_error("mmap");
// TODO close fd at some point in time, call munmap(...)
return addr;
}
//==========SPLIT THE STRING BY NEWLINE (\n) ==========
std::vector<std::string> splitstringtolines(std::string const& str) {
std::vector<std::string> split_vector;
split(split_vector, str, is_any_of("\n"));
return split_vector;
}
//============Get a string starting from pos============
std::string getpos(int const& pos, std::string const& yy) {
size_t i = pos;
std::string str;
for (; ((yy[i] != ' ') && (i < yy.length())); i++) {str += yy[i];}
return str;
}
//==================read string vector and return graphs vector===================
std::vector<Graph> creategraphs(std::vector<std::string> const& fichlines) {
for (std::string yy : fichlines) {
switch (yy[0]) {
case 't': {
std::string str2 = getpos(4, yy);
unsigned gid = atoi(str2.c_str());
dataG.emplace_back(GraphProperties(gid, gid));
} break;
case 'v': {
assert(!dataG.empty()); // assert will terminate the program if its argument turns out to be false
// std::cout<<yy<<std::endl;
int vId, vLabel;
std::string vvv = getpos(2, yy);
vId = atoi(vvv.c_str());
std::string vvvv = getpos((int)vvv.length() + 3, yy);
// std::cout<<vvvv<<std::endl;
vLabel = atoi(vvvv.c_str());
boost::add_vertex(VertexProperties(vId, vLabel), dataG.back());
}
break;
case 'e': { // std::cout<<yy<<std::endl;
assert(!dataG.empty()); // assert will terminate the program if its argument turns out to be false
int fromId, toId, eLabel;
std::string eee = getpos(2, yy);
// std::cout<<eee<<std::endl;
fromId = atoi(eee.c_str());
std::string eee2 = getpos((int)eee.length() + 3, yy);
// std::cout<<eee2<<std::endl;
toId = atoi(eee2.c_str());
int c = (int)eee.length() + (int)eee2.length() + 4;
// std::cout<<c<<std::endl;
std::string eee3 = getpos(c, yy);
// std::cout<<eee3<<std::endl;
eLabel = atoi(eee3.c_str());
for (size_t i = 0; i < num_vertices(dataG.back()); ++i) // size_t vertice number in the graph
{
if(dataG.back()[i].id==fromId) fromId=i;
else if(dataG.back()[i].id==toId) toId=i;
}
boost::add_edge(fromId, toId, EdgeProperties(eLabel), dataG.back());
} break;
}
}
return dataG;
}
//==============================M A I N P R O G R A M =======================================
int main() {
size_t length;
std::cout << std::boolalpha;
std::vector<Graph> dataG = creategraphs(splitstringtolines(readfromfile("3test.txt", length)));
auto const& graph_small = dataG[0];
auto const& graph_large = dataG[3];
my_callback<Graph, Graph> my_callback(graph_small, graph_large);
std::cout << "equal(graph_small, graph_large,my_callback)=" << vf2_graph_iso(graph_small, graph_large, my_callback) << std::endl;
// first step
{
auto vos = boost::copy_range<std::vector<Graph::vertex_descriptor> >(vertices(graph_small));
std::cout << "equal(graph_small, graph_large,my_callback)=" << vf2_graph_iso(graph_small, graph_large, my_callback, vos, no_named_parameters()) << std::endl;
}
// second step
{
auto vos = boost::copy_range<std::vector<Graph::vertex_descriptor> >(vertices(graph_small));
bool iso = vf2_graph_iso(graph_small, graph_large, my_callback, vos,
edges_equivalent ([&graph_small, &graph_large](Graph::edge_descriptor small_ed, Graph::edge_descriptor large_ed) {
return graph_small[small_ed] == graph_large[large_ed];
}).
vertices_equivalent([&graph_small, &graph_large](Graph::vertex_descriptor small_vd, Graph::vertex_descriptor large_vd) {
return graph_small[small_vd] == graph_large[large_vd];
})
);
std::cout << "equal(graph_small, graph_large,my_callback)=" << iso << std::endl;
}
// third step
{
auto vos = boost::copy_range<std::vector<Graph::vertex_descriptor> >(vertices(graph_small));
bool iso = vf2_graph_iso(graph_small, graph_large, my_callback, vos,
edges_equivalent (make_property_map_equivalent(boost::get(edge_bundle, graph_small), boost::get(edge_bundle, graph_large))).
vertices_equivalent(make_property_map_equivalent(boost::get(vertex_bundle, graph_small), boost::get(vertex_bundle, graph_large)))
);
std::cout << "equal(graph_small, graph_large,my_callback)=" << iso << std::endl;
}
}
Prints output:
equal(graph_small, graph_large,my_callback)=true
equal(graph_small, graph_large,my_callback)=true
equal(graph_small, graph_large,my_callback)=false
equal(graph_small, graph_large,my_callback)=false
[¹] Of course assuming you implement operator== for your edge and vertex property types (see full listing)
After reading a graph from a txt file:
t # 0
v 0 5
v 1 9
v 2 8
v 3 7
e 0 1 4
e 1 2 68
e 3 2 18
I'm triying to test if two edges are neighbours.
here is the function:
bool edgesneighbors(Graph g, edge_iter ep1,edge_iter ep2)
{
vertex_t fromep1 = source(*ep1, g);
vertex_t toep1 = target(*ep1, g);
vertex_t fromep2 = source(*ep2, g);
vertex_t toep2 = target(*ep2, g);
cout<<g[fromep1].id<<"--"<<g[toep1].id<<endl;cout<<g[fromep2].id<<"--"<<g[toep2].id<<endl;
if(graphconnexe(g)){return((fromep1==fromep2)||(fromep1==toep2)||(toep1==toep2)||(fromep2==toep1));}
else {return false;}
}
and here is the part of the program where I do the test.
I want to test all the edges two by two.
if (!dataG.empty())
{
edge_pair ep;edge_iter e1,e2;
for (ep = edges(dataG[0]); ep.first != ep.second; ++ep.first) //ep edge number
{
e1=ep.first;
e2=ep.second;
}
cout<<"edgesneighbors"<<edgesneighbors(dataG[0],e1,e2)<<endl;
}
But when I run it I got a "core dumped" error, and I think it comes from
e2=ep.second
How can I solve this?
for more information here is the full source code: http://pastebin.com/3HrmJppv
I want to know if there is any predefined functions in BOOST to work with edges/vertices adjacency ?
1. don't work on a copy
bool edgesneighbors(Graph g, edge_iter ep1, edge_iter ep2)
This takes g by value, making a copy. Of course, ep1 and ep2 are not valid iterators into the copy
Take it by reference:
bool edgesneighbors(Graph const& g, edge_iter ep1, edge_iter ep2) {
2. don't use the end iterator
You used ep.second, which is the end iterator. That's invalid. Instead:
if (!dataG.empty()) {
edge_pair ep = edges(dataG[0]);
if (size(ep) >= 2) {
Graph::edge_descriptor e1 = ep.first++;
Graph::edge_descriptor e2 = ep.first++;
cout << "edgesneighbors" << edgesneighbors(dataG[0], e1, e2) << endl;
}
}
3. prefer writing the intention of the code
Until your profiling tells you you have performance bottlenecks in this function:
template <typename Graph, typename E = typename boost::graph_traits<Graph>::edge_descriptor>
bool edgesneighbors(Graph const& g, E e1, E e2) {
std::set<vertex_t> vertex_set {
source(e1, g), target(e1, g),
source(e2, g), target(e2, g),
};
return graphconnexe(g) && vertex_set.size() < 4;
}
So there is less need to "trust" that all these conditions were spelled correctly.
DEMO
Live On Coliru
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/vf2_sub_graph_iso.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <ctime>
#include <queue> // std::queue
// for mmap:
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
using namespace std;
using namespace boost;
//==========STRUCTURES==========
// vertex
struct VertexProperties {
int id;
int label;
VertexProperties(unsigned i = 0, unsigned l = 0) : id(i), label(l) {}
};
// edge
struct EdgeProperties {
unsigned id;
unsigned label;
EdgeProperties(unsigned i = 0, unsigned l = 0) : id(i), label(l) {}
};
// Graph
struct GraphProperties {
unsigned id;
unsigned label;
GraphProperties(unsigned i = 0, unsigned l = 0) : id(i), label(l) {}
};
// adjency list
typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS, VertexProperties, EdgeProperties,
GraphProperties> Graph;
// descriptors
typedef boost::graph_traits<Graph>::vertex_descriptor vertex_t;
typedef std::pair<boost::graph_traits<Graph>::edge_descriptor, bool> edge_t;
// iterators
typedef graph_traits<Graph>::vertex_iterator vertex_iter;
typedef graph_traits<Graph>::edge_iterator edge_iter;
typedef std::pair<edge_iter, edge_iter> edge_pair;
//==========READ ALL THE FILE AND RETURN A STRING==========
void handle_error(const char *msg) {
perror(msg);
exit(255);
}
//===============================
const char *readfromfile2(const char *fname, size_t &length) {
int fd = open(fname, O_RDONLY);
if (fd == -1)
handle_error("open");
// obtain file size
struct stat sb;
if (fstat(fd, &sb) == -1)
handle_error("fstat");
length = sb.st_size;
const char *addr = static_cast<const char *>(mmap(NULL, length, PROT_READ, MAP_PRIVATE, fd, 0u));
if (addr == MAP_FAILED)
handle_error("mmap");
// TODO close fd at some point in time, call munmap(...)
return addr;
}
//==========SPLIT THE STRING BY NEWLINE (\n) ==========
vector<string> splitstringtolines(string const &str) {
vector<string> split_vector;
split(split_vector, str, is_any_of("\n"));
return split_vector;
}
//==============================================================
string getpos(int pos, string yy) {
size_t i = pos;
string str;
for (; yy[i] != ' ' && i < yy.length(); i++)
str += yy[i];
return str;
}
//==============================================================
std::vector<Graph> creategraphs(std::vector<string> const &fichlines) {
std::vector<Graph> dataG;
int compide = 0; // compteur de id edge
for (string yy : fichlines) {
switch (yy[0]) {
case 't': {
string str2 = getpos(4, yy);
unsigned gid = atoi(str2.c_str());
dataG.emplace_back(GraphProperties(gid, gid));
compide = 0;
} break;
case 'v': {
assert(!dataG.empty()); // assert will terminate the program if its argument turns out to be false
// cout<<yy<<endl;
int vId, vLabel;
string vvv = getpos(2, yy);
vId = atoi(vvv.c_str());
string vvvv = getpos((int)vvv.length() + 3, yy);
// cout<<vvvv<<endl;
vLabel = atoi(vvvv.c_str());
boost::add_vertex(VertexProperties(vId, vLabel), dataG.back());
}
break;
case 'e': { // cout<<yy<<endl;
assert(!dataG.empty()); // assert will terminate the program if its argument turns out to be false
int fromId, toId, eLabel;
string eee = getpos(2, yy);
// cout<<eee<<endl;
fromId = atoi(eee.c_str());
string eee2 = getpos((int)eee.length() + 3, yy);
// cout<<eee2<<endl;
toId = atoi(eee2.c_str());
int c = (int)eee.length() + (int)eee2.length() + 4;
// cout<<c<<endl;
string eee3 = getpos(c, yy);
// cout<<eee3<<endl;
eLabel = atoi(eee3.c_str());
boost::add_edge(fromId, toId, EdgeProperties(compide, eLabel), dataG.back());
compide++;
} break;
}
}
return dataG;
}
//==================================================================================
bool graphconnexe(Graph const &g) { return num_edges(g) >= num_vertices(g) - 1; }
//============================================================================
void printgraph(Graph const &gr) {
typedef std::pair<edge_iter, edge_iter> edge_pair;
std::cout << " contains " << num_vertices(gr) << " vertices, and " << num_edges(gr) << " edges " << std::endl;
if (graphconnexe(gr)) {
// Vertex list
if (num_vertices(gr) != 0) {
std::cout << " Vertex list: " << std::endl;
for (size_t i = 0; i < num_vertices(gr); ++i) // size_t vertice number in the graph
{
std::cout << " v[" << i << "] ID: " << gr[i].id << ", Label: " << gr[i].label << std::endl;
}
}
// Edge list
if (num_edges(gr) != 0) {
std::cout << " Edge list: " << std::endl;
edge_pair ep;
for (ep = edges(gr); ep.first != ep.second; ++ep.first) // ep edge number
{
vertex_t from = source(*ep.first, gr);
vertex_t to = target(*ep.first, gr);
edge_t edg = edge(from, to, gr);
std::cout << " e(" << gr[from].id << "," << gr[to].id << ") ID: " << gr[edg.first].id
<< " , Label: " << gr[edg.first].label << std::endl;
}
}
std::cout << "\n\n" << std::endl;
} else {
cout << "Please check this graph connectivity." << endl;
}
}
//==================================================================================
struct my_callback {
template <typename CorrespondenceMap1To2, typename CorrespondenceMap2To1>
bool operator()(CorrespondenceMap1To2 f, CorrespondenceMap2To1 g) const {
return false;
}
};
//==================================================================================
/*bool graphexistance( std::vector<Graph> const& v, Graph item)
{
return std::find(v.begin(), v.end(), item)!=v.end();
}*/
//=========================================================
bool gUe(Graph &g, edge_iter ep, Graph t) {
vertex_t from = source(*ep, t);
vertex_t to = target(*ep, t);
Graph::edge_descriptor copied_edge = boost::add_edge(from, to, t[*ep], g).first;
g[source(copied_edge, g)] = t[from];
g[target(copied_edge, g)] = t[to];
if (graphconnexe(g) && graphconnexe(t)) {
return vf2_subgraph_iso(g, t, my_callback());
} else {
return false;
}
}
//==========================================
bool verticeexist(Graph &g, int vId, int vlabel) {
int cpt = 0;
if (num_edges(g) != 0) {
for (size_t i = 0; i < num_vertices(g); ++i) // size_t vertice number in the graph
{
if ((g[i].id == vId) && (g[i].label == vlabel)) {
cpt++;
}
}
}
return cpt != 0;
}
//========================================
bool edgeexist(Graph g, int fromid, int toid, unsigned elabel) {
int bn = 0;
if (graphconnexe(g)) {
if (num_edges(g) != 0) {
edge_pair ep;
for (ep = edges(g); ep.first != ep.second; ++ep.first) // ep edge number
{
vertex_t from = source(*ep.first, g);
vertex_t to = target(*ep.first, g);
edge_t edg = edge(from, to, g);
if ((g[from].id == fromid) && (g[to].id == toid) && (g[edg.first].label == elabel)) {
bn++;
}
}
}
}
return (bn != 0);
}
// =========================================
bool vareneighbors(Graph g, int a, int b) {
int bn = 0;
if (graphconnexe(g)) {
if (num_edges(g) != 0) {
edge_pair ep;
for (ep = edges(g); ep.first != ep.second; ++ep.first) // ep edge number
{
vertex_t from = source(*ep.first, g);
vertex_t to = target(*ep.first, g);
if (((g[from].id == a) || (g[to].id == a)) && ((g[from].id == b) || (g[to].id == b))) {
bn++;
}
}
}
}
return (bn != 0);
}
//==========================================
template <typename Graph, typename E = typename boost::graph_traits<Graph>::edge_descriptor>
bool edgesneighbors(Graph const& g, E e1, E e2) {
std::set<vertex_t> vertex_set {
source(e1, g), target(e1, g),
source(e2, g), target(e2, g),
};
return graphconnexe(g) && vertex_set.size() < 4;
}
//==========================================
void emptygraphaddedge(Graph &g, int fromId, int toId, int eLabel) {
if (num_edges(g) == 0) {
boost::add_edge(fromId, toId, EdgeProperties(num_edges(g) + 1, eLabel), g);
}
}
//==========================================
int main() {
clock_t start = std::clock();
size_t length;
std::vector<Graph> dataG = creategraphs(splitstringtolines(readfromfile2("testgUe.txt", length)));
typedef std::pair<edge_iter, edge_iter> edge_pair;
if (!dataG.empty()) {
edge_pair ep = edges(dataG[0]);
if (size(ep) >= 2) {
Graph::edge_descriptor e1 = *ep.first++;
Graph::edge_descriptor e2 = *ep.first++;
cout << "edgesneighbors" << edgesneighbors(dataG[0], e1, e2) << endl;
}
}
// end and time
cout << "FILE Contains " << dataG.size() << " graphs.\nTIME: " << (std::clock() - start) / (double)CLOCKS_PER_SEC
<< "s" << endl; // fin du programme.
}
Output:
edgesneighbors1
FILE Contains 1 graphs.
TIME: 0s
I would like to use the Boost Graph Library more effectively by attaching properly encapsulated classes to graph nodes & edges. I am not interested in attaching int's or POD struct's. Following suggestions on other StackOverFlow articles, I have developed the following sample app. Can anybody tell me the magic I need to sprinkle onto the EdgeInfo class to make this thing compile?
I am using Visual Studio 2010 with Boost 1.54.0.
//------------------------------------------------------------------------
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/properties.hpp>
#include <boost/graph/dijkstra_shortest_paths.hpp>
#include <iostream>
//------------------------------------------------------------------------
struct VertexInfo
{
struct Tag
{
typedef boost::vertex_property_tag kind;
static std::size_t const num; // ???
};
typedef boost::property<Tag, VertexInfo> Property;
};
std::size_t const VertexInfo::Tag::num = reinterpret_cast<std::size_t> (&VertexInfo::Tag::num);
//------------------------------------------------------------------------
class EdgeInfo
{
int _nWeight;
public:
int getWeight () const {return _nWeight;}
struct Tag
{
typedef boost::edge_property_tag kind;
static std::size_t const num; // ???
};
typedef boost::property<boost::edge_weight_t, int> Weight;
typedef boost::property<Tag, EdgeInfo> Property;
EdgeInfo (int nWeight = 9999) : _nWeight (nWeight) {}
};
std::size_t const EdgeInfo::Tag::num = reinterpret_cast<std::size_t> (&EdgeInfo::Tag::num);
//------------------------------------------------------------------------
typedef boost::property<boost::edge_weight_t, int> EdgeProperty;
typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS, VertexInfo::Property, EdgeProperty> GraphWorking;
typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS, VertexInfo::Property, EdgeInfo::Property> GraphBroken;
//------------------------------------------------------------------------
template<typename GraphType, typename EdgeType> void
dijkstra (GraphType g, EdgeType e)
{
typedef boost::graph_traits<GraphType>::vertex_descriptor VertexDesc;
typedef boost::graph_traits<GraphType>::edge_descriptor EdgeDesc;
VertexDesc u = add_vertex (g);
VertexDesc v = add_vertex (g);
std::pair<EdgeDesc, bool> result = add_edge (u, v, e, g);
std::vector<VertexDesc> vecParent (num_vertices (g), 0);
dijkstra_shortest_paths (g, u, boost::predecessor_map (&vecParent[0]));
}
//------------------------------------------------------------------------
int
main (int argc, char** argv)
{
#if defined(BOOST_MSVC) && BOOST_MSVC <= 1300
std::cout << "Buy a new compiler\n";
#else
std::cout << "Your compiler is fine\n";
#endif
GraphWorking gWorking;
GraphBroken gBroken;
dijkstra (gWorking, 3);
dijkstra (gBroken, EdgeInfo (4));
}
//------------------------------------------------------------------------
When I run your code i get an error in numeric_limits that results from a distance map in dijkstra.
"
Error 1 error C2440: '' : cannot convert from 'int' to 'D' c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\limits 92
"
probably from this part of http://www.boost.org/doc/libs/1_55_0/boost/graph/dijkstra_shortest_paths.hpp
typedef typename property_traits<DistanceMap>::value_type D;
D inf = choose_param(get_param(params, distance_inf_t()),
(std::numeric_limits<D>::max)());
I think there may be an easier way to tie a real class for your nodes and edges. Its more trouble than its worth to create vertex and edge property classes that will provide all the needed tagged properties (index, weight, color, etc) needed for most boost algorihtms.
Don't forget Edge class != Edge property.
The edge class is really the graph_traits::edge_discriptor.
Properties are the data associated with each edge. Same for vertex.
I would use bundled properties and add a pointer to your class in each one.
Here is an example
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/properties.hpp>
#include <boost/graph/dijkstra_shortest_paths.hpp>
#include <boost/property_map/property_map.hpp>
#include <iostream>
//Fancy Edge class
class EdgeData
{
int _data;
public:
EdgeData(){
_data=0;
}
EdgeData(int data){
_data= data;
}
void printHello(){
std::cout << "hello " << _data << std::endl;
}
};
//Fancy Vert class
class VertexData
{
int _data;
public:
VertexData(){
_data=0;
}
VertexData(int data){
_data= data;
}
void printHello(){
std::cout << "hello " << _data << std::endl;
}
};
//bundled properties
struct VertexProps
{
VertexData* data;
};
struct EdgeProps
{
size_t weight;
EdgeData* data;
};
//Graph
typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS,
VertexProps,EdgeProps> Graph;
//helpers
//Vertex
typedef boost::graph_traits<Graph>::vertex_descriptor Vertex;
//Edge
typedef boost::graph_traits<Graph>::edge_descriptor Edge;
//------------------------------------------------------------------------
template<typename GraphType> void
templateFunction (GraphType g)
{
typedef boost::graph_traits<GraphType>::edge_iterator edge_iter;
std::pair<edge_iter, edge_iter> ep;
edge_iter ei, ei_end;
ep = edges(g);
ei_end = ep.second;
for (ei = ep.first; ei != ei_end; ++ei){
g[*ei].data->printHello();
}
}
//if you want to alter the graph use referenced &graph
template<typename GraphType,typename EdgePropType> void
templateFuctionProps(GraphType &g, EdgePropType e)
{
typedef boost::graph_traits<GraphType>::vertex_descriptor VertexDesc;
VertexDesc v = add_vertex(g);
VertexDesc u = add_vertex(g);
//add an edge with the Edge property
add_edge(v,u,e,g);
}
//------------------------------------------------------------------------
int
main (int argc, char** argv)
{
Graph g;
//vertex holder
std::vector<Vertex> verts;
//add some verts
for(size_t i = 0; i < 5; ++i){
Vertex v = add_vertex(g);
g[v].data = new VertexData(i%2);
verts.push_back(v);
}
//add some edges
for(size_t i = 0; i < 4; ++i){
std::pair<Edge,bool> p = add_edge(verts.at(i),verts.at(i+1),g);
Edge e = p.first;
g[e].data = new EdgeData(i%3);
g[e].weight = 5;
}
//iterate edges and call a class function
typedef boost::graph_traits<Graph>::edge_iterator edge_iter;
std::pair<edge_iter, edge_iter> ep;
edge_iter ei, ei_end;
ep = edges(g);
ei_end = ep.second;
for (ei = ep.first; ei != ei_end; ++ei){
g[*ei].data->printHello();
}
std::cout << "Iterate with template with template " << std::endl;
templateFunction(g);
//Use an edge property in a function
EdgeProps edgeProp;
edgeProp.weight = 5;
edgeProp.data = new EdgeData(150);
std::cout << "Modity graph with template function " << std::endl;
templateFuctionProps(g,edgeProp);
std::cout << "Iterate again with template" << std::endl;
templateFunction(g);
//getting the weight property
boost::property_map<Graph,size_t EdgeProps::*>::type w
= get(&EdgeProps::weight, g);
std::cout << "Print weights" << std::endl;
ep = edges(g);
ei_end = ep.second;
for (ei = ep.first; ei != ei_end; ++ei){
std::cout << w[*ei] << std::endl;
}
std::cin.get();
}
//------------------------------------------------------------------------
Also I see you are using vecS, meaning that both vectors and edges are stored as vectors with a fixed ordering.
You could just have a class that stores your Edge and Vertex classes with a pointer to the vertex map or edge map for the graph.
I don't know your goals for this project, but I would definitely have higher level classes than manage all of this boost stuff behind the scenes. Meaning storing classes in a vector with an index look up would be hidden and encapsulated from applications that want to use your nice graph class.