graph_properties.cc 10.4 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
// 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.

19
20
21
22
23
#include <boost/lambda/bind.hpp>

#include "graph.hh"
#include "histogram.hh"
#include "graph_filtering.hh"
24
#include "graph_python_filtering.hh"
25
#include "graph_selectors.hh"
Tiago Peixoto's avatar
Tiago Peixoto committed
26
27
#include "graph_properties.hh"

28
29
30
31
#include <boost/mpl/for_each.hpp>
#include <iostream>
#include <iomanip>

32
33
34
35
36
37
using namespace std;
using namespace boost;
using namespace boost::lambda;
using namespace graph_tool;


Tiago Peixoto's avatar
Tiago Peixoto committed
38
39
40
//==============================================================================
// find_property_map(dp,name,key_type)
//==============================================================================
41
42
dynamic_property_map& 
graph_tool::find_property_map(const dynamic_properties& dp, string name, const type_info& key_type)
Tiago Peixoto's avatar
Tiago Peixoto committed
43
44
{
    for(typeof(dp.begin()) iter = dp.begin(); iter != dp.end(); ++iter)
45
46
        if (iter->first == name && iter->second->key() == key_type)
            return *iter->second;
Tiago Peixoto's avatar
Tiago Peixoto committed
47

48
49
50
51
52
53
54
55
56
57
58
    throw property_not_found(name);
}

//==============================================================================
// RemoveVertexProperty(property)
//==============================================================================
void GraphInterface::RemoveVertexProperty(string property)
{
    dynamic_properties_copy dp;
    try
    {
59
60
61
62
        dynamic_property_map& prop_map = find_property_map(_properties, property, typeid(graph_traits<multigraph_t>::vertex_descriptor));
        for (typeof(_properties.begin()) iter = _properties.begin(); iter != _properties.end(); ++iter)
        {
            if (iter->second != &prop_map)
63
                dp.insert(iter->first, auto_ptr<dynamic_property_map>(iter->second));
64
        }
65
66
67
    }
    catch (property_not_found)
    {
68
        throw GraphException("property '" + property + "' not found");
69
70
71
72
73
74
75
76
77
78
79
80
    }
    _properties = dp;
}

//==============================================================================
// RemoveEdgeProperty(property)
//==============================================================================
void GraphInterface::RemoveEdgeProperty(string property)
{
    dynamic_properties_copy dp;
    try
    {
81
82
83
84
        dynamic_property_map& prop_map = find_property_map(_properties, property, typeid(graph_traits<multigraph_t>::edge_descriptor));
        for (typeof(_properties.begin()) iter = _properties.begin(); iter != _properties.end(); ++iter)
        {
            if (iter->second != &prop_map)
85
                dp.insert(iter->first, auto_ptr<dynamic_property_map>(iter->second));
86
        }
87
88
89
    }
    catch (property_not_found)
    {
90
        throw GraphException("property '" + property + "' not found");
91
92
93
94
95
96
97
98
99
100
101
102
103
    }
    _properties = dp;
}

//==============================================================================
// edit_property
//==============================================================================
template <class Descriptor>
struct edit_property
{
    template <class Graph, class PropertyMap>
    void operator()(const Graph& g, const dynamic_properties& dp, PropertyMap prop_map, python::object& op) const
    {
104
        typedef mpl::vector<in_degreeS,out_degreeS,total_degreeS> degrees;
105

106
        python::object operation = op[0], variables = op[1];
107

108
109
        typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
        typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;
110

111
        typedef typename mpl::if_<is_same<Descriptor,vertex_descriptor>,vertex_descriptor,edge_descriptor>::type descriptor_t;
112
        descriptor_t u;
113
114
        
        populate_python_funcs<descriptor_t>()(g, u, dp, variables);
115

116
        put_properties(g, u, prop_map, operation);
117
118
119
120
    }
    
    template<class Graph, class PropertyMap>
    void put_properties(const Graph& g, typename graph_traits<Graph>::vertex_descriptor& v, 
121
                        PropertyMap prop_map, python::object& operation) const
122
    {
123
124
125
126
127
128
129
        typename graph_traits<Graph>::vertex_iterator vi,v_end;
        for (tie(vi, v_end) = vertices(g); vi != v_end; ++vi)
        {
            v = *vi;
            typename property_traits<PropertyMap>::value_type val = python::extract<typename property_traits<PropertyMap>::value_type>(operation());
            put(prop_map, v, val);
        }
130
131
132
133
    }

    template<class Graph, class PropertyMap>
    void put_properties(const Graph& g, typename graph_traits<Graph>::edge_descriptor& e, 
134
                        PropertyMap prop_map, python::object& operation) const
135
    {
136
137
138
139
140
141
142
        typename graph_traits<Graph>::edge_iterator ei,e_end;
        for (tie(ei, e_end) = edges(g); ei != e_end; ++ei)
        {
            e = *ei;
            typename property_traits<PropertyMap>::value_type val = python::extract<typename property_traits<PropertyMap>::value_type>(operation());
            put(prop_map, e, val);
        }
143
    }
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
};

//==============================================================================
// update_property_map()
//==============================================================================

template <class ValueTypes, class Descriptor, class IndexMap>
class update_property_map
{
public:
    update_property_map(GraphInterface& gi, dynamic_properties& dp, IndexMap index_map, string property, string type, char* types[], python::object op)
        : _gi(gi), _dp(dp), _index_map(index_map), _property(property), _type(type), _types(types), _op(op) {}

    template <class ValueType>
    void operator()(ValueType)
    {
        if (_type == _types[mpl::find<ValueTypes,ValueType>::type::pos::value])
        {
            try
            {
                dynamic_property_map& dpmap = find_property_map(_dp, _property, typeid(Descriptor));
                typedef DynamicPropertyMapWrap<ValueType,Descriptor> prop_map_t;
                prop_map_t prop_map(dpmap);
                check_filter(_gi, bind<void>(edit_property<Descriptor>(), _1, var(_dp), prop_map, var(_op)),
                             reverse_check(), directed_check());
            }
            catch (property_not_found)
            {
                typedef vector_property_map<ValueType, IndexMap> prop_map_t;
                prop_map_t prop_map(_index_map);
                check_filter(_gi, bind<void>(edit_property<Descriptor>(), _1, var(_dp), prop_map, var(_op)),
                             reverse_check(), directed_check());
                _dp.property(_property, prop_map);
            }    
178

179
180
181
182
183
184
185
186
187
188
189
        }
    }

private:
    GraphInterface& _gi;
    dynamic_properties& _dp;
    IndexMap _index_map;
    string _property;
    string _type;
    char** _types;
    python::object _op;
190
191
};

192

193
194
195
196
//==============================================================================
// EditVertexProperty()
//==============================================================================

197
void GraphInterface::EditVertexProperty(string property, string type, python::object op)
198
{
199
200
201
202
203
204
205
206
207
208
    typedef mpl::vector<bool, int, long, float, double, std::string> value_types;
    char* type_names[] = {"boolean", "int", "long", "float", "double", "string"};

    bool valid = false;
    for(int i = 0; i < mpl::size<value_types>::type::value; ++i)
        if (type == type_names[i])
            valid = true;
    if (!valid)
        throw GraphException("invalid type: " + type);

209
    typedef graph_traits<multigraph_t>::vertex_descriptor vertex_descriptor;
210
    mpl::for_each<value_types>(update_property_map<value_types,vertex_descriptor,vertex_index_map_t>(*this, _properties, _vertex_index, property, type, type_names, op));
211
212
}

213
214
215
216
217
//==============================================================================
// EditEdgeProperty()
//==============================================================================

void GraphInterface::EditEdgeProperty(string property, string type, python::object op)
218
{
219
220
221
222
223
224
225
226
227
228
    typedef mpl::vector<bool, int, long, float, double, std::string> value_types;
    char* type_names[] = {"boolean", "int", "long", "float", "double", "string"};

    bool valid = false;
    for(int i = 0; i < mpl::size<value_types>::type::value; ++i)
        if (type == type_names[i])
            valid = true;
    if (!valid)
        throw GraphException("invalid type: " + type);

229
    typedef graph_traits<multigraph_t>::edge_descriptor edge_descriptor;
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
    mpl::for_each<value_types>(update_property_map<value_types,edge_descriptor,edge_index_map_t>(*this, _properties, _edge_index, property, type, type_names, op));
}

//==============================================================================
// ListProperties()
//==============================================================================

template <class ValueTypes>
class print_name
{
public:
    print_name(const type_info& type, char* types[]): _type(type), _types(types) {}

    template <class ValueType>
    void operator()(ValueType)
245
    {
246
247
        if (_type == typeid(ValueType))
            cout << _types[mpl::find<ValueTypes,ValueType>::type::pos::value];
248
    }
249
250
251
252
253
254
255
256
257
258
259
private:
    const type_info& _type;
    char** _types;
};

void GraphInterface::ListProperties() const
{
    typedef mpl::vector<bool, int, long, float, double, std::string> value_types;
    char* type_names[] = {"boolean", "int", "long", "float", "double", "string"};

    for (typeof(_properties.begin()) p = _properties.begin(); p != _properties.end(); ++p)
260
    {
261
262
263
264
265
266
267
268
269
270
271
        cout << setw(15) << left << p->first << " " << setw(8) << left;
        if (p->second->key() == typeid(graph_traits<multigraph_t>::vertex_descriptor))
            cout << "(vertex)";
        else 
            if (p->second->key() == typeid(graph_traits<multigraph_t>::edge_descriptor))
                cout << "(edge)";
            else
                cout << "(graph)";
        cout << "  type: ";
        mpl::for_each<value_types>(print_name<value_types>(p->second->value(), type_names));
        cout << endl;
272
    }
Tiago Peixoto's avatar
Tiago Peixoto committed
273
}
274