boost graph copy a filtered_graph - c++

My actual intention is to use mcgregor_common_subgraphs to find some induced partial subgraphs. But it takes too long to compare small graphs. So instead of comparing the entire graphs I want to filter out a subset of comparable vertices and edges. Then find subgraphs between them.
So I use filtered_graph with vertex and edge predicates for both of these graphs. And pass the filtered graph to mcgregor_common_subgraphs. But it complains
error: use of deleted function ‘boost::iterators::filter_iterator<bya::util::isomorphism::directed_graph::vertex_filter_predicate, boost::range_detail::integer_iterator<long unsigned int> >& boost::iterators::filter_iterator<bya::util::isomorphism::directed_graph::vertex_filter_predicate, boost::range_detail::integer_iterator<long unsigned int> >::operator=(const boost::iterators::filter_iterator<bya::util::isomorphism::directed_graph::vertex_filter_predicate, boost::range_detail::integer_iterator<long unsigned int> >&)’
So I planned to copy the filtered graph into a new graph with copy_graph. But it complains that there is no default constructor for the vertex predicate vertex_filter_predicate.
error: no matching function for call to ‘bya::util::isomorphism::directed_graph::vertex_filter_predicate::vertex_filter_predicate()’
However my vertex and edge predicate takes a const reference to the original graph. So I cannot add an empty default constructor. I have searched in boost documentation, but didn't find any example of copying a filtered_graph. What is the solution ? Also why would copy_graph require the predicates to copy ?
struct directed_graph{
typedef boost::adjacency_list<boost::setS, boost::vecS, boost::bidirectionalS, vertex_data, edge_data> graph_type;
graph_type _graph;
// ...
};
I have a directed graph struct inside which I have the predicates and equivalance comparators. Both small and large are instances of directed_graph.
directed_graph::edge_filter_predicate edge_filter_small (small._graph, allowed_vertex_ids), edge_filter_large (large._graph, allowed_vertex_ids);
directed_graph::vertex_filter_predicate vertex_filter_small(small._graph, allowed_vertex_ids), vertex_filter_large(large._graph, allowed_vertex_ids);
boost::filtered_graph<directed_graph::graph_type, directed_graph::edge_filter_predicate, directed_graph::vertex_filter_predicate> filtered_small_view(small._graph, edge_filter_small, vertex_filter_small);
boost::filtered_graph<directed_graph::graph_type, directed_graph::edge_filter_predicate, directed_graph::vertex_filter_predicate> filtered_large_view(large._graph, edge_filter_large, vertex_filter_large);
directed_graph::graph_type filtered_small;
boost::copy_graph(filtered_small_view, filtered_small);

Related

Boost graph: speeding up add_edge

I have a boost graph application where I need to call the function add_edge( ) [documentation available here].
Profiling this application with KCachegrind reveals the following breakup of time spent:
As can be seen, the add_edge function call takes up roughly 21% of the time of the parent caller. Out of this 21%, 14.49% is simply some std::vector's reallocation.
The suggested way to prevent such vector reallocations seems to be to upfront reserve some amount of space. See for e.g., thread: How to prevent memory reallocation using std::vector
What is the equivalent way to do this reservation of some sufficient amount of space in boost graph?
The underlying graph object over which this repeated calls to add_edge are made is thus:
typedef adjacency_list<
vecS, vecS, directedS,
property<
vertex_name_t, std::string,
property<vertex_index_t, int,
property<vertex_color_t, boost::default_color_type,
property<vertex_distance_t, double,
property<vertex_predecessor_t, Traits::edge_descriptor>
> > > >,
property<
edge_index_t, int,
property<edge_capacity_t, double,
property<edge_weight_t, double,
property<edge_residual_capacity_t, double,
property<edge_reverse_t, Traits::edge_descriptor>
> > > > >
Graph;
Edited to add: Similar questions here and here.
Unfortunately for me, g.m_edges does NOT have function reserve.
Edited to add link to a minimal example (that is difficult to get to work fully) but compiles fine except for an undefined external reference that is not the main issue.
Unfortunately for me, g.m_edges does NOT have function reserve
But m_vertices does.
#include <boost/graph/adjacency_list.hpp>
int main() {
boost::adjacency_list<> g;
g.m_vertices.reserve(1024);
}
Also, since you're using vecS you could almost equivalently just construct with a pre-allocated number of vertices:
boost::adjacency_list<> g(1024);
The difference is, of course, that this doesn't just reserve space for, but resizes the graph to contain 1024 vertices.

How Can I Know Which Boost Graph Properties are Available in a Template Adjacency List?

Consider the following two adjacency lists:
#include <boost/graph/adjacency_list.hpp>
using Graph_1 = typename boost::adjacency_list<boost::vecS,
boost::vecS,
boost::directedS,
boost::no_property,
boost::property<boost::edge_weight_t, double> >;
Graph_1 graph_1(0);
struct VertexBundle { int some_int; };
struct EdgeBundle { double weight; };
struct GraphBundle { std::string name; };
using Graph_2 = typename boost::adjacency_list<boost::listS,
boost::listS,
boost::undirectedS,
VertexBundle,
boost::property<boost::edge_index_t, double, EdgeBundle>,
GraphBundle>;
Graph_2 graph_2(0);
They differ in their containers, directed category, and the properties defined for vertex, edge, and graph.
Now, for example with boost::detail::is_directed( boost::graph_traits<Graph>::directed_category ) I hold a boolean whether the graph of type Graph is directed or not, as taken from this SO question.
But how can I read out other information about the Graph Type's properties, especially which internal/bundled properties the graph has defined?
I found this boost docs page on graph_traits, but I'm not quite getting the hang of it. To beginners, the boost graph docs are a bit hard to read...
I'm thankful about any hints!
I already showed most of this here.
However I do notice that I made a mistake: I specialized boost::graph_property<Graph, Tag> where it should have been boost::property_map<Graph, Tag>. See https://www.boost.org/doc/libs/1_64_0/libs/graph/doc/property_map.html
You can either SFINAE on that or the result of get(property_tag_t{}, graph).
It looks like property_map might not even be very sfinae friendly - perhaps it hard-fails on eager instantiation of details. Mmm. That would mean you "can't" - you'll just have to always take parameters for any optional property-maps and default them to the library implementation. That way, if people fail to provide one when they should, it will croak with a hard compiler error
I'm happy to be proven wrong here, but I fear that BGL is showing its age here. I'm not sure whether c++20 std::detected<> has anything new/better here. Intuitively, I think, no, because it would require a core language change surrounding the extent of Sfinae.

Making an array of pairs of vectors

I'm trying to make an array of pairs of vectors, and in the vectors is another pair of int and float. Here is the code to help explain: pair<vector<pair<int,float> >, vector<float> >[numNodes];
At first I just had an array of a vector of pairs, but now that I changed it to an array of pairs I'm being thrown errors. I think the errors have to do with the placement of make_pair but I'm not sure.
Here is my code, but first, I little more information on what exactly I'm trying to do with the code. I'm working on a school assignment where the goal is to read in a three files of a graph and store it as an adjacency matrix and adjacency list. Right now I'm working on the list. One file has just the connections, another has the weights of the connections, and the last file has the position values of each node. Then I will search the graphs with different search algorithms. The array of vectors was the adjacency list and all the other data types involved in the pair<vector<pair<int,float> >, vector<float> >[numNodes]; were an attempt to store these variables in the list. I know another way of doing this would be to have a Node object with member variables where I can save the nodeID and position values, but I don't know exactly how this would work in terms of adding it into the list. Also would there be advantages to doing this rather than having everything stored in the list?
class AdjacencyList{
public:
pair<vector<pair<int,float> >, vector<float> > *adjList;
int numNodes;
AdjacencyList(int numNodes){//constructor
this->numNodes = numNodes;
adjList = new pair<vector<pair<int,float> >, vector<float> >[numNodes];
}
void addEdge(int sourceNode, int destNode, float weight, vector<float> posVals){
make_pair(adjList[sourceNode].push_back(make_pair(destNode, weight)), posVals);
}
}
And here is the error I'm being thrown:
main.cpp:71:39: error: no member named 'push_back' in
'std::__1::pair<std::__1::vector<std::__1::pair<int, float>,
std::__1::allocator<std::__1::pair<int, float> > >,
std::__1::vector<float, std::__1::allocator<float> > >'
make_pair(adjList[sourceNode].push_back(make_pair(destNode, weig...
Another Error I'm getting after changing the array of vectors to an array of pairs is this:
no member named 'size' in
'std::__1::pair<std::__1::vector<std::__1::pair<int, float>,
std::__1::allocator<std::__1::pair<int, float> > >,
std::__1::vector<float, std::__1::allocator<float> > >'
return adjList->size();
This size function was working before the change, which makes me think these errors are happening because its recognizing it as a pair now instead of an array. Any ideas on how to fix this?
I have no idea what vector of pairs of vectors of pairs of ints and floats and vectors of floats could possibly in any possible way represent, but anyway you could just assign to the pairs of vectors you want to assign to:
#include <vector>
class AdjacencyList{
public:
std::vector<
std::pair<
std::vector<std::pair<int,float>>,
std::vector<float>
>
> adjList;
int numNodes;
AdjacencyList(int numNodes) :
numNodes(numNodes),
// construct the vector with numNodes default-constructred elements
adjList(numNodes) {
}
void addEdge(int sourceNode, int destNode, float weight, std::vector<float> posVals){
// prefer at() instead of [] for error checking
adjList.at(sourceNode) = std::make_pair(
std::vector<std::pair<int, float>>{
// vector of pairs?? anyway:
std::make_pair(
destNode, weight
)
},
posVals
);
}
};
Do not use raw pointers - use std::vector for managing dynamic array. Your code leaks memory allocated by new.
In the first error thrown, the compiler is complaining about a missing method push_back being called. If you look at it, this makes sense because you are trying to call push_back from a pair variable (which does not have implemented any push_back method). And a similar thing goes with the second error: size() is a valid method for the vector class, but here you are calling it from a pointer pointing to an array (check this question for more info).
Instead of an array of pairs, you could use a vector of pairs, or even a set of pairs:
class AdjacencyList{
public:
vector<pair<vector<pair<int,float> >, vector<float> > > adjList;
int numNodes;
AdjacencyList(int numNodes){//constructor
this->numNodes = numNodes;
// no need to initialize the vector
//adjList = new pair<vector<pair<int,float> >, vector<float> >[numNodes];
}
void addEdge(int sourceNode, int destNode, float weight, vector<float> posVals){
// add the new pair <int, float> to the existent vector for this source node
adjList[sourceNode].first.push_back(make_pair(destNode, weight));
// define second value of the outer pair as the parameter variable posVals?
adjList[sourceNode].second = posVals;
// or you wanted to do this? I don't think so :S
make_pair(adjList[sourceNode].first, posVals);
}
}
You could do the same using an outer set instead of vector, and then you would need to change the push_back(...) for insert(...), so that you obtain the benefits of sets of pairs as well.
Actually, if you need to do it using outer arrays, then your code would be fine but changing your AddEdge function to the one proposed above.
I don't really know which is the desired performance of the code, but if you provide more information about it I might be able to help a bit more.
I think you have some inconsistencies in the type declared and the type being added.
You have declared an array (now does not matter whether it is an array, vector, or set) of pairs of vectors. Whereas on your addEdge function you are creating a pair of None (push_back returns None) and vector. The push_back on its side is adding the pair <int, float> of the first vector of the outer pair to you differently variable defined above.

Compute the minimum spanning tree using Prim's algorithm : how to make it simple?

The issue here is mostly implementation. I'd like to compute a MST using Prim's algorithm.
Here's the code :
vector<edge_desc> mst;
auto root = boost::vertex(h, Gs[i]);
boost::prim_minimum_spanning_tree(Gs[i], root);
Where h is an integer, Gs is a vector of weight graphs, defined like so :
typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS,
boost::no_property, boost::property<boost::edge_weight_t, int>>
weighted_graph;
I have this error :
no instance of overloaded function "boost::prim_minimum_spanning_tree" matches the argument list -- argument types are: (weighted_graph, std::size_t, std::back_insert_iterator<std::vector<edge_desc, std::allocator<edge_desc>>>)
According to the documentation : https://www.boost.org/doc/libs/1_55_0/libs/graph/doc/prim_minimum_spanning_tree.html
I need to give all of these named parameters?
How does C++ know which parameter is which?
My goal is to construct a MST starting from root on Gs[i] and store the edge descriptors inside mst.
How do I proceed?
"I need to give all of these named parameters?" - Yes.
"How does C++ know which parameter is which?" - By the order in which they are provided.

When analyzing boost::graph, does one operate on vertex and edge descriptor or their iterators?

When working with the BOOST graph library, I have a graph instance fully initialized -- the structure is now static. I need to do some processing based on the graph.
I'm not clear if I should be working with the iterator types for vertices and edges, or the vertex and edge types themselves?
typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::bidirectionalS, VertexProperty, EdgeProperty > GraphType;
typedef typename boost::graph_traits< GraphType >::vertex_descriptor VertexType;
typedef typename boost::graph_traits<GraphType>::vertex_iterator VertexIterator;
typedef typename boost::graph_traits< GraphType >::edge_descriptor EdgeType;
typedef typename boost::graph_traits<GraphType>::out_edge_iterator EdgeIterator;
I have an algorithm where I need to check if two edges are "the same". (in the strongest sense. Suppose the graph has two parallel edges connecting E1(S1,T2) & E2(S1,T2). An edge can only be "the same" with at most one of them.
What's the difference between (edge_descriptor == edge_descriptor) and (edge_iterator == edge_iterator)? Same question for vertices.
Most of the graph functions return iterators rather than the edge/vertex types themselves.
I also have the need to store a set of edges. Not sure whether I should be storing EdgeType or EdgeIterator?
std::vector<EdgeType> processedEdges;
std::vector<EdgeIterator> processedEdges;
vit = std::find( processedEdges.begin(), processedEdges.end(), anotherEdgeRef )
if ( vit == processedEdges.end() )
doSomethingBasedOnEdgeProperty(*vit);
Reference:
http://www.boost.org/doc/libs/1_64_0/libs/graph/doc/adjacency_list.html
You should be storing descriptors, not iterators.
Iterators relate to a logical range, not the graph. Iterators may not be valid between different ranges of the same graph:
auto range1 = out_edges(vertex1, g);
auto range2 = out_edges(vertex2, g);
assert(range1.first != range2.first); // unspecified or undefined
Instead, descriptors are graph-wide. Depending on graph model, descriptors may be more stable: if an operation invalidates iterators, it doesn't necessarily invalidate the descriptors corresponding to the same graph elements.
In other words, this makes descriptors more usable as vertex or edge "ID" - or, as Boost Graph would call it, vertex_index or edge_index properties.
I think that is very close to your question.
One caveat: even so, descriptors may not always be stable!
E.g.:
adjacency_list<vecS, vecS, directedS>
leads to vertex descriptors that are stable on append, but not on
deletion.
adjacency_list<setS, listS, directedS>
on the other hand, leads to vertex descriptors that are stable on both
insertion and removal.
See documentation section "Iterator and Descriptor
Stability/Invalidation"
If you need a completely stable identity for your graph elements, you may need to add one as a (bundled) property.