/*
* @(#)SimpleCommunityDetection.java
*
* Copyright 2010 by University of Pittsburgh, released under GPLv3.
*
*/
package routing.community;
import java.util.*;
//import routing.communitydetection.DiBuBB.Duration;
import core.*;
/**
*
Performs the SIMPLE Community Detection algorithm described in
* Distributed Community Detection in Delay Tolerant Networks by Pan
* Hui et al. (bibtex record is included below for convenience). A node using
* SIMPLE keeps a record of all the nodes it has met and the cummulative contact
* duration it has had with each. Once this total contact duration for one of
* these nodes exceeds a configurable parameter, the node is added to the host's
* familiar set and local community. When two peers meet, they compair their
* familiar sets and local communities for commonalities and may decide to merge
* their local communities, which intuitively means that they've decided that
* they each tend to meet the same nodes often, suggesting they both are and
* should be part of the same local community.
*
*
*
* \@inproceedings{1366929,
* Address = {New York, NY, USA},
* Author = {Hui, Pan and Yoneki, Eiko and Chan, Shu Yan and Crowcroft, Jon},
* Booktitle = {MobiArch '07: Proceedings of 2nd ACM/IEEE international workshop
* on Mobility in the evolving internet architecture},
* Doi = {http://doi.acm.org/10.1145/1366919.1366929},
* Isbn = {978-1-59593-784-8},
* Location = {Kyoto, Japan},
* Pages = {1--8},
* Publisher = {ACM},
* Title = {Distributed community detection in delay tolerant networks},
* Year = {2007}
* }
*
*
* @author PJ Dillon, University of Pittsburgh
*/
public class SimpleCommunityDetection implements CommunityDetection
{
/** Threshold value for adding a host to the local community -setting id
* {@value}
*/
public static final String LAMBDA_SETTING = "lambda";
/** Threshold value for merging the local community with a peer -setting id
* {@value}
*/
public static final String GAMMA_SETTING = "gamma";
/** Total contact time threshold for adding a node to the familiar set
* -setting id {@value}
*/
public static final String FAMILIAR_SETTING = "familiarThreshold";
protected Set familiarSet;
protected Set localCommunity;
protected double lambda;
protected double gamma;
protected double familiarThreshold;
/**
* Constructs a new SimpleCommunityDetection from the Settings parameter
* object
*
* @param s Settings from which to initialize
*/
public SimpleCommunityDetection(Settings s)
{
this.lambda = s.getDouble(LAMBDA_SETTING);
this.gamma = s.getDouble(GAMMA_SETTING);
this.familiarThreshold = s.getDouble(FAMILIAR_SETTING);
}
public SimpleCommunityDetection(SimpleCommunityDetection proto)
{
this.lambda = proto.lambda;
this.gamma = proto.gamma;
this.familiarThreshold = proto.familiarThreshold;
familiarSet = new HashSet();
localCommunity = new HashSet();
}
public void newConnection(DTNHost myHost, DTNHost peer,
CommunityDetection peerCD)
{
boolean addPeerToMyLocal=false, addMeToPeerLocal=false;
SimpleCommunityDetection scd = (SimpleCommunityDetection)peerCD;
this.localCommunity.add(myHost);
scd.localCommunity.add(peer);
// Add peer to my local community if needed
if(!this.localCommunity.contains(peer))
{
/*
* The algorithm calls for computing the size of the intersection of
* peer's familiarSet and this host's localCommunity. We divide that by
* the size of the peer's familiar set
*/
// compute set intersection
int count=0, peerFsize = scd.familiarSet.size();
for(DTNHost h : scd.familiarSet)
if(this.localCommunity.contains(h))
count++;
// add peer to local community if enough nodes in common
if(addPeerToMyLocal = ((double)count)/peerFsize > this.lambda)
{
this.localCommunity.add(peer);
}
}
/*
* Repeat the computation for the other end of the connection
*/
if(!scd.localCommunity.contains(myHost))
{
// compute set intersection
int count = 0, myFsize = this.familiarSet.size();
for(DTNHost h : this.familiarSet)
if(scd.localCommunity.contains(h))
count++;
// add this host to local community of peer if enough nodes in common
if(addMeToPeerLocal = ((double)count)/myFsize > scd.lambda)
{
scd.localCommunity.add(myHost);
}
}
// Test for conditions when the local communities should be merged
if(addPeerToMyLocal || addMeToPeerLocal)
{
// Compute set union
Set commUnion = new HashSet(this.localCommunity.size() +
scd.localCommunity.size() + 2);
commUnion.addAll(this.localCommunity);
commUnion.addAll(scd.localCommunity);
// compute intersection of the two local communities
// (the result is the same from both node's perspective)
int count = 0;
for(DTNHost h : this.localCommunity)
if(scd.localCommunity.contains(h))
count++;
// merge communities if enough nodes are common
if(addPeerToMyLocal && count > this.gamma * commUnion.size())
{
this.localCommunity.addAll(scd.localCommunity);
}
if(addMeToPeerLocal && count > scd.gamma * commUnion.size())
{
scd.localCommunity.addAll(this.localCommunity);
}
}
}
public void connectionLost(DTNHost myHost, DTNHost peer,
CommunityDetection peerCD, List history)
{
if(this.familiarSet.contains(peer)) return;
/*
* If the peer isn't part of the familiar set, add it when the total
* contact duration exceeds the familiarThreshold
*/
// Compute total contact duration
Iterator i = history.iterator();
double time = 0;
while(i.hasNext())
{
Duration d = i.next();
time += d.end - d.start;
}
// Add peer to familiar set if needed (and by extension to the local comm.)
if(time > this.familiarThreshold)
{
this.familiarSet.add(peer);
this.localCommunity.add(peer);
}
}
public boolean isHostInCommunity(DTNHost h)
{
return this.localCommunity.contains(h);
}
public CommunityDetection replicate()
{
return new SimpleCommunityDetection(this);
}
public Set getLocalCommunity()
{
return this.localCommunity;
}
public Set getFamiliarSet()
{
return this.familiarSet;
}
}