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)
Related
I want to be able to store values from a file into a user defined struct. I want to have columns that hold different types of data such as: a std::string for Character names, a float for Character health and an int for Character experience.
My desired output is to have a 6 by 3 array as shown below
Alice 23.4 3210
Xander 45.3 1110
Bernard 12.9 2024
Yanni 23.7 1098
Craw 50.5 980
Zack 11.9 1024
Here is what I have tried so far:
struct charData
{
string charName;
float charHealth;
int charExp;
};
int main() {
const int NUM_COLS = 3;
int NUM_ROWS = 6;
int charNumber = 0;
int userInput;
int loop = 0;
int i,j;
string line;
ifstream myIn; // Declare read file stream
myIn.open("party.dat"); // Open file
struct charData charArray[NUM_ROWS][NUM_COLS];
while( !myIn.eof() ) {
for ( j = 0; j < NUM_COLS ; j++) {
for ( i = 0; i < NUM_ROWS ; i++) {
myIn >> charArray[i][j].charName;
myIn >> charArray[i][j].charHealth;
myIn >> charArray[i][j].charExp;
}
}
}
return 0;
}
I am also planning on to allow the user to sort the data by each column type. To sort names alphabetically, sort by health and or experience: I am thinking of using a 2D array. Would this be the best option?
I think you are confusing the number of fields in your structure with the number of columns of data. You show data for only 6 records of 3 fields each. Try setting NUM_COLS to 1 and see if it works any better for you.
Or, get rid of the second dimension (j) of your array entirely.
I don't know if you are reading your file as binary or as a text; but within my answer I'm reading from a text file where each field on a line of text is separated by a space character. I will include all files necessary to compile and build a proper working program of what you are looking for. Some of these includes may not be needed but are within my solution for I have larger project that depends on these to properly build.
stdafx.h
#ifndef STDAFX_H
#define STDAFX_H
#include <Windows.h>
#include <stdio.h>
#include <tchar.h>
#include <conio.h>
#include <string>
#include <sstream>
#include <fstream>
#include <iostream>
#include <iomanip>
#include <vector>
#include <array>
#include <memory>
#include <queue>
#include <functional>
#include <algorithm>
// User Application Specific
// #include "ExceptionHandler.h" // Required For My Solution But Isn't Used In Yours
namespace util {
enum ReturnCode {
RETURN_OK = 0,
RETURN_ERROR = 1,
}; // ReturnCode
extern const unsigned INVALID_UNSIGNED;
extern const unsigned INVALID_UNSIGNED_SHORT;
} // namespace util
#endif // STDAFX_H
stdafx.cpp
#include "stdafx.h"
namespace util {
const unsigned INVALID_UNSIGNED = static_cast<const unsigned>( -1 );
const unsigned INVALID_UNSIGNED_SHORT = static_cast<const unsigned short>( -1 );
} // namespace util
Utility.h
#ifndef UTILITY_H
#define UTILITY_H
namespace util {
class Utility {
public:
static void pressAnyKeyToQuit();
static std::string toUpper(const std::string& str);
static std::string toLower(const std::string& str);
static std::string trim(const std::string& str, const std::string elementsToTrim = " \t\n\r");
static unsigned convertToUnsigned(const std::string& str);
static int convertToInt(const std::string& str);
static float convertToFloat(const std::string& str);
static std::vector<std::string> splitString(const std::string& strStringToSplit, const std::string& strDelimiter, const bool keepEmpty = true);
private:
Utility(); // Private - Not A Class Object
Utility(const Utility& c); // Not Implemented
Utility& operator=(const Utility& c); // Not Implemented
template<typename T>
static bool stringToValue(const std::string& str, T* pValue, unsigned uNumValues);
template<typename T>
static T getValue(const std::string& str, std::size_t& remainder);
}; // Utility
#include "Utility.inl"
} // namespace util
#endif // UTILITY_H
Utility.inl
// ----------------------------------------------------------------------------
// stringToValue()
template<typename T>
static bool Utility::stringToValue(const std::string& str, T* pValue, unsigned uNumValues) {
int numCommas = std::count(str.begin(), str.end(), ',');
if (numCommas != uNumValues - 1) {
return false;
}
std::size_t remainder;
pValue[0] = getValue<T>(str, remainder);
if (uNumValues == 1) {
if (str.size() != remainder) {
return false;
}
}
else {
std::size_t offset = remainder;
if (str.at(offset) != ',') {
return false;
}
unsigned uLastIdx = uNumValues - 1;
for (unsigned u = 1; u < uNumValues; ++u) {
pValue[u] = getValue<T>(str.substr(++offset), remainder);
offset += remainder;
if ((u < uLastIdx && str.at(offset) != ',') ||
(u == uLastIdx && offset != str.size()))
{
return false;
}
}
}
return true;
} // stringToValue
Utility.cpp
#include "stdafx.h"
#include "Utility.h"
namespace util {
// ----------------------------------------------------------------------------
// pressAnyKeyToQuit()
void Utility::pressAnyKeyToQuit() {
std::cout << "Press any key to quit" << std::endl;
_getch();
} // pressAnyKeyToQuit
// ----------------------------------------------------------------------------
// toUpper()
std::string Utility::toUpper( const std::string& str ) {
std::string result = str;
std::transform( str.begin(), str.end(), result.begin(), ::toupper );
return result;
} // toUpper
// ----------------------------------------------------------------------------
// toLower()
std::string Utility::toLower( const std::string& str ) {
std::string result = str;
std::transform( str.begin(), str.end(), result.begin(), ::tolower );
return result;
} // toLower
// ----------------------------------------------------------------------------
// trim()
// Removes Elements To Trim From Left And Right Side Of The str
std::string Utility::trim( const std::string& str, const std::string elementsToTrim ) {
std::basic_string<char>::size_type firstIndex = str.find_first_not_of( elementsToTrim );
if ( firstIndex == std::string::npos ) {
return std::string(); // Nothing Left
}
std::basic_string<char>::size_type lastIndex = str.find_last_not_of( elementsToTrim );
return str.substr( firstIndex, lastIndex - firstIndex + 1 );
} // trim
// ----------------------------------------------------------------------------
// getValue()
template<>
float Utility::getValue( const std::string& str, std::size_t& remainder ) {
return std::stof( str, &remainder );
} // getValue <float>
// ----------------------------------------------------------------------------
// getValue()
template<>
int Utility::getValue( const std::string& str, std::size_t& remainder ) {
return std::stoi( str, &remainder );
} // getValue <int>
// ----------------------------------------------------------------------------
// getValue()
template<>
unsigned Utility::getValue( const std::string& str, std::size_t& remainder ) {
return std::stoul( str, &remainder );
} // getValue <unsigned>
// ----------------------------------------------------------------------------
// convertToUnsigned()
unsigned Utility::convertToUnsigned( const std::string& str ) {
unsigned u = 0;
if ( !stringToValue( str, &u, 1 ) ) {
std::ostringstream strStream;
strStream << __FUNCTION__ << " Bad conversion of [" << str << "] to unsigned";
throw strStream.str();
}
return u;
} // convertToUnsigned
// ----------------------------------------------------------------------------
// convertToInt()
int Utility::convertToInt( const std::string& str ) {
int i = 0;
if ( !stringToValue( str, &i, 1 ) ) {
std::ostringstream strStream;
strStream << __FUNCTION__ << " Bad conversion of [" << str << "] to int";
throw strStream.str();
}
return i;
} // convertToInt
// ----------------------------------------------------------------------------
// convertToFloat()
float Utility::convertToFloat(const std::string& str) {
float f = 0;
if (!stringToValue(str, &f, 1)) {
std::ostringstream strStream;
strStream << __FUNCTION__ << " Bad conversion of [" << str << "] to float";
throw strStream.str();
}
return f;
} // convertToFloat
// ----------------------------------------------------------------------------
// splitString()
std::vector<std::string> Utility::splitString( const std::string& strStringToSplit, const std::string& strDelimiter, const bool keepEmpty ) {
std::vector<std::string> vResult;
if ( strDelimiter.empty() ) {
vResult.push_back( strStringToSplit );
return vResult;
}
std::string::const_iterator itSubStrStart = strStringToSplit.begin(), itSubStrEnd;
while ( true ) {
itSubStrEnd = search( itSubStrStart, strStringToSplit.end(), strDelimiter.begin(), strDelimiter.end() );
std::string strTemp( itSubStrStart, itSubStrEnd );
if ( keepEmpty || !strTemp.empty() ) {
vResult.push_back( strTemp );
}
if ( itSubStrEnd == strStringToSplit.end() ) {
break;
}
itSubStrStart = itSubStrEnd + strDelimiter.size();
}
return vResult;
} // splitString
} // namspace util
CharacterData.h
#ifndef CHARACTER_DATA_H
#define CHARACTER_DATA_H
class CharacterData {
private:
std::string m_name;
float m_health;
unsigned m_exp;
public:
CharacterData();
CharacterData( const std::string& name, float health, unsigned exp );
void setName( const std::string& name );
void setHealth( float health );
void setExperience( unsigned exp );
std::string getName() const;
float getHealth() const;
unsigned getExperience() const;
private:
CharacterData( const CharacterData& c ); // Not Implemented
CharacterData& operator=( const CharacterData& c ); // Not Implemented
}; // CharacterData
#endif // CHARACTER_DATA_H
CharacterData.cpp
#include "stdafx.h"
#include "CharacterData.h"
// ----------------------------------------------------------------------------
// CharacterData()
CharacterData::CharacterData() :
m_name( std::string() ),
m_health( 0.0f ),
m_exp( 0 ) {
} // CharacterData
// ----------------------------------------------------------------------------
// CharacterData()
CharacterData::CharacterData( const std::string& name, float health, unsigned exp ) :
m_name( name ),
m_health( health ),
m_exp( exp ) {
} // CharacterData
// ----------------------------------------------------------------------------
// setName()
void CharacterData::setName( const std::string& name ) {
m_name = name;
} // setName
// ----------------------------------------------------------------------------
// getName()
std::string CharacterData::getName() const {
return m_name;
} // getName
// ----------------------------------------------------------------------------
// setHealth()
void CharacterData::setHealth( float health ) {
m_health = health;
} // setHealth
// ----------------------------------------------------------------------------
// getHealth()
float CharacterData::getHealth() const {
return m_health;
} // getHealth
// ----------------------------------------------------------------------------
// setExperience()
void CharacterData::setExperience( unsigned exp ) {
m_exp = exp;
} // setExperience
// ----------------------------------------------------------------------------
// getExperience()
unsigned CharacterData::getExperience() const {
return m_exp;
} // getExperience
CharacterDatabase.h
#ifndef CHARACTER_DATABASE_H
#define CHARACTER_DATABASE_H
class CharacterData;
class CharacterDatabase {
private:
std::string m_filename;
std::vector<std::shared_ptr<CharacterData>> m_vpCharacters;
public:
explicit CharacterDatabase( const std::string& filename );
// ~CharacterDatabase(); // Default Okay
void displayByOption( unsigned option = 0 );
private:
CharacterDatabase( const CharacterDatabase& c ); // Not Implemented
CharacterDatabase& operator=( const CharacterDatabase& c ); // Not Implemented
void parseFile();
void display() const;
static bool sortByName( const std::shared_ptr<CharacterData>& d1, const std::shared_ptr<CharacterData>& d2);
static bool sortByHealth( const std::shared_ptr<CharacterData>& d1, const std::shared_ptr<CharacterData>& d2);
static bool sortByExperience(const std::shared_ptr<CharacterData>& d1, const std::shared_ptr<CharacterData>& d2);
}; // CharacterDataase
#endif // CHARACTER_DATABASE_H
CharacterDatabase.cpp
#include "stdafx.h"
#include "CharacterDatabase.h"
#include "CharacterData.h"
#include "Utility.h"
// ----------------------------------------------------------------------------
// CharacterDatabase()
CharacterDatabase::CharacterDatabase( const std::string& filename ) :
m_filename( filename ) {
parseFile();
} // CharacterDatabase
// ----------------------------------------------------------------------------
// parseFile()
void CharacterDatabase::parseFile() {
using namespace util;
if ( m_filename.empty() ) {
std::cout << "Missing or invalid filename." << std::endl;
return;
}
std::string line;
std::vector<std::string> results;
std::ifstream in;
// Try To Open File For Reading
in.open( m_filename.c_str(), std::ios_base::in );
if ( !in.is_open() ) {
std::cout << "Can not open file(" << m_filename << ") for reading.";
return;
}
// Read Line By Line And Store Contents Into String & Parse Each Line One At A Time.
while ( !in.eof() ) {
std::getline( in, line );
results = Utility::splitString( line, " " );
// On Each Pass We Want To Construct A CharacterData Object & Save It Into Our Container
m_vpCharacters.push_back( std::make_shared<CharacterData>( results[0], Utility::convertToFloat( results[1] ), Utility::convertToUnsigned( results[2] ) ) );
}
// Close File Pointer
in.close();
} // parseFile
// ----------------------------------------------------------------------------
// display()
void CharacterDatabase::display() const {
for (unsigned u = 0; u < m_vpCharacters.size(); u++) {
std::cout << m_vpCharacters[u]->getName() << "\t"
<< m_vpCharacters[u]->getHealth() << "\t"
<< m_vpCharacters[u]->getExperience() << std::endl;
}
std::cout << std::endl;
} // display
// ----------------------------------------------------------------------------
// displayByOption() Default 0 = Order In Which File Is Read In,
// 1 = Sorted By Name, 2 = Sorted By Health, 3 = Sorted By Experience
void CharacterDatabase::displayByOption( unsigned option ) {
switch ( option ) {
case 1: { // Sorted By Name
std::sort( m_vpCharacters.begin(), m_vpCharacters.end(), sortByName );
display();
break;
}
case 2: { // Sorted By Health
std::sort( m_vpCharacters.begin(), m_vpCharacters.end(), sortByHealth );
display();
break;
}
case 3: { // Sorted By Experience
std::sort( m_vpCharacters.begin(), m_vpCharacters.end(), sortByExperience );
display();
break;
}
default: { // Unsorted - Order Read In By File
display();
}
}
} // displayByOption
// ----------------------------------------------------------------------------
// sortByName()
bool CharacterDatabase::sortByName( const std::shared_ptr<CharacterData>& d1, const std::shared_ptr<CharacterData>& d2 ) {
return d1->getName() < d2->getName();
} // sortByName
// ----------------------------------------------------------------------------
// sortByHealth()
bool CharacterDatabase::sortByHealth( const std::shared_ptr<CharacterData>& d1, const std::shared_ptr<CharacterData>& d2 ) {
return d1->getHealth() < d2->getHealth();
} // sortByHealth
// ----------------------------------------------------------------------------
// sortByExperience()
bool CharacterDatabase::sortByExperience( const std::shared_ptr<CharacterData>& d1, const std::shared_ptr<CharacterData>& d2) {
return d1->getExperience() < d2->getExperience();
} // sortByExperience
characterData.txt
Alice 23.4 3210
Xander 45.3 1110
Bernard 12.9 2024
Yanni 23.7 1098
Craw 50.5 980
Zack 11.9 1024
main.cpp
#include "stdafx.h"
#include "Utility.h"
#include "CharacterDatabase.h"
int main() {
using namespace util;
CharacterDatabase cd( "characterData.txt" );
cd.displayByOption();
cd.displayByOption( 1 );
cd.displayByOption( 2 );
cd.displayByOption( 3 );
Utility::pressAnyKeyToQuit();
return RETURN_OK;
} // main
Just make sure that you are calling the file from the correct path, also when using the Utility::splitString() method make sure the second parameter or the delimiter matches what you have in your stored file. The splitString() method will divide the string from each line of the file every time it sees that character. If you happen to have multiple names such as a first & last name that you want stored to a single string then a little more care needs to be taken.
for sorting on the basis of any col you can use sort() in algorithm header with your own compare function.
Define your compare function like this:
on the basis of Health:
bool MyCompHealth(struct charData a,struct charData b)
{
return (a.charHealth>b.charHealth);
}
on the basis of Exp:
bool MyCompExp(struct charData a,struct charData b)
{
return (a.charExp > b.charExp);
}
on the basis of Name:
bool MyCompName(struct charData a,struct charData b)
{
int r = a.charName.compare(b.charName);
return (r > 0);
}
code:
#include<algorithm>
#include<iostream>
#include<fstream>
using namespace std;
struct charData
{
string charName;
float charHealth;
int charExp;
};
bool MyCompHealth(struct charData a,struct charData b)
{
return (a.charHealth<b.charHealth);
}
//on the basis of Exp:
bool MyCompExp(struct charData a,struct charData b)
{
return (a.charExp < b.charExp);
}
//on the basis of Name:
bool MyCompName(struct charData a,struct charData b)
{
int r = a.charName.compare(b.charName);
return !(r > 0);
}
int main() {
const int NUM_COLS = 3;
int NUM_ROWS = 6;
int charNumber = 0;
int userInput;
int loop = 0;
int i,j;
string line;
ifstream myIn; // Declare read file stream
myIn.open("party.dat",ios::in); // Open file
struct charData charArray[NUM_ROWS];
while( !myIn.eof() ) //taking input
{
for ( i = 0; i < NUM_ROWS ; i++)
{
myIn >> charArray[i].charName;
myIn >> charArray[i].charHealth;
myIn >> charArray[i].charExp;
}
}
cout<<"How you want to sort?(1:health 2:Exp 3:Name)\n";
cin>>userInput; //input from user how he wants to sort
if(userInput==1)
{
//sorting on the basis of health
sort(charArray,charArray+NUM_ROWS,MyCompHealth);
}
else if(userInput==1)
{
//sorting on the basis of Experience
sort(charArray,charArray+NUM_ROWS,MyCompExp);
}
else
{
//sorting on the basis of Name
sort(charArray,charArray+NUM_ROWS,MyCompName);
}
//display result
for ( i = 0; i < NUM_ROWS ; i++)
{
cout<<charArray[i].charName<<" ";
cout<<charArray[i].charHealth<<" ";
cout<<charArray[i].charExp<<endl;
}
return 0;
}
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);
}
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'm using BOOST for a graph mining problem, but when I compile it I got this error:
cc1plus: out of memory allocating 1677721600 bytes after a total of
6270976 bytes
How can I solve it? and how can I improve this code to be faster and avoid memory problems?
Here is the 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 <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;
//=================callback used fro subgraph_iso=================================================================
struct my_callback {
template <typename CorrespondenceMap1To2, typename CorrespondenceMap2To1>
bool operator()(CorrespondenceMap1To2 f, CorrespondenceMap2To1 g) const {
return false;
}
};
//==========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) {
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) {
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;
}
//============test if the graph connectivity========================================================
bool graphconnexe(Graph const& g) {
return num_edges(g) >= num_vertices(g) - 1;
}
//====================print the graph information========================================================
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;
}
}
//=========================================================
/*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;
}
}*/
//=================test if the given vertice exist in the graph=========================
bool verticeexist(Graph const& g, int const& vId, int const& 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;
}
//=============test if the given edge exist in the graph===========================
bool edgeexist(Graph const& g, int const& fromid, int const& toid, unsigned const& 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);
}
// =============test if thoses vertices are neighbours============================
bool verticesareneighbours(Graph const& g, int const& a, int const& 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);
}
//=============test if those edges are neighbours=============================
template <typename Graph, typename E = typename boost::graph_traits<Graph>::edge_descriptor>
bool edgesareneighbours(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;
}
//===============if the graph is empty add the edge with vertices===========================
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);
}
}
//==============================M A I N P R O G R A M =======================================
int main() {
clock_t start = std::clock();
size_t length;
std::vector<Graph> dataG = creategraphs(splitstringtolines(readfromfile("testgUe.txt", length)));
typedef std::pair<edge_iter, edge_iter> edge_pair;
if (!dataG.empty()) {
cout<<"graphconnexe?"<<graphconnexe(dataG[0])<<endl;
cout<<"verticeexist?"<<verticeexist(dataG[0],1,4);
cout<<"verticeexist?"<<verticeexist(dataG[0],4,2);
cout<<"verticesareneighbours?"<<verticesareneighbours(dataG[0],1,4)<<endl;
cout<<"verticesareneighbours?"<<verticesareneighbours(dataG[0],4,2)<<endl;
cout<<"edgeexist?"<<edgeexist(dataG[0],1,4,16)<<endl;
cout<<"edgeexist?"<<edgeexist(dataG[0],1,4,12)<<endl;
edge_pair ep = edges(dataG[0]);
if (size(ep) >= 2) {
Graph::edge_descriptor e1 = *ep.first++;
Graph::edge_descriptor e2 = *ep.first++;
cout << "edgesareneighbours?" << edgesareneighbours(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.
}
Here's an estimation of the lowerbound on amount of memory required live on Coliru:
16 megabytes:
g++: internal compiler error: Killed (program cc1plus)
libbacktrace could not find executable to open
Please submit a full bug report,
with preprocessed source if appropriate.
See <http://gcc.gnu.org/bugs.html> for instructions.
32 megabytes:
/usr/local/libexec/gcc/x86_64-unknown-linux-gnu/4.9.2/cc1plus: error while loading shared libraries: libc.so.6: failed to map segment from shared object: Cannot allocate memory
64 megabytes:
virtual memory exhausted: Cannot allocate memory
128 megabytes:
virtual memory exhausted: Cannot allocate memory
256 megabytes:
virtual memory exhausted: Cannot allocate memory
512 megabytes:
graphconnexe?1
verticeexist?0verticeexist?0verticesareneighbours?0
verticesareneighbours?0
edgeexist?0
edgeexist?0
edgesareneighbours?1
FILE Contains 1 graphs.
TIME: 0s
It looks like 512 megabytes should not be a problem. Fix your compiler setup
computer with enough resources
reasonably up-to-date compiler
check the flags (try more and less optimization, debug information etc.)
On my system, gcc 4.9 with -std=c++11 -Wall -pedantic -g -O0 -m32 works starting from 32 megabytes:
$ bash -c '{ ulimit -v $((1024*32)); make -Bsn; }' /usr/lib/gcc-snapshot/bin/g++ -std=c++11 -Wall -pedantic -g -O0 -m32 -isystem /home/sehe/custom/boost -march=native test.cpp -o test
I want use Boost.Spirit.Lex to lex a binary file; for this purpose I wrote the following program (here is an extract):
#include <boost/spirit/include/lex_lexertl.hpp>
#include <boost/spirit/include/support_multi_pass.hpp>
#include <boost/bind.hpp>
#include <boost/ref.hpp>
#include <fstream>
#include <iterator>
#include <string>
namespace spirit = boost::spirit;
namespace lex = spirit::lex;
#define X 1
#define Y 2
#define Z 3
template<typename L>
class word_count_tokens : public lex::lexer<L>
{
public:
word_count_tokens () {
this->self.add
("[^ \t\n]+", X)
("\n", Y)
(".", Z);
}
};
class counter
{
public:
typedef bool result_type;
template<typename T>
bool operator () (const T &t, size_t &c, size_t &w, size_t &l) const {
switch (t.id ()) {
case X:
++w; c += t.value ().size ();
break;
case Y:
++l; ++c;
break;
case Z:
++c;
break;
}
return true;
}
};
int main (int argc, char **argv)
{
std::ifstream ifs (argv[1], std::ios::in | std::ios::binary);
auto first = spirit::make_default_multi_pass (std::istream_iterator<char> (ifs));
auto last = spirit::make_default_multi_pass (std::istream_iterator<char> ());
size_t w, c, l;
word_count_tokens<lex::lexertl::lexer<>> word_count_functor;
w = c = l = 0;
bool r = lex::tokenize (first, last, word_count_functor, boost::bind (counter (), _1, boost::ref (c), boost::ref (w), boost::ref (l)));
ifs.close ();
if (r) {
std::cout << l << ", " << w << ", " << c << std::endl;
}
return 0;
}
The build returns the following error:
lexer.hpp:390:46: error: non-const lvalue reference to type 'const char *' cannot bind to a value of unrelated type
Now, the error is due to definition of concrete lexer, lex::lexer<>; in fact its first parameter is defaulted to const char *. I obtain the same error also if I use spirit::istream_iterator or spirit::make_default_multi_pass (.....).
But if I specify the correct template parameters of lex::lexer<> I obtain a plethora of errors!
Solutions?
Update
I have putted all source file; it's the word_counter site's example.
Okay, since the question was changed, here's a new answer, addressing some points with the complete code sample.
Firstly, you need to use a custom token type. I.e.
word_count_tokens<lex::lexertl::lexer<lex::lexertl::token<boost::spirit::istream_iterator>>> word_count_functor;
// instead of:
// word_count_tokens<lex::lexertl::lexer<>> word_count_functor;
Obviously, it's customary to typedef lex::lexertl::token<boost::spirit::istream_iterator>
You need to use min_token_id instead of token IDs 1,2,3. Also, make it an enum for ease of maintenance:
enum token_ids {
X = lex::min_token_id + 1,
Y,
Z,
};
You can no longer just use .size() on the default token value() since the iterator range is not RandomAccessRange anymore. Instead, employ boost::distance() which is specialized for iterator_range:
++w; c += boost::distance(t.value()); // t.value ().size ();
Combining these fixes: Live On Coliru
#include <boost/spirit/include/lex_lexertl.hpp>
#include <boost/spirit/include/support_istream_iterator.hpp>
#include <boost/bind.hpp>
#include <fstream>
namespace spirit = boost::spirit;
namespace lex = spirit::lex;
enum token_ids {
X = lex::min_token_id + 1,
Y,
Z,
};
template<typename L>
class word_count_tokens : public lex::lexer<L>
{
public:
word_count_tokens () {
this->self.add
("[^ \t\n]+", X)
("\n" , Y)
("." , Z);
}
};
struct counter
{
typedef bool result_type;
template<typename T>
bool operator () (const T &t, size_t &c, size_t &w, size_t &l) const {
switch (t.id ()) {
case X:
++w; c += boost::distance(t.value()); // t.value ().size ();
break;
case Y:
++l; ++c;
break;
case Z:
++c;
break;
}
return true;
}
};
int main (int argc, char **argv)
{
std::ifstream ifs (argv[1], std::ios::in | std::ios::binary);
ifs >> std::noskipws;
boost::spirit::istream_iterator first(ifs), last;
word_count_tokens<lex::lexertl::lexer<lex::lexertl::token<boost::spirit::istream_iterator>>> word_count_functor;
size_t w = 0, c = 0, l = 0;
bool r = lex::tokenize (first, last, word_count_functor,
boost::bind (counter (), _1, boost::ref (c), boost::ref (w), boost::ref (l)));
ifs.close ();
if (r) {
std::cout << l << ", " << w << ", " << c << std::endl;
}
}
When run on itself, prints
65, 183, 1665
I think the real problem is not shown. You don't show first or last and I have a feeling you might have temporaries there.
Here's a sample I came up with to verify, perhaps you can see what it is you're doing ---wrong--- differently :)
Live on Coliru (memory mapped an byte-vector, via const char*)
And this alternative (using spirit::istream_iterator)
#include <boost/spirit/include/lex_lexertl.hpp>
#include <boost/spirit/include/qi.hpp>
#include <fstream>
#ifdef MEMORY_MAPPED
# include <boost/iostreams/device/mapped_file.hpp>
#endif
namespace /*anon*/
{
namespace qi =boost::spirit::qi;
namespace lex=boost::spirit::lex;
template <typename Lexer>
struct mylexer_t : lex::lexer<Lexer>
{
mylexer_t()
{
fileheader = "hello";
this->self = fileheader
| space [ lex::_pass = lex::pass_flags::pass_ignore ];
}
lex::token_def<lex::omit>
fileheader, space;
};
template <typename Iterator> struct my_grammar_t
: public qi::grammar<Iterator>
{
template <typename TokenDef>
my_grammar_t(TokenDef const& tok)
: my_grammar_t::base_type(header)
{
header = tok.fileheader;
BOOST_SPIRIT_DEBUG_NODE(header);
}
private:
qi::rule<Iterator> header;
};
}
namespace /* */ {
std::string safechar(char ch) {
switch (ch) {
case '\t': return "\\t"; break;
case '\0': return "\\0"; break;
case '\r': return "\\r"; break;
case '\n': return "\\n"; break;
}
return std::string(1, ch);
}
template <typename It>
std::string showtoken(const boost::iterator_range<It>& range)
{
std::ostringstream oss;
oss << '[';
std::transform(range.begin(), range.end(), std::ostream_iterator<std::string>(oss), safechar);
oss << ']';
return oss.str();
}
}
bool parsefile(const std::string& spec)
{
#ifdef MEMORY_MAPPED
typedef char const* It;
boost::iostreams::mapped_file mmap(spec.c_str(), boost::iostreams::mapped_file::readonly);
char const *first = mmap.const_data();
char const *last = first + mmap.size();
#else
typedef char const* It;
std::ifstream in(spec.c_str());
in.unsetf(std::ios::skipws);
std::string v(std::istreambuf_iterator<char>(in.rdbuf()), std::istreambuf_iterator<char>());
It first = &v[0];
It last = first+v.size();
#endif
typedef lex::lexertl::token<It /*, boost::mpl::vector<char, unsigned int, std::string> */> token_type;
typedef lex::lexertl::actor_lexer<token_type> lexer_type;
typedef mylexer_t<lexer_type>::iterator_type iterator_type;
try
{
static mylexer_t<lexer_type> mylexer;
static my_grammar_t<iterator_type> parser(mylexer);
auto iter = mylexer.begin(first, last);
auto end = mylexer.end();
bool r = qi::parse(iter, end, parser);
r = r && (iter == end);
if (!r)
std::cerr << spec << ": parsing failed at: \"" << std::string(first, last) << "\"\n";
return r;
}
catch (const qi::expectation_failure<iterator_type>& e)
{
std::cerr << "FIXME: expected " << e.what_ << ", got '";
for (auto it=e.first; it!=e.last; it++)
std::cerr << showtoken(it->value());
std::cerr << "'" << std::endl;
return false;
}
}
int main()
{
if (parsefile("input.bin"))
return 0;
return 1;
}
For the variant:
typedef boost::spirit::istream_iterator It;
std::ifstream in(spec.c_str());
in.unsetf(std::ios::skipws);
It first(in), last;