graph.cc 21.2 KB
Newer Older
Tiago Peixoto's avatar
Tiago Peixoto committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// graph-tool -- a general graph modification and manipulation thingy
//
// Copyright (C) 2006  Tiago de Paula Peixoto <tiago@forked.de>
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

#include <algorithm>
#include <tr1/unordered_set>
#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>
#include <boost/graph/graphviz.hpp>
#include <boost/graph/breadth_first_search.hpp>
#include <boost/graph/strong_components.hpp>
#include <boost/graph/connected_components.hpp>
#include <boost/graph/gursoy_atun_layout.hpp>
#include <boost/graph/fruchterman_reingold.hpp>
#include <boost/graph/random_layout.hpp>
#include <boost/random.hpp>
31
#include <boost/python/make_function.hpp>
Tiago Peixoto's avatar
Tiago Peixoto committed
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54

#include <unistd.h>    /* standard unix functions, like getpid()         */
#include <sys/types.h> /* various type definitions, like pid_t           */
#include <signal.h>    /* signal name macros, and the signal() prototype */

#include "graph.hh"
#include "histogram.hh"
#include "graph_filtering.hh"
#include "graph_selectors.hh"
#include "graph_properties.hh"

using namespace std;
using namespace boost;
using namespace boost::lambda;
using namespace graph_tool;


pair<GraphInterface::degree_t,string> graph_tool::get_degree_type(GraphInterface::deg_t degree)
{
    GraphInterface::degree_t deg;
    string name;
    try 
    {
55
        deg = boost::get<GraphInterface::degree_t>(degree);
Tiago Peixoto's avatar
Tiago Peixoto committed
56
57
58
    }
    catch (bad_get)
    {
59
60
        name = boost::get<std::string>(degree);
        deg = GraphInterface::SCALAR;
Tiago Peixoto's avatar
Tiago Peixoto committed
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
    }
    return make_pair(deg,name);
}


//==============================================================================
// GraphInterface()
//==============================================================================
GraphInterface::GraphInterface()
:_mg(), 
 _reversed(false),
 _directed(true),
 _vertex_index(get(vertex_index,_mg)),
 _edge_index(get(edge_index_t(),_mg)),
 _vertex_range(make_pair(numeric_limits<double>::min(), numeric_limits<double>::max())),
 _edge_range(make_pair(numeric_limits<double>::min(), numeric_limits<double>::max()))
{

}

//==============================================================================
// ~GraphInterface()
//==============================================================================
GraphInterface::~GraphInterface()
{
}

//==============================================================================
// SetVertexFilter()
//==============================================================================

92
93
void GraphInterface::SetVertexFilterProperty(string property)
{
94
#ifndef NO_RANGE_FILTERING
95
    _vertex_filter_property = property;
Tiago Peixoto's avatar
Tiago Peixoto committed
96
    
97
    if (property != "")
Tiago Peixoto's avatar
Tiago Peixoto committed
98
    {
99
100
101
102
103
        try 
        {
            dynamic_property_map& pmap = find_property_map(_properties, property, typeid(graph_traits<multigraph_t>::vertex_descriptor));

            if (get_static_property_map<vector_property_map<double,vertex_index_map_t> >(&pmap))
104
                _vertex_filter_map = get_static_property_map<vector_property_map<double,vertex_index_map_t> >(pmap);
105
            else if (get_static_property_map<HashedDescriptorMap<vertex_index_map_t,double> >(&pmap))
106
                _vertex_filter_map = get_static_property_map<HashedDescriptorMap<vertex_index_map_t,double> >(pmap);
107
            else if (get_static_property_map<vector_property_map<size_t,vertex_index_map_t> >(&pmap))
108
                _vertex_filter_map = get_static_property_map<vector_property_map<size_t,vertex_index_map_t> >(pmap);
109
            else if (get_static_property_map<HashedDescriptorMap<vertex_index_map_t,size_t> >(&pmap))
110
                _vertex_filter_map = get_static_property_map<HashedDescriptorMap<vertex_index_map_t,size_t> >(pmap);
111
            else if (get_static_property_map<vertex_index_map_t>(&pmap))
112
                _vertex_filter_map = get_static_property_map<vertex_index_map_t>(pmap);
113
            else 
114
                _vertex_filter_map = DynamicPropertyMapWrap<double, graph_traits<multigraph_t>::vertex_descriptor>(pmap);
115
116
117
118
119
        }
        catch (property_not_found) 
        {
            throw GraphException("property " + property + " not found");
        }
120
    }
121
#else
122
123
    if (property != "")
        throw GraphException("support for graph range filtering was not enabled during compilation.");
124
#endif
Tiago Peixoto's avatar
Tiago Peixoto committed
125
126
127
128
129
130
}

bool GraphInterface::IsVertexFilterActive() const { return _vertex_filter_property != "" || _vertex_python_filter != python::object(); }

void GraphInterface::SetEdgeFilterProperty(string property) 
{
131
#ifndef NO_RANGE_FILTERING
132
    _edge_filter_property = property;
Tiago Peixoto's avatar
Tiago Peixoto committed
133
    
134
    if (property != "")
Tiago Peixoto's avatar
Tiago Peixoto committed
135
    {
136
137
138
139
140
        try
        {
            dynamic_property_map& pmap = find_property_map(_properties, property, typeid(graph_traits<multigraph_t>::edge_descriptor));
            
            if (get_static_property_map<vector_property_map<double,edge_index_map_t> >(&pmap))
141
                _edge_filter_map = get_static_property_map<vector_property_map<double,edge_index_map_t> >(pmap);
142
            else if (get_static_property_map<HashedDescriptorMap<edge_index_map_t,double> >(&pmap))
143
                _edge_filter_map = get_static_property_map<HashedDescriptorMap<edge_index_map_t,double> >(pmap);
144
            else if (get_static_property_map<vector_property_map<size_t,edge_index_map_t> >(&pmap))
145
                _edge_filter_map = get_static_property_map<vector_property_map<size_t,edge_index_map_t> >(pmap);
146
            else if (get_static_property_map<HashedDescriptorMap<edge_index_map_t,size_t> >(&pmap))
147
                _edge_filter_map = get_static_property_map<HashedDescriptorMap<edge_index_map_t,size_t> >(pmap);
148
            else if (get_static_property_map<edge_index_map_t>(&pmap))
149
                _edge_filter_map = get_static_property_map<edge_index_map_t>(pmap);
150
            else 
151
                _edge_filter_map = DynamicPropertyMapWrap<double, graph_traits<multigraph_t>::edge_descriptor>(pmap);
152
153
154
155
156
        }
        catch (property_not_found) 
        {
            throw GraphException("property " + property + " not found");
        }
157
    }
158
159

#else
160
161
    if (property != "")
        throw GraphException("support for graph range filtering was not enabled during compilation.");
162
#endif
Tiago Peixoto's avatar
Tiago Peixoto committed
163
164
165
166
}

bool GraphInterface::IsEdgeFilterActive() const {return _edge_filter_property != "" || _edge_python_filter != python::object();}

167
168
void GraphInterface::SetVertexFilterRange(std::pair<double,double> allowed_range)
{
169
#ifndef NO_RANGE_FILTERING
170
171
    _vertex_range = allowed_range;
#else
172
    throw GraphException("support for graph range filtering was not enabled during compilation.");
173
174
175
176
177
178
#endif
}


void GraphInterface::SetGenericVertexFilter(boost::python::object filter) 
{
179
#ifndef NO_PYTHON_FILTERING
180
181
    _vertex_python_filter = filter;
#else
182
183
    if (filter != python::object())
        throw GraphException("support for graph python filtering was not enabled during compilation.");
184
185
186
187
188
#endif    
}

void GraphInterface::SetGenericEdgeFilter(boost::python::object filter) 
{ 
189
#ifndef NO_PYTHON_FILTERING
190
191
    _edge_python_filter = filter;
#else
192
193
    if (filter != python::object())
        throw GraphException("support for graph python filtering was not enabled during compilation.");
194
195
196
#endif    
}

Tiago Peixoto's avatar
Tiago Peixoto committed
197
198
199
200
201
202
203
204

//==============================================================================
// GetNumberOfVertices()
//==============================================================================
size_t GraphInterface::GetNumberOfVertices() const
{
    size_t n = 0;
    if (IsVertexFilterActive())
205
        check_filter(*this,var(n)=bind<size_t>(HardNumVertices(),_1),reverse_check(),directed_check()); 
Tiago Peixoto's avatar
Tiago Peixoto committed
206
207
208
209
210
211
212
213
214
215
216
217
    else
        check_filter(*this,var(n)=bind<size_t>(SoftNumVertices(),_1),reverse_check(),directed_check());
    return n;
}

//==============================================================================
// GetNumberOfEdges()
//==============================================================================
size_t GraphInterface::GetNumberOfEdges() const
{
    size_t n = 0;
    if (IsEdgeFilterActive() || IsVertexFilterActive())
218
        check_filter(*this,var(n)=bind<size_t>(HardNumEdges(),_1),reverse_check(),directed_check()); 
Tiago Peixoto's avatar
Tiago Peixoto committed
219
220
221
222
223
224
    else
        check_filter(*this,var(n)=bind<size_t>(SoftNumEdges(),_1),reverse_check(),directed_check());
    return n;
}

//==============================================================================
225
226
// get_vertex_histogram
// generalized functor to obtain histogram of different types of "degrees"
Tiago Peixoto's avatar
Tiago Peixoto committed
227
228
//==============================================================================
template <class DegreeSelector>
229
struct get_vertex_histogram
Tiago Peixoto's avatar
Tiago Peixoto committed
230
{
231
    get_vertex_histogram(DegreeSelector& deg): _degree(deg) {}
Tiago Peixoto's avatar
Tiago Peixoto committed
232
    template <class Graph, class Hist>
233
    void operator()(const Graph& g, Hist& hist) const
Tiago Peixoto's avatar
Tiago Peixoto committed
234
    {
235
        typename graph_traits<Graph>::vertex_iterator v, v_begin, v_end;
Tiago Peixoto's avatar
Tiago Peixoto committed
236
237
238
239
240
241
242
        tie(v_begin, v_end) = vertices(g);
        for(v = v_begin; v != v_end; ++v)
            hist[_degree(*v,g)]++;
    }
    DegreeSelector& _degree;
};

243
struct choose_vertex_histogram
Tiago Peixoto's avatar
Tiago Peixoto committed
244
{
245
    choose_vertex_histogram(const GraphInterface& g, GraphInterface::deg_t deg, GraphInterface::hist_t& hist)
246
        : _g(g), _hist(hist) 
Tiago Peixoto's avatar
Tiago Peixoto committed
247
    {
248
        tie(_deg, _deg_name) = get_degree_type(deg);
Tiago Peixoto's avatar
Tiago Peixoto committed
249
250
251
252
    }
    template <class DegreeSelector>
    void operator()(DegreeSelector)
    {
253
254
255
256
257
        if (mpl::at<degree_selector_index,DegreeSelector>::type::value == _deg)
        {
            DegreeSelector selector(_deg_name, _g);
            check_filter(_g, bind<void>(get_vertex_histogram<DegreeSelector>(selector), _1, var(_hist)),reverse_check(),directed_check());
        }
Tiago Peixoto's avatar
Tiago Peixoto committed
258
259
260
261
262
263
264
265
    }
    const GraphInterface &_g;
    GraphInterface::hist_t &_hist;
    GraphInterface::degree_t _deg;
    string _deg_name;    
};

//==============================================================================
266
// GetVertexHistogram(deg_type)
Tiago Peixoto's avatar
Tiago Peixoto committed
267
//==============================================================================
268
GraphInterface::hist_t GraphInterface::GetVertexHistogram(GraphInterface::deg_t deg) const
Tiago Peixoto's avatar
Tiago Peixoto committed
269
270
271
272
{
    hist_t hist;
    try 
    {
273
        mpl::for_each<mpl::vector<in_degreeS, out_degreeS, total_degreeS, scalarS> >(choose_vertex_histogram(*this, deg, hist));
Tiago Peixoto's avatar
Tiago Peixoto committed
274
275
276
    }
    catch (dynamic_get_failure &e)
    {
277
        throw GraphException("error getting scalar property: " + string(e.what()));
Tiago Peixoto's avatar
Tiago Peixoto committed
278
279
280
281
282
    }

    return hist;
}

283
284
285
286
287
288
289
290
291
292
//==============================================================================
// get_edge_histogram
// generalized functor to obtain histogram of edge properties
//==============================================================================
struct get_edge_histogram
{
    get_edge_histogram(scalarS& prop): _prop(prop) {}
    template <class Graph, class Hist>
    void operator()(const Graph& g, Hist& hist) const
    {
293
        typename graph_traits<Graph>::edge_iterator e, e_begin, e_end;
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
        tie(e_begin, e_end) = edges(g);
        for(e = e_begin; e != e_end; ++e)
            hist[_prop(*e,g)]++;
    }
    scalarS& _prop;
};

//==============================================================================
// GetEdgeHistogram(property)
//==============================================================================
GraphInterface::hist_t GraphInterface::GetEdgeHistogram(string property) const
{
    hist_t hist;
    try 
    {
309
310
        scalarS prop(property, *this);
        check_filter(*this, bind<void>(get_edge_histogram(prop), _1, var(hist)),reverse_check(),directed_check());
311
312
313
    }
    catch (dynamic_get_failure &e)
    {
314
        throw GraphException("error getting scalar property: " + string(e.what()));
315
316
317
318
319
320
    }


    return hist;
}

Tiago Peixoto's avatar
Tiago Peixoto committed
321
//==============================================================================
322
// LabelComponents(property)
Tiago Peixoto's avatar
Tiago Peixoto committed
323
324
//==============================================================================

325
struct label_components
Tiago Peixoto's avatar
Tiago Peixoto committed
326
{
327
328
329
    template <class Graph, class CompMap>
    void operator()(const Graph &g, CompMap comp_map) const
    {   
330
        get_components(g, comp_map, typename is_convertible<typename graph_traits<Graph>::directed_category, directed_tag>::type());
331
332
333
334
    }

    template <class Graph, class CompMap>
    void get_components(const Graph& g, CompMap comp_map, boost::true_type is_directed) const
Tiago Peixoto's avatar
Tiago Peixoto committed
335
    {
336
        strong_components(g, comp_map);
Tiago Peixoto's avatar
Tiago Peixoto committed
337
338
    }

339
340
    template <class Graph, class CompMap>
    void get_components(const Graph& g, CompMap comp_map, boost::false_type is_directed) const
Tiago Peixoto's avatar
Tiago Peixoto committed
341
    {
342
        connected_components(g, comp_map);
Tiago Peixoto's avatar
Tiago Peixoto committed
343
    }
344
    
Tiago Peixoto's avatar
Tiago Peixoto committed
345
346
};

347
void GraphInterface::LabelComponents(string prop)
Tiago Peixoto's avatar
Tiago Peixoto committed
348
{
349
350
    typedef HashedDescriptorMap<vertex_index_map_t, size_t> comp_map_t;
    static comp_map_t comp_map(_vertex_index);
Tiago Peixoto's avatar
Tiago Peixoto committed
351

352
    check_filter(*this, bind<void>(label_components(), _1, comp_map), reverse_check(), directed_check());
Tiago Peixoto's avatar
Tiago Peixoto committed
353

354
355
    try
    {
356
357
        find_property_map(_properties, prop, typeid(graph_traits<multigraph_t>::vertex_descriptor));
        RemoveVertexProperty(prop);
Tiago Peixoto's avatar
Tiago Peixoto committed
358
    }
359
    catch (property_not_found) {}
Tiago Peixoto's avatar
Tiago Peixoto committed
360

361
    _properties.property(prop, comp_map);
Tiago Peixoto's avatar
Tiago Peixoto committed
362
363
}

Tiago Peixoto's avatar
Tiago Peixoto committed
364
365
366
367
368
369
370
371
372
//==============================================================================
// label_parallel_edges
// label parallel edges in order
//==============================================================================
struct label_parallel_edges
{
    template <class Graph, class EdgeIndexMap, class ParallelMap>
    void operator()(const Graph& g, EdgeIndexMap edge_index, ParallelMap parallel) const
    {
373
374
375
376
377
378
379
        typename graph_traits<Graph>::vertex_iterator v, v_end;
        for (tie(v, v_end) = vertices(g); v != v_end; ++v)
        {
            tr1::unordered_set<typename graph_traits<Graph>::edge_descriptor,DescriptorHash<EdgeIndexMap> > p_edges(0, DescriptorHash<EdgeIndexMap>(edge_index));
            typename graph_traits<Graph>::out_edge_iterator e1, e2, e_end;
            for (tie(e1, e_end) = out_edges(*v, g); e1 != e_end; ++e1)
            {
380
381
382
383
384
385
386
387
388
389
                if (p_edges.find(*e1) != p_edges.end())
                    continue;
                size_t n = 0;
                put(parallel, *e1, n);
                for (tie(e2, e_end) = out_edges(*v, g); e2 != e_end; ++e2)
                    if (*e2 != *e1 && target(*e1, g) == target(*e2, g))
                    {
                        put(parallel, *e2, ++n);
                        p_edges.insert(*e2);
                    }
390
391
            }
        }
Tiago Peixoto's avatar
Tiago Peixoto committed
392
393
394
395
396
397
398
399
400
401
    }
};

//==============================================================================
// LabelParallelEdges(property)
//==============================================================================
void GraphInterface::LabelParallelEdges(string property)
{
    try
    {
402
403
        DynamicPropertyMapWrap<size_t,graph_traits<multigraph_t>::edge_descriptor> parallel_map(find_property_map(_properties, property, typeid(graph_traits<multigraph_t>::edge_descriptor)));
        check_filter(*this, bind<void>(label_parallel_edges(), _1, _edge_index, parallel_map), reverse_check(), directed_check());
Tiago Peixoto's avatar
Tiago Peixoto committed
404
405
406
    }
    catch (property_not_found) 
    {
407
408
409
410
        typedef HashedDescriptorMap<edge_index_map_t,size_t> parallel_map_t;
        parallel_map_t parallel_map(_edge_index);
        check_filter(*this, bind<void>(label_parallel_edges(), _1, _edge_index, parallel_map), reverse_check(), directed_check());
        _properties.property(property, parallel_map);
Tiago Peixoto's avatar
Tiago Peixoto committed
411
412
413
414
    }
}


Tiago Peixoto's avatar
Tiago Peixoto committed
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
//==============================================================================
// InsertEdgeIndexProperty(property)
//==============================================================================
void GraphInterface::InsertEdgeIndexProperty(string property)
{
    _properties.property(property, _edge_index);
}

//==============================================================================
// InsertVertexIndexProperty(property)
//==============================================================================
void GraphInterface::InsertVertexIndexProperty(string property)
{
    _properties.property(property, _vertex_index);
}

//==============================================================================
// ComputeGraphLayoutGursoy(iter, seed)
//==============================================================================

struct compute_gursoy
{
    template <class Graph, class PosMap, class IndexMap>
    void operator()(Graph &g, size_t iter, size_t seed, PosMap pos, IndexMap index_map) const
    {
440
441
442
443
444
445
446
447
        mt19937 rng(static_cast<mt19937::result_type>(seed));
        size_t n = HardNumVertices()(g);
        
        vector_property_map<square_topology<mt19937>::point_type, IndexMap> position_map(index_map);
        if (iter == 0)
            iter = n;
        square_topology<mt19937> topology(rng, n);
        gursoy_atun_layout(g, topology, position_map, iterations(iter).
448
449
450
                           diameter_range(make_pair(sqrt(double(n)), 1.0)).
                           learning_constant_range(make_pair(0.8, 0.2)).
                           vertex_index_map(index_map));
451
452
453
454
455
456
457
        typename graph_traits<Graph>::vertex_iterator v, v_begin, v_end;
        tie(v_begin, v_end) = vertices(g);
        for(v = v_begin; v != v_end; ++v)
        {
            pos[*v].x = position_map[*v][0];
            pos[*v].y = position_map[*v][1];
        }
Tiago Peixoto's avatar
Tiago Peixoto committed
458
459
460
461
462
463
464
465
466
467
    }
};

typedef struct { double x; double y; } pos_t;
ostream& operator<<(ostream &o, const pos_t &p ) { o << p.x << "," << p.y; return o;}
istream& operator>>(istream &o, pos_t &p ) { char c; o >> p.x >> c >> p.y; return o;}

void GraphInterface::ComputeGraphLayoutGursoy(size_t iter, size_t seed)
{       
    // vertex postion map
468
469
    typedef HashedDescriptorMap<vertex_index_map_t, pos_t> pos_map_t;
    pos_map_t pos_map(_vertex_index);    
Tiago Peixoto's avatar
Tiago Peixoto committed
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485

    check_filter(*this,bind<void>(compute_gursoy(),_1,iter,seed,var(pos_map),var(_vertex_index)),reverse_check(),directed_check());

    _properties.property("pos", pos_map);
}

//==============================================================================
// ComputeGraphLayoutSpringBlock(iter,seed)
//==============================================================================
struct compute_spring_block
{

    template <class Graph, class PosMap, class IndexMap>
    void operator()(Graph &g, size_t iter, size_t seed, PosMap pos, IndexMap index_map) const
    {
  
486
487
        mt19937 rng(static_cast<mt19937::result_type>(seed));
        size_t n = HardNumVertices()(g);
Tiago Peixoto's avatar
Tiago Peixoto committed
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502

        if (iter == 0)
            iter = 100;
        double radius = n*iter;
        random_graph_layout(g, pos, -radius/2, radius/2, -radius/2, radius/2, rng);
        fruchterman_reingold_force_directed_layout(g, pos, radius, radius, 
                                                   cooling(linear_cooling<double>(iter)).
                                                   vertex_index_map(index_map));
    }
    
};

void GraphInterface::ComputeGraphLayoutSpringBlock(size_t iter, size_t seed)
{
    // vertex postion map
503
504
    typedef HashedDescriptorMap<vertex_index_map_t,pos_t> pos_map_t;
    pos_map_t pos_map(_vertex_index);    
Tiago Peixoto's avatar
Tiago Peixoto committed
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572

    check_filter(*this,bind<void>(compute_spring_block(),_1,iter,seed,var(pos_map),var(_vertex_index)),reverse_check(),directed_check()); 

    _properties.property("pos", pos_map);
}

//==============================================================================
// InitSignalHandling()
//==============================================================================

void catch_sig_stop(int sig_num)
{
    std::cerr << "graph-tool: received signal ";
    switch (sig_num)
    {
    case SIGINT:
        std::cerr << "SIGINT (Interrupt).";
        break;
    case SIGTERM:
        std::cerr << "SIGTERM (Termination).";
        break;
    case SIGQUIT:
        std::cerr << "SIGQUIT (Terminal quit).";
        break;
    case SIGHUP:
        std::cerr << "SIGHUP (Hangup).";
        break;
    case SIGPWR:
        std::cerr << "SIGPWR (Power failure restart).";
        break;
    case SIGSEGV:
        std::cerr << "SIGSEGV (Segmentation fault). There's a bug somewhere in the program. Go fix it.";
        break;
    case SIGBUS:
        std::cerr << "SIGBUS (BUS error). The bus is broken, I guess...";
        break;
    case SIGFPE:
        std::cerr << "SIGFPE (Floating-point exception). INFs and NANs are wreaking havoc.";
        break;
    case SIGILL:
        std::cerr << "SIGILL (Illegal instruction). Did you compile it right?";
        break;
    case SIGXCPU:
        std::cerr << "SIGXCPU (CPU limit exceeded). Time's over.";
        break;
    case SIGXFSZ:
        std::cerr << "SIGXFSZ (File size limit exceeded). The fascist sysadmin doesn't let you write more.";
        break;
    }
    std::cerr << " Bailing out cowardly and calling abort()." << std::endl;
    abort();
}


void GraphInterface::InitSignalHandling()
{
    signal(SIGINT, catch_sig_stop);
    signal(SIGTERM, catch_sig_stop);
    signal(SIGQUIT, catch_sig_stop);
    signal(SIGHUP, catch_sig_stop);
    signal(SIGPWR, catch_sig_stop);
    signal(SIGSEGV, catch_sig_stop);
    signal(SIGBUS, catch_sig_stop);
    signal(SIGFPE, catch_sig_stop);
    signal(SIGILL, catch_sig_stop);
    signal(SIGXCPU, catch_sig_stop);
    signal(SIGXFSZ, catch_sig_stop);
}