source: src/graph/graph_filtering.cc @ 60acdc

Revision 60acdc, 10.3 KB checked in by Tiago de Paula Peixoto <tiago@…>, 3 years ago (diff)
Include Graph.reindex_edges() and Graph.max_edge_index These functions/properties provide more information and control about edge indexing, which might be useful.
  • Property mode set to 100644
Line 
1// graph-tool -- a general graph modification and manipulation thingy
2//
3// Copyright (C) 2007-2010 Tiago de Paula Peixoto <tiago@forked.de>
4//
5// This program is free software; you can redistribute it and/or
6// modify it under the terms of the GNU General Public License
7// as published by the Free Software Foundation; either version 3
8// of the License, or (at your option) any later version.
9//
10// This program is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18#include "graph_filtering.hh"
19#include <boost/python/type_id.hpp>
20
21using namespace graph_tool;
22using namespace graph_tool::detail;
23using namespace boost;
24
25bool graph_tool::graph_filtering_enabled()
26{
27#ifndef NO_GRAPH_FILTERING
28    return true;
29#else
30    return false;
31#endif
32}
33
34// Whenever no implementation is called, the following exception is thrown
35graph_tool::ActionNotFound::ActionNotFound(const boost::any& graph_view,
36                                           const type_info& action,
37                                           const vector<const type_info*>& args)
38    : GraphException(""), _graph_view(graph_view),
39      _action(action), _args(args) {}
40
41const char * graph_tool::ActionNotFound::what () const throw ()
42{
43    using python::detail::gcc_demangle;
44
45    string error =
46        "No static implementation was found for the desired routine. "
47        "This is a graph_tool bug. :-( Please follow but report "
48        "instructions at " PACKAGE_BUGREPORT ". What follows is debug "
49        "information.\n\n";
50
51    error += "Graph view: " + string(gcc_demangle(_graph_view.type().name()))
52        + "\n\n";
53
54    error += "Action: " + string(gcc_demangle(_action.name())) + "\n\n";
55    for (size_t i = 0; i < _args.size(); ++i)
56    {
57        error += "Arg " + lexical_cast<string>(i+1) + ": " +
58            string(gcc_demangle(_args[i]->name())) + "\n\n";
59    }
60    return error.c_str();
61}
62
63// this function retrieves a graph view stored in graph_views, or stores one if
64// non-existent
65template <class Graph>
66typename remove_const<Graph>::type&
67retrieve_graph(vector<boost::any>& graph_views, Graph& init)
68{
69    typedef typename remove_const<Graph>::type g_t;
70    size_t index = mpl::find<all_graph_views,g_t>::type::pos::value;
71    if (index >= graph_views.size())
72        graph_views.resize(index+1);
73    boost::any gview = graph_views[index];
74    shared_ptr<g_t>* gptr = any_cast<shared_ptr<g_t> >(&gview);
75    if (gptr == 0)
76    {
77        shared_ptr<g_t> new_g(new g_t(init));
78        gptr = &new_g;
79        gview = new_g;
80        graph_views[index] = gview;
81    }
82    return **gptr;
83}
84
85
86// this will check whether a graph is reversed and return the proper view
87// encapsulated
88template <class Graph>
89boost::any check_reverse(const Graph &g, bool reverse,
90                         vector<boost::any>& graph_views)
91{
92    if (reverse)
93    {
94        typedef typename mpl::if_<is_const<Graph>,
95                                  const reverse_graph
96                                      <typename remove_const<Graph>::type>,
97                                  reverse_graph<Graph> >::type
98            reverse_graph_t;
99
100        reverse_graph_t rg(g);
101        return &retrieve_graph(graph_views, rg);
102    }
103
104    return boost::any(&const_cast<Graph&>(g));
105};
106
107// this will check whether a graph is directed and return the proper view
108// encapsulated
109template <class Graph>
110boost::any check_directed(const Graph &g, bool reverse, bool directed,
111                          vector<boost::any>& graph_views)
112{
113    if (directed)
114    {
115        return check_reverse(g, reverse, graph_views);
116    }
117
118    typedef UndirectedAdaptor<Graph> ug_t;
119    ug_t ug(g);
120    return &retrieve_graph(graph_views, ug);
121};
122
123// this will check whether a graph is filtered and return the proper view
124// encapsulated
125template <class Graph, class EdgeFilter, class VertexFilter>
126boost::any
127check_filtered(const Graph &g, const EdgeFilter& edge_filter,
128               const bool& e_invert, bool e_active, size_t max_eindex,
129               const VertexFilter& vertex_filter, const bool& v_invert,
130               bool v_active, vector<boost::any>& graph_views, bool reverse,
131               bool directed)
132{
133#ifndef NO_GRAPH_FILTERING
134    MaskFilter<EdgeFilter> e_filter(edge_filter, e_invert);
135    MaskFilter<VertexFilter> v_filter(vertex_filter, v_invert);
136
137    if (e_active)
138    {
139        if (max_eindex > 0)
140            edge_filter.reserve(max_eindex+1);
141        if (v_active)
142        {
143            if (num_vertices(g) > 0)
144                vertex_filter.reserve(num_vertices(g));
145            typedef filtered_graph<Graph, MaskFilter<EdgeFilter>,
146                                   MaskFilter<VertexFilter> > fg_t;
147            fg_t init(g, e_filter, v_filter);
148            fg_t& fg = retrieve_graph(graph_views, init);
149            fg.m_edge_pred = e_filter;
150            fg.m_vertex_pred = v_filter;
151            return check_directed(fg, reverse, directed, graph_views);
152        }
153        else
154        {
155            typedef filtered_graph<Graph, MaskFilter<EdgeFilter>,
156                                   keep_all> fg_t;
157            fg_t init(g, e_filter, keep_all());
158            fg_t& fg = retrieve_graph(graph_views, init);
159            fg.m_edge_pred = e_filter;
160            return check_directed(fg, reverse, directed, graph_views);
161        }
162    }
163    else
164    {
165        if (v_active)
166        {
167            if (num_vertices(g) > 0)
168                vertex_filter.reserve(num_vertices(g));
169            typedef filtered_graph<Graph, keep_all,
170                                   MaskFilter<VertexFilter> > fg_t;
171            fg_t init(g, keep_all(), v_filter);
172            fg_t& fg = retrieve_graph(graph_views, init);
173            fg.m_vertex_pred = v_filter;
174            return check_directed(fg, reverse, directed, graph_views);
175        }
176        else
177        {
178            return check_directed(g, reverse, directed, graph_views);
179        }
180    }
181#else
182    return check_directed(g, reverse, directed, graph_views);
183#endif
184}
185
186// gets the correct graph view at run time
187boost::any GraphInterface::GetGraphView() const
188{
189    // TODO: implement memoization
190
191    boost::any graph =
192        check_filtered(_mg, _edge_filter_map, _edge_filter_invert,
193                       _edge_filter_active, _max_edge_index, _vertex_filter_map,
194                       _vertex_filter_invert, _vertex_filter_active,
195                       const_cast<vector<boost::any>&>(_graph_views),
196                       _reversed, _directed);
197    return graph;
198}
199
200// these test whether or not the vertex and edge filters are active
201bool GraphInterface::IsVertexFilterActive() const
202{ return _vertex_filter_active; }
203
204bool GraphInterface::IsEdgeFilterActive() const
205{ return _edge_filter_active; }
206
207
208// this function will reindex all the edges, in the order in which they are
209// found
210void GraphInterface::ReIndexEdges()
211{
212    size_t index = 0;
213    graph_traits<multigraph_t>::edge_iterator e, e_end;
214    for (tie(e, e_end) = edges( _mg); e != e_end; ++e)
215        _edge_index[*e] = index++;
216    _max_edge_index =  (index > 0) ? index - 1 : 0;
217    _nedges = index;
218    _free_indexes.clear();
219}
220
221// this will definitively remove all the edges from the graph, which are being
222// currently filtered out. This will also disable the edge filter
223void GraphInterface::PurgeEdges()
224{
225    if (!IsEdgeFilterActive())
226        return;
227
228    MaskFilter<edge_filter_t> filter(_edge_filter_map, _edge_filter_invert);
229    graph_traits<multigraph_t>::vertex_iterator v, v_end;
230    graph_traits<multigraph_t>::out_edge_iterator e, e_end;
231    vector<graph_traits<multigraph_t>::edge_descriptor> deleted_edges;
232    for (tie(v, v_end) = vertices(_mg); v != v_end; ++v)
233    {
234        for (tie(e, e_end) = out_edges(*v, _mg); e != e_end; ++e)
235            if (!filter(*e))
236                deleted_edges.push_back(*e);
237        for (typeof(deleted_edges.begin()) iter = deleted_edges.begin();
238             iter != deleted_edges.end(); ++iter)
239            RemoveEdgeIndex(*iter);
240        deleted_edges.clear();
241    }
242}
243
244
245// this will definitively remove all the verticess from the graph, which are
246// being currently filtered out. This will also disable the vertex filter
247void GraphInterface::PurgeVertices()
248{
249    if (!IsVertexFilterActive())
250        return;
251
252    MaskFilter<vertex_filter_t> filter(_vertex_filter_map,
253                                       _vertex_filter_invert);
254    size_t N = num_vertices(_mg);
255    vector<bool> deleted(N, false);
256    for (size_t i = 0; i < N; ++i)
257        deleted[i] = !filter(vertex(i, _mg));
258
259    vector<graph_traits<multigraph_t>::edge_descriptor> edges;
260
261    //remove vertices
262    for (int i = N-1; i >= 0; --i)
263    {
264        if (deleted[i])
265        {
266            graph_traits<multigraph_t>::vertex_descriptor v = vertex(i, _mg);
267            graph_traits<multigraph_t>::out_edge_iterator e, e_end;
268            for(tie(e, e_end) = out_edges(v, _mg); e != e_end; ++e)
269                edges.push_back(*e);
270            graph_traits<multigraph_t>::in_edge_iterator ei, ei_end;
271            for(tie(ei, ei_end) = in_edges(v, _mg); ei != ei_end; ++ei)
272                edges.push_back(*ei);
273            for(size_t j = 0; j < edges.size(); ++j)
274                RemoveEdgeIndex(edges[j]);
275            clear_vertex(v, _mg);
276            remove_vertex(v, _mg);
277            edges.clear();
278        }
279    }
280}
281
282void GraphInterface::SetVertexFilterProperty(boost::any property, bool invert)
283{
284#ifdef NO_GRAPH_FILTERING
285    throw GraphException("graph filtering was not enabled at compile time");
286#endif
287
288    try
289    {
290        _vertex_filter_map =
291            any_cast<vertex_filter_t::checked_t>(property).get_unchecked();
292        _vertex_filter_invert = invert;
293        _vertex_filter_active = true;
294    }
295    catch(bad_any_cast&)
296    {
297        _vertex_filter_active = false;
298    }
299}
300
301void GraphInterface::SetEdgeFilterProperty(boost::any property, bool invert)
302{
303#ifdef NO_GRAPH_FILTERING
304    throw GraphException("graph filtering was not enabled at compile time");
305#endif
306
307    try
308    {
309        _edge_filter_map =
310            any_cast<edge_filter_t::checked_t>(property).get_unchecked();
311        _edge_filter_invert = invert;
312        _edge_filter_active = true;
313    }
314    catch(bad_any_cast&)
315    {
316        _edge_filter_active = false;
317    }
318}
319
Note: See TracBrowser for help on using the repository browser.