File: MutableVertexPartition.h

package info (click to toggle)
libleidenalg 0.12.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 424 kB
  • sloc: cpp: 3,679; makefile: 11; ansic: 9
file content (183 lines) | stat: -rw-r--r-- 7,220 bytes parent folder | download | duplicates (2)
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
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
178
179
180
181
182
183
#ifndef MUTABLEVERTEXPARTITION_H
#define MUTABLEVERTEXPARTITION_H

#include <string>
#include "GraphHelper.h"
#include <map>
#include <queue>
#include <utility>
#include <algorithm>

using std::string;
using std::map;
using std::make_pair;
using std::pair;
using std::sort;
using std::reverse;
using std::priority_queue;

/****************************************************************************
Contains a partition of graph.

This class contains the basic implementation for optimising a partition.
Specifically, it implements all the administration necessary to keep track of
the partition from various points of view. Internally, it keeps track of the
number of internal edges (or total weight), the size of the communities, the
total incoming degree (or weight) for a community, etc... When deriving from
this class, one can easily use this administration to provide their own
implementation.

In order to keep the administration up-to-date, all changes in partition
should be done through move_node. This function moves a node from one
community to another, and updates all the administration.

It is possible to manually update the membership vector, and then call
__init_admin() which completely refreshes all the administration. This is
only possible by updating the membership vector, not by changing some of the
other variables.

The basic idea is that diff_move computes the difference in the quality
function if we call move_node for the same move. Using this framework, the
Leiden method in the optimisation class can call these general functions in
order to optimise the quality function.
*****************************************************************************/

class LIBLEIDENALG_EXPORT MutableVertexPartition
{
  public:
    MutableVertexPartition(Graph* graph,
        vector<size_t> const& membership);
    MutableVertexPartition(Graph* graph);
    virtual MutableVertexPartition* create(Graph* graph);
    virtual MutableVertexPartition* create(Graph* graph, vector<size_t> const& membership);

    virtual ~MutableVertexPartition();

    inline size_t membership(size_t v) { return this->_membership[v]; };
    inline vector<size_t> const& membership() const { return this->_membership; };

    double csize(size_t comm);
    size_t cnodes(size_t comm);
    vector<size_t> get_community(size_t comm);
    vector< vector<size_t> > get_communities();
    size_t n_communities();

    void move_node(size_t v,size_t new_comm);
    virtual double diff_move(size_t v, size_t new_comm)
    {
      throw Exception("Function not implemented. This should be implemented in a derived class, since the base class does not implement a specific method.");
    };
    virtual double quality()
    {
      throw Exception("Function not implemented. This should be implemented in a derived class, since the base class does not implement a specific method.");
    };

    inline Graph* get_graph() { return this->graph; };

    void renumber_communities();
    void renumber_communities(vector<size_t> const& fixed_nodes, vector<size_t> const& fixed_membership);
    void renumber_communities(vector<size_t> const& new_membership);
    void set_membership(vector<size_t> const& new_membership);
    void relabel_communities(vector<size_t> const& new_comm_id);
    vector<size_t> static rank_order_communities(vector<MutableVertexPartition*> partitions);
    size_t get_empty_community();
    size_t add_empty_community();
    void from_coarse_partition(vector<size_t> const& coarse_partition_membership);
    void from_coarse_partition(MutableVertexPartition* partition);
    void from_coarse_partition(MutableVertexPartition* partition, vector<size_t> const& coarser_membership);
    void from_coarse_partition(vector<size_t> const& coarse_partition_membership, vector<size_t> const& coarse_node);

    void from_partition(MutableVertexPartition* partition);

    inline double total_weight_in_comm(size_t comm)   { return comm < _n_communities ? this->_total_weight_in_comm[comm] : 0.0; };
    inline double total_weight_from_comm(size_t comm) { return comm < _n_communities ? this->_total_weight_from_comm[comm] : 0.0; };
    inline double total_weight_to_comm(size_t comm)   { return comm < _n_communities ? this->_total_weight_to_comm[comm] : 0.0; };

    inline double total_weight_in_all_comms()         { return this->_total_weight_in_all_comms; };
    inline size_t total_possible_edges_in_all_comms() { return this->_total_possible_edges_in_all_comms; };

    inline double weight_to_comm(size_t v, size_t comm)
    {
      if (this->_current_node_cache_community_to != v)
      {
        this->cache_neigh_communities(v, IGRAPH_OUT);
        this->_current_node_cache_community_to = v;
      }

      if (comm < this->_cached_weight_to_community.size())
        return this->_cached_weight_to_community[comm];
      else
        return 0.0;
    }

    inline double weight_from_comm(size_t v, size_t comm)
    {
      if (!this->graph->is_directed())
        return weight_to_comm(v, comm);

      if (this->_current_node_cache_community_from != v)
      {
        this->cache_neigh_communities(v, IGRAPH_IN);
        this->_current_node_cache_community_from = v;
      }

      if (comm < this->_cached_weight_from_community.size())
        return this->_cached_weight_from_community[comm];
      else
        return 0.0;
    }

    vector<size_t> const& get_neigh_comms(size_t v, igraph_neimode_t);
    vector<size_t> get_neigh_comms(size_t v, igraph_neimode_t mode, vector<size_t> const& constrained_membership);

    // By delegating the responsibility for deleting the graph to the partition,
    // we no longer have to worry about deleting this graph.
    int destructor_delete_graph;

  protected:

    void init_admin();

    vector<size_t> _membership; // Membership vector, i.e. \sigma_i = c means that node i is in community c

    Graph* graph;

    // Community size
    vector<double> _csize;

    // Number of nodes in community
    vector< size_t > _cnodes;

    double weight_vertex_tofrom_comm(size_t v, size_t comm, igraph_neimode_t mode);

    void set_default_attrs();

  private:

    // Keep track of the internal weight of each community
    vector<double> _total_weight_in_comm;
    // Keep track of the total weight to a community
    vector<double> _total_weight_to_comm;
    // Keep track of the total weight from a community
    vector<double> _total_weight_from_comm;
    // Keep track of the total internal weight
    double _total_weight_in_all_comms;
    size_t _total_possible_edges_in_all_comms;
    size_t _n_communities;

    vector<size_t> _empty_communities;

    void cache_neigh_communities(size_t v, igraph_neimode_t mode);

    size_t _current_node_cache_community_from; vector<double> _cached_weight_from_community; vector<size_t> _cached_neigh_comms_from;
    size_t _current_node_cache_community_to;   vector<double> _cached_weight_to_community;   vector<size_t> _cached_neigh_comms_to;
    size_t _current_node_cache_community_all;  vector<double> _cached_weight_all_community;  vector<size_t> _cached_neigh_comms_all;

    void clean_mem();
    void init_graph_admin();

    void update_n_communities();

};

#endif // MUTABLEVERTEXPARTITION_H