MergeCommunities
(
LinkedList<Community> oCommunities,
CommunityPair oCommunityPairToMerge,
DeltaQMaxHeap oDeltaQMaxHeap,
Int32 iEdgesInGraph,
IDGenerator oIDGenerator
)
{
Debug.Assert(oCommunityPairToMerge != null);
Debug.Assert(oCommunities != null);
Debug.Assert(oDeltaQMaxHeap != null);
Debug.Assert(iEdgesInGraph > 0);
Debug.Assert(oIDGenerator != null);
// Merge Community1 and Community2 into a NewCommunity.
Community oCommunity1 = oCommunityPairToMerge.Community1;
Community oCommunity2 = oCommunityPairToMerge.Community2;
Community oNewCommunity = new Community();
oNewCommunity.ID = oIDGenerator.GetNextID();
oNewCommunity.Degree = oCommunity1.Degree + oCommunity2.Degree;
ICollection<IVertex> oNewCommunityVertices = oNewCommunity.Vertices;
foreach (IVertex oVertex in oCommunity1.Vertices)
{
oNewCommunityVertices.Add(oVertex);
}
foreach (IVertex oVertex in oCommunity2.Vertices)
{
oNewCommunityVertices.Add(oVertex);
}
// In the following sorted lists, the sort key is the ID of
// CommunityPair.Community2 and the value is the CommunityPair.
SortedList<Int32, CommunityPair> oCommunity1CommunityPairs =
oCommunity1.CommunityPairs;
SortedList<Int32, CommunityPair> oCommunity2CommunityPairs =
oCommunity2.CommunityPairs;
SortedList<Int32, CommunityPair> oNewCommunityCommunityPairs =
oNewCommunity.CommunityPairs;
Int32 iCommunity1CommunityPairs = oCommunity1CommunityPairs.Count;
Int32 iCommunity2CommunityPairs = oCommunity2CommunityPairs.Count;
IList<Int32> oCommunity1Keys = oCommunity1CommunityPairs.Keys;
IList<CommunityPair> oCommunity1Values =
oCommunity1CommunityPairs.Values;
IList<Int32> oCommunity2Keys = oCommunity2CommunityPairs.Keys;
IList<CommunityPair> oCommunity2Values =
oCommunity2CommunityPairs.Values;
// Step through the community pairs in oCommunity1 and oCommunity2.
Int32 iCommunity1Index = 0;
Int32 iCommunity2Index = 0;
Single fMaximumDeltaQ = Single.MinValue;
CommunityPair oCommunityPairWithMaximumDeltaQ = null;
Single fTwoTimesEdgesInGraph = 2F * iEdgesInGraph;
while (iCommunity1Index < iCommunity1CommunityPairs ||
iCommunity2Index < iCommunity2CommunityPairs)
{
Int32 iCommunity1OtherCommunityID =
(iCommunity1Index < iCommunity1CommunityPairs) ?
oCommunity1Keys[iCommunity1Index] : Int32.MaxValue;
Int32 iCommunity2OtherCommunityID =
(iCommunity2Index < iCommunity2CommunityPairs) ?
oCommunity2Keys[iCommunity2Index] : Int32.MaxValue;
CommunityPair oNewCommunityPair = new CommunityPair();
oNewCommunityPair.Community1 = oNewCommunity;
if (iCommunity1OtherCommunityID == oCommunity2.ID)
{
// This is an internal connection eliminated by the merge.
// Skip it.
iCommunity1Index++;
continue;
}
else if (iCommunity2OtherCommunityID == oCommunity1.ID)
{
// This is an internal connection eliminated by the merge.
// Skip it.
iCommunity2Index++;
continue;
}
else if (iCommunity1OtherCommunityID == iCommunity2OtherCommunityID)
{
// The other community is connected to both commmunity 1 and
// community 2.
//
// This is equation 10a from the paper "Finding Community
// Structure in Very Large Networks," by Clauset, Newman, and
// Moore.
oNewCommunityPair.Community2 =
oCommunity1Values[iCommunity1Index].Community2;
oNewCommunityPair.DeltaQ =
oCommunity1Values[iCommunity1Index].DeltaQ +
oCommunity2Values[iCommunity2Index].DeltaQ;
iCommunity1Index++;
iCommunity2Index++;
}
else if (iCommunity1OtherCommunityID < iCommunity2OtherCommunityID)
{
// The other community is connected only to commmunity 1.
//
// This is equation 10b from the same paper.
Community oOtherCommunity =
oCommunity1Values[iCommunity1Index].Community2;
oNewCommunityPair.Community2 = oOtherCommunity;
Single fAj = oCommunity2.Degree / fTwoTimesEdgesInGraph;
Single fAk = oOtherCommunity.Degree / fTwoTimesEdgesInGraph;
oNewCommunityPair.DeltaQ =
oCommunity1Values[iCommunity1Index].DeltaQ -
2F * fAj * fAk;
iCommunity1Index++;
}
else
{
// The other community is connected only to commmunity 2.
//
// This is equation 10c from the same paper.
Community oOtherCommunity =
oCommunity2Values[iCommunity2Index].Community2;
oNewCommunityPair.Community2 = oOtherCommunity;
Single fAi = oCommunity1.Degree / fTwoTimesEdgesInGraph;
Single fAk = oOtherCommunity.Degree / fTwoTimesEdgesInGraph;
oNewCommunityPair.DeltaQ =
oCommunity2Values[iCommunity2Index].DeltaQ -
2F * fAi * fAk;
iCommunity2Index++;
}
oNewCommunityCommunityPairs.Add(oNewCommunityPair.Community2.ID,
oNewCommunityPair);
Single fNewCommunityPairDeltaQ = oNewCommunityPair.DeltaQ;
if (fNewCommunityPairDeltaQ > fMaximumDeltaQ)
{
fMaximumDeltaQ = oNewCommunityPair.DeltaQ;
oCommunityPairWithMaximumDeltaQ = oNewCommunityPair;
}
// The other community is connected to one or both of the merged
// communities. Update it.
oNewCommunityPair.Community2.OnMergedCommunities(
oCommunity1, oCommunity2, oNewCommunity,
fNewCommunityPairDeltaQ, oDeltaQMaxHeap);
}
oNewCommunity.CommunityPairWithMaximumDeltaQ =
oCommunityPairWithMaximumDeltaQ;
// Update the community list.
oCommunities.Remove(oCommunity1);
oCommunities.Remove(oCommunity2);
oCommunities.AddLast(oNewCommunity);
// Update the max heap.
oDeltaQMaxHeap.Remove(oCommunity1);
oDeltaQMaxHeap.Remove(oCommunity2);
oDeltaQMaxHeap.Add(oNewCommunity, oNewCommunity.MaximumDeltaQ);
}