Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions multinet/include/community.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,7 @@ namespace mlnet {

double modularity(const MLNetworkSharedPtr& mnet, const CommunityStructureSharedPtr& groups, double c);
double modularity(const MLNetworkSharedPtr& mnet, const hash_map<NodeSharedPtr,long>& groups, double c); // for back-compatibility
hash_map<CommunitySharedPtr,hash_map<NodeSharedPtr,double>> get_nodes_belonging_coef(const CommunityStructureSharedPtr& communities);
double extended_modularity(const MLNetworkSharedPtr& mnet, const CommunityStructureSharedPtr& communities, hash_map<CommunitySharedPtr,hash_map<NodeSharedPtr,double>> nodes_belonging_coefficients,EdgeBelonigngFunc func);
/* Community comparison functions (external) */
double extended_modularity(const MLNetworkSharedPtr& mnet, const CommunityStructureSharedPtr& communities, double c);

double community_jaccard(const CommunitySharedPtr& c1, const CommunitySharedPtr& c2);

Expand Down
8 changes: 5 additions & 3 deletions multinet/include/community/flattening.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@

namespace mlnet {

enum WeighteningType {ZeroOne=0, NumOfLayers=1, Neighborhood=2};
enum SingleLayerAlgorithm {LabelPropagation =1};
enum WeighteningType {ZeroOne=0, NumOfLayers=1, Neighborhood=2, Jaccard=3};

ActorCommunityStructureSharedPtr flattenAndDetectComs(const MLNetworkSharedPtr& mnet, WeighteningType wType,SingleLayerAlgorithm slAlgo);

MLNetworkSharedPtr flatten(const MLNetworkSharedPtr& mnet, WeighteningType wType);

CommunityStructureSharedPtr map_back_to_ml(const CommunityStructureSharedPtr& fComs,const MLNetworkSharedPtr& mnet);

}

Expand Down
71 changes: 40 additions & 31 deletions multinet/src/community/community_evaluation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,30 +94,17 @@ namespace mlnet {

double omega_index(const CommunityStructureSharedPtr& partitioning1, const CommunityStructureSharedPtr& partitioning2,const MLNetworkSharedPtr& mnet){

//Create a map to represent pairs agreement in each input partitioning
//Create a map to represent pairs agreement in each input partitioning
//The map is of the form [ key = pair of nodes (node1,node2) and value = number of times they co-occured together]
std::map<std::pair<NodeSharedPtr,NodeSharedPtr>, int> p1_pairs_cooccurance;
std::map<std::pair<NodeSharedPtr,NodeSharedPtr>, int> p2_pairs_cooccurance;

//Get the nodes of the multi-net instance
NodeListSharedPtr network_nodes = mnet->get_nodes();

//Initialise both partitioning maps
for (NodeSharedPtr node1:*network_nodes){
for (NodeSharedPtr node2:*network_nodes){
if(node1!=node2){
std::pair<NodeSharedPtr,NodeSharedPtr> key (node1 ,node2);
std::pair<NodeSharedPtr,NodeSharedPtr> key_inversed (node2,node1);
if(p1_pairs_cooccurance.find(key)== p1_pairs_cooccurance.end() & p1_pairs_cooccurance.find(key_inversed)==p1_pairs_cooccurance.end()){
p1_pairs_cooccurance[key]=0;
p2_pairs_cooccurance[key]=0;
}
}
}
}

vector<CommunitySharedPtr> partitioning1_coms;
vector<CommunitySharedPtr> partitioning2_coms;
std::vector<CommunitySharedPtr> partitioning1_coms;
std::vector<CommunitySharedPtr> partitioning2_coms;

//Iterate through the first partitioning communities to set the values for the corresponding map
if(partitioning1!=NULL && partitioning1->get_communities().size()!=0){
Expand All @@ -140,6 +127,7 @@ namespace mlnet {
if(p1_pairs_cooccurance.find(key_inversed)!=p1_pairs_cooccurance.end()){
p1_pairs_cooccurance[key_inversed]=p1_pairs_cooccurance[key_inversed]+1;
}
else p1_pairs_cooccurance[key]=1;
}
}
}
Expand Down Expand Up @@ -169,6 +157,7 @@ namespace mlnet {
p2_pairs_cooccurance[key_inversed]=p2_pairs_cooccurance[key_inversed]+1;

}
else p2_pairs_cooccurance[key]=1;
}
}
}
Expand All @@ -178,33 +167,53 @@ namespace mlnet {

//Count the agreements between both partitions
int max_cooccurance_value=0;
int actual_agreements = 0;
int max_possible_num_of_agreements =0;
int actual_non_zero_agreements = 0;
int actual_zero_agreements = 0;
int total_agreemets=0;
int disagreements =0;
int max_possible_num_of_agreements = (network_nodes->size()*(network_nodes->size()-1))/2;

//Iterate through the keys in the first partitioning map
typedef std::map<std::pair<NodeSharedPtr,NodeSharedPtr>, int>::const_iterator MapIterator;
for (MapIterator iter = p1_pairs_cooccurance.begin(); iter != p1_pairs_cooccurance.end(); ++iter)
for (auto key_value:p1_pairs_cooccurance)
{
max_possible_num_of_agreements++;
//Get the current key
std::pair<NodeSharedPtr,NodeSharedPtr> key (iter->first.first ,iter->first.second);
std::pair<NodeSharedPtr,NodeSharedPtr> key (key_value.first.first ,key_value.first.second);
std::pair<NodeSharedPtr,NodeSharedPtr> inversed_key (key_value.first.second,key_value.first.first);
//Get the value referred to by the current key
int value_in_p1 = iter->second;
int value_in_p1 = key_value.second;
//check if this pair, key, exists in the other paritioning p2
int value_in_p2 = -1;
if ( p2_pairs_cooccurance.find(key) != p2_pairs_cooccurance.end()) {
value_in_p2 = p2_pairs_cooccurance[key];
}
else if (p2_pairs_cooccurance.find(inversed_key) != p2_pairs_cooccurance.end()) {
value_in_p2 = p2_pairs_cooccurance[inversed_key];
}
//Check the value of the same key in the second partitioning map
int value_in_p2 = p2_pairs_cooccurance[key];
if(value_in_p1==value_in_p2){
actual_agreements++;
actual_non_zero_agreements++;
p1_pairs_cooccurance[key]=0;
if ( p2_pairs_cooccurance.find(key) != p2_pairs_cooccurance.end()) p2_pairs_cooccurance[key]=0;
else p2_pairs_cooccurance[inversed_key]=0;
}
//Store the maximum value
if(value_in_p2>max_cooccurance_value | value_in_p1>max_cooccurance_value)
max_cooccurance_value=(value_in_p2 > value_in_p1)?value_in_p2:value_in_p1;

//std::cout << "< " << iter->first.first->actor->name << ", " << iter->first.second->actor->name <<"> = " << iter->second << std::endl;
// std::cout << "< " << iter->first.first->actor->name << ", " << iter->first.second->actor->name <<"> = " << p2_pairs_cooccurance[key] << std::endl;
if(value_in_p2>max_cooccurance_value || value_in_p1>max_cooccurance_value)
max_cooccurance_value=(value_in_p2 > value_in_p1)?value_in_p2:value_in_p1;
}

//count the disagreements
for(auto key_value:p1_pairs_cooccurance){
if(p1_pairs_cooccurance[key_value.first]!=0) disagreements++;
}
for(auto key_value:p2_pairs_cooccurance){
if(p2_pairs_cooccurance[key_value.first]!=0) disagreements++;
}

actual_zero_agreements = max_possible_num_of_agreements - actual_non_zero_agreements - disagreements;
total_agreemets = actual_zero_agreements + actual_non_zero_agreements;

double unadjusted_omega = ((float)actual_agreements/(float)max_possible_num_of_agreements);
double unadjusted_omega = ((float)total_agreemets/(float)max_possible_num_of_agreements);
//std::cout << "Unadjustd" << unadjusted_omega<<std::endl;

//calculate the exptected omega index of a null model
double omega_null_model=0;
Expand Down
145 changes: 97 additions & 48 deletions multinet/src/community/flattening.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <iostream>
#include <fstream>
#include "community/flattening.h"
#include "datastructures.h"

namespace mlnet {

Expand All @@ -24,20 +25,16 @@ double numOfDimentionsWeightening(const MLNetworkSharedPtr& mnet,const ActorShar
/*for each layer in the input multi-layer network try to find the corresponding nodes of input actors*/
for(LayerSharedPtr layer: *mnet->get_layers())
{
if(layer->name!="flattened")
{
NodeSharedPtr node1 = mnet->get_node(act1,layer);

NodeSharedPtr node2 = mnet->get_node(act2,layer);

/*if the corresponding nodes were found, and there is an edge among them, then increase the weight*/
if(node1 && node2 && mnet->get_edge(node1,node2))
{
expectedWeight+=1;
}
}
}
return expectedWeight;
return expectedWeight/(double) mnet->get_layers()->size();
}


Expand Down Expand Up @@ -108,69 +105,124 @@ double neighborhoodWeightening(const MLNetworkSharedPtr& mnet,const ActorSharedP

}


/**
* @brief calculate the weigh of an edge in case the weightening type "Jaccard" is chosen.
* The weight for an edge in the flattened layer will be set to the ratio constituted by the number
* of common layers of the two actors as a numerator and the union of layers as a denumerator
* @mnet : the multi-layer network instance
* @act1 : the first actor
* @act2 : the second actor
* @return : a double value representing the corresponding weight
**/
double jaccardWeghtening(const MLNetworkSharedPtr& mnet,const ActorSharedPtr& act1, const ActorSharedPtr& act2){


std::unordered_set<std::string> a1_layers ;
std::unordered_set<std::string> a2_layers ;

for (LayerSharedPtr layer: *mnet->get_layers()) {
if (mnet->get_node(act1,layer)) {
a1_layers.insert(layer->name);
}
if (mnet->get_node(act2,layer)) {
a2_layers.insert(layer->name);
}
}

std::vector<std::unordered_set<std::string> > arr;
arr.push_back(a1_layers);
arr.push_back(a2_layers);


return jaccard_similarity(arr);

}

/**
* @brief Detect communities in multiplex network.
* This is the implementation of Cocasa's method in detecting multi-dimentional communities using flattening
* https://pdfs.semanticscholar.org/fb9f/ec17f5962ecbc18b49f2057cbce0447e117d.pdf
* @brief Flatten a multiplex network into one single layer weighted network.
* @mnet: The input multiplex network instance
* @wType: The weightening method to be implemented in the resulted edges in the flattened graph
* @slAlgo:The single layer algorithm to be used to detect the communities
* @return:The resulted communities
* @return:The result of weighted flattening (i.e : a single layer weighted network)
**/

ActorCommunityStructureSharedPtr flattenAndDetectComs(const MLNetworkSharedPtr& mnet, WeighteningType wType,SingleLayerAlgorithm slAlgo){


MLNetworkSharedPtr flatten(const MLNetworkSharedPtr& mnet, WeighteningType wType){

//STEPS:
CommunityStructureSharedPtr singleLayerComs ;
ActorCommunityStructureSharedPtr result ;
MLNetworkSharedPtr fnet = MLNetwork::create("flattened_net");

//(1) Mapping function : from multi-dimentional(multiplex) to mono-dimentional(flattened layer)
/*add a new layer to the same multi-layer instance*/
LayerSharedPtr flattenedLayer = mnet->add_layer("flattened",UNDIRECTED);
/*add the wight attribute to the edges of this layer*/
mnet->edge_features(flattenedLayer,flattenedLayer)->add("_WEIGHT",NUMERIC_TYPE);

/*add a new layer to the flattened network*/
LayerSharedPtr flattenedLayer = fnet->add_layer("flattened",UNDIRECTED);

/*add the weight attribute to the edges of this layer*/
fnet->edge_features(flattenedLayer,flattenedLayer)->add("_WEIGHT",NUMERIC_TYPE);

/*add the actors to the flattened network */
for (ActorSharedPtr act:*mnet->get_actors()){
fnet->add_actor(act->name);
fnet->add_node(act,flattenedLayer);
}

/*for each edge in the input network*/
for (EdgeSharedPtr edge : *mnet->get_edges()) {
/*consider the edge only if is an intra-layer edge*/
if(edge->v1->layer == edge->v2->layer)
{
ActorSharedPtr act1 = edge->v1->actor;
ActorSharedPtr act2 = edge->v2->actor;
NodeSharedPtr from = mnet->add_node(act1,flattenedLayer) ;
NodeSharedPtr to = mnet->add_node(act2,flattenedLayer);
ActorSharedPtr act1 = mnet->get_actor(edge->v1->actor->name);
ActorSharedPtr act2 = mnet->get_actor(edge->v2->actor->name);

NodeSharedPtr from = fnet->get_node(act1,flattenedLayer);
NodeSharedPtr to = fnet->get_node(act2,flattenedLayer);
double expectedWeight=0;
//Add the edge if the nodes are retrieved and the edge is not already existent
if(from && to && !mnet->get_edge(from,to))
//Add the edge if the it is not already existent
if(!fnet->get_edge(from,to))
{
mnet->add_edge(from,to);
fnet->add_edge(from,to);

//calculate the weight of the edge
switch (wType) {
case ZeroOne: expectedWeight =1 ; break;
case ZeroOne:
expectedWeight =1;
break;
case NumOfLayers:
expectedWeight = numOfDimentionsWeightening(mnet,act1,act2) ;break;
case Neighborhood: expectedWeight = neighborhoodWeightening(mnet,act1,act2);
break;
expectedWeight = numOfDimentionsWeightening(mnet,act1,act2) ;
break;
case Neighborhood:
expectedWeight = neighborhoodWeightening(mnet,act1,act2);
break;
case Jaccard:
expectedWeight = jaccardWeghtening(mnet,act1,act2);
break;
default: expectedWeight =1;
}
mnet->set_weight(from,to,expectedWeight);
fnet->set_weight(from,to,expectedWeight);
}

}
}

//(2) Perform community detection on the resulted mono-dimentional graph (in other words, the flattened layer)
switch (slAlgo) {
case LabelPropagation:
singleLayerComs = label_propagation_single(mnet, flattenedLayer);
break;
default:
singleLayerComs = label_propagation_single(mnet, flattenedLayer);
}
return fnet;
}


/**
* @brief maps back the communities found in the flattened network into multi-layer communities in the original multi-layer instance.
* @fComs: The communities of the flattened graph
* @mnet: The input multi-layer network instance
* @return:The mapping as actor communities on the multi-layer instance
**/
CommunityStructureSharedPtr map_back_to_ml(const CommunityStructureSharedPtr& fComs,const MLNetworkSharedPtr& mnet){

//(3) Mapping back : from mono-dimentional(flattened layer) to multi-dimentional(multiplex)
result = actor_community_structure::create();
//for each community in the single layer communities instance
for(CommunitySharedPtr singleCom:singleLayerComs->get_communities()){
ActorCommunityStructureSharedPtr result = actor_community_structure::create();

//for each community in the flattened network
for(CommunitySharedPtr singleCom:fComs->get_communities()){
ActorCommunitySharedPtr actor_com = actor_community::create();
//for each node in the current single layer community

//for each node in the current flattened network community
for(NodeSharedPtr node:singleCom->get_nodes()){
//find the actor of this node in the mnet instance
ActorSharedPtr actor = node->actor;
Expand All @@ -188,11 +240,8 @@ ActorCommunityStructureSharedPtr flattenAndDetectComs(const MLNetworkSharedPtr&
// add this community to the list of communities to be returned
result->add_community(actor_com);
}
//now, the flattened layer can be safely deleted from the mnet instance
mnet->erase(flattenedLayer);
return result;
}

return to_node_communities(result,mnet);
}

}

Loading