/// Removes any gaps in node labels. ##TPRManager::CheckGap void CheckGap (int GapLabel) { for (TNEANet::TNodeI NI = Net->BegNI(); NI != Net->EndNI(); NI++) { int NId = NI.GetId(); int OldLabel = LabelsV[NId]; if (OldLabel > GapLabel && OldLabel <= LabelLimit) { LabelsV[NId] = MaxLabel; LabelCounts[OldLabel]--; LabelCounts[MaxLabel]++; if (IsActive(NId)) { RemoveActive(NId); } } } LabelLimit = GapLabel - 1; }
TPRManager(PNEANet &Net) : Net(Net), CapIndex(0), FlowV(Net->GetMxEId()), ExcessV(Net->GetMxNId()), EdgeNumsV(Net->GetMxNId()), LabelsV(Net->GetMxNId()), LabelCounts(Net->GetNodes() + 1), LabelLimit(0), MaxLabel(Net->GetNodes()), ActiveNodeSet(Net->GetMxNId()), ActiveCount(0) { CapIndex = Net->GetIntAttrIndE(CapAttrName); for (int i = 0; i <= Net->GetNodes(); i++) { LabelCounts[i] = 0; } for (TNEANet::TEdgeI EI = Net->BegEI(); EI != Net->EndEI(); EI++) { int EId = EI.GetId(); IAssert(Capacity(EId) >= 0); FlowV[EId] = 0; } for (TNEANet::TNodeI NI = Net->BegNI(); NI != Net->EndNI(); NI++) { int NId = NI.GetId(); ExcessV[NId] = 0; EdgeNumsV[NId] = 0; ActiveNodeSet[NId] = 0; } LabelCounts[0] = Net->GetNodes(); }
/// Implements the Global Relabeling heuristic. ##TSnap::GlobalRelabel void GlobalRelabel (PNEANet &Net, TPRManager &PRM, const int& SrcNId, const int& SnkNId) { TIntQ NodeQ; int size = Net->GetMxNId(); TIntV NodeV(size); for (int i = 0; i < size; i++) { NodeV[i] = 0; } NodeQ.Push(SnkNId); NodeV[SnkNId] = 1; int MaxLabel = PRM.GetMaxLabel(); while (!NodeQ.Empty()) { // Backward search int NId = NodeQ.Top(); NodeQ.Pop(); const TNEANet::TNodeI &NI = Net->GetNI(NId); // Check all edges that point out of the current node for those over which flow can be returned. for (int EdgeN = 0; EdgeN < NI.GetOutDeg(); EdgeN++) { int OutNId = NI.GetOutNId(EdgeN); int EId = NI.GetOutEId(EdgeN); if (!NodeV[OutNId] && PRM.Flow(EId) > 0) { NodeV[OutNId] = 1; NodeQ.Push(OutNId); PRM.SetLabel(OutNId, PRM.Label(NId) + 1); } } // Check all edges that point into the current node for those over which flow can be added. for (int EdgeN = 0; EdgeN < NI.GetInDeg(); EdgeN++) { int InNId = NI.GetInNId(EdgeN); int EId = NI.GetInEId(EdgeN); if (!NodeV[InNId] && PRM.Capacity(EId) > PRM.Flow(EId)) { NodeV[InNId] = 1; NodeQ.Push(InNId); PRM.SetLabel(InNId, PRM.Label(NId) + 1); } } } for (TNEANet::TNodeI NI = Net->BegNI(); NI != Net->EndNI(); NI++) { int NId = NI.GetId(); if (NodeV[NId]) { if (PRM.Excess(NId) > 0 && PRM.Label(NId) < MaxLabel && NId != SnkNId) { if (!PRM.IsActive(NId)) { PRM.PushActive(NId); } } } else { if (PRM.IsActive(NId)) { PRM.RemoveActive(NId); } PRM.SetLabel(NId, MaxLabel); } } }
int GetMaxFlowIntPR (PNEANet &Net, const int& SrcNId, const int& SnkNId) { IAssert(Net->IsNode(SrcNId)); IAssert(Net->IsNode(SnkNId)); if (SrcNId == SnkNId) { return 0; } TPRManager PRM(Net); int MaxLabel = PRM.GetMaxLabel(); TNEANet::TNodeI SrcNI = Net->GetNI(SrcNId); for (int EdgeN = 0; EdgeN < SrcNI.GetOutDeg(); EdgeN++) { int EId = SrcNI.GetOutEId(EdgeN); int OutNId = SrcNI.GetOutNId(EdgeN); if (OutNId != SrcNId) { int Capacity = PRM.Capacity(EId); PRM.Flow(EId) = Capacity; PRM.Excess(OutNId) = Capacity; } } GlobalRelabel(Net, PRM, SrcNId, SnkNId); PRM.SetLabel(SrcNId, MaxLabel); int RelabelCount = 1; int GRRate = Net->GetNodes(); while (PRM.HasActive()) { int NId = PRM.PopActive(); const TNEANet::TNodeI &NI = Net->GetNI(NId); int PrevLabel = MaxLabel; while (PRM.Excess(NId) > 0 && PRM.Label(NId) <= PrevLabel) { PrevLabel = PRM.Label(NId); int NbrNId = PushRelabel(PRM, NId, NI); if (NbrNId != -1 && NbrNId != SnkNId && PRM.Excess(NbrNId) > 0 && !PRM.IsActive(NbrNId)) { PRM.PushActive(NbrNId); } } if (PRM.Excess(NId) > 0 && PRM.Label(NId) < MaxLabel) { PRM.PushActive(NId); } if (RelabelCount % GRRate == 0) { GlobalRelabel(Net, PRM, SrcNId, SnkNId); } } return PRM.Excess(SnkNId); }
/// Returns the ID of the neighbor that \c NId pushes to, -1 if no push was made. int PushRelabel (TPRManager &PRM, const int &NId, const TNEANet::TNodeI &NI) { int EdgeN = PRM.EdgeNum(NId); int EId = -1, NbrNId = -1, ResFlow = 0; int Cutoff = NI.GetInDeg(); if (EdgeN < Cutoff) { EId = NI.GetInEId(EdgeN); NbrNId = NI.GetInNId(EdgeN); ResFlow = PRM.Flow(EId); } else { EId = NI.GetOutEId(EdgeN - Cutoff); NbrNId = NI.GetOutNId(EdgeN - Cutoff); ResFlow = PRM.Capacity(EId) - PRM.Flow(EId); } if (ResFlow > 0 && PRM.Label(NId) - 1 == PRM.Label(NbrNId)) { if (EdgeN < Cutoff) { PushToInNbr(PRM, NId, NbrNId, EId); } else { PushToOutNbr(PRM, NId, NbrNId, EId); } return NbrNId; } if (EdgeN + 1 == NI.GetDeg()) { PRM.EdgeNum(NId) = 0; Relabel(PRM, NId, NI); } else { PRM.EdgeNum(NId)++; } return -1; }
int GetWeightedPageRankMP1(const PNEANet Graph, TIntFltH& PRankH, const TStr& Attr, const double& C, const double& Eps, const int& MaxIter) { if (!Graph->IsFltAttrE(Attr)) return -1; TFltV Weights = Graph->GetFltAttrVecE(Attr); int mxid = Graph->GetMxNId(); TFltV OutWeights(mxid); Graph->GetWeightOutEdgesV(OutWeights, Weights); /*for (TNEANet::TNodeI NI = Graph->BegNI(); NI < Graph->EndNI(); NI++) { OutWeights[NI.GetId()] = Graph->GetWeightOutEdges(NI, Attr); }*/ /*TIntFltH Weights; for (TNEANet::TNodeI NI = Graph->BegNI(); NI < Graph->EndNI(); NI++) { Weights.AddDat(NI.GetId(), Graph->GetWeightOutEdges(NI, Attr)); }*/ const int NNodes = Graph->GetNodes(); TVec<TNEANet::TNodeI> NV; //const double OneOver = 1.0/double(NNodes); PRankH.Gen(NNodes); for (TNEANet::TNodeI NI = Graph->BegNI(); NI < Graph->EndNI(); NI++) { NV.Add(NI); PRankH.AddDat(NI.GetId(), 1.0/NNodes); //IAssert(NI.GetId() == PRankH.GetKey(PRankH.Len()-1)); } TFltV TmpV(NNodes); for (int iter = 0; iter < MaxIter; iter++) { #pragma omp parallel for schedule(dynamic,10000) for (int j = 0; j < NNodes; j++) { TNEANet::TNodeI NI = NV[j]; TmpV[j] = 0; for (int e = 0; e < NI.GetInDeg(); e++) { const int InNId = NI.GetInNId(e); const TFlt OutWeight = OutWeights[InNId]; int EId = Graph->GetEId(InNId, NI.GetId()); const TFlt Weight = Weights[Graph->GetFltKeyIdE(EId)]; if (OutWeight > 0) { TmpV[j] += PRankH.GetDat(InNId) * Weight / OutWeight; } } TmpV[j] = C*TmpV[j]; // Berkhin (the correct way of doing it) //TmpV[j] = C*TmpV[j] + (1.0-C)*OneOver; // iGraph } double diff=0, sum=0, NewVal; #pragma omp parallel for reduction(+:sum) schedule(dynamic,10000) for (int i = 0; i < TmpV.Len(); i++) { sum += TmpV[i]; } const double Leaked = (1.0-sum) / double(NNodes); #pragma omp parallel for reduction(+:diff) schedule(dynamic,10000) for (int i = 0; i < PRankH.Len(); i++) { // re-instert leaked PageRank NewVal = TmpV[i] + Leaked; // Berkhin //NewVal = TmpV[i] / sum; // iGraph diff += fabs(NewVal-PRankH[i]); PRankH[i] = NewVal; } if (diff < Eps) { break; } } return 0; }
/// Increases the label of a node \c NId to allow valid pushes to some neighbor. void Relabel (TPRManager &PRM, const int &NId, const TNEANet::TNodeI &NI) { int MaxLabel = PRM.GetMaxLabel(); int MinLabel = MaxLabel; for (int EdgeN = 0; EdgeN < NI.GetInDeg(); EdgeN++) { if (PRM.Flow(NI.GetInEId(EdgeN)) > 0) { int InLabel = PRM.Label(NI.GetInNId(EdgeN)); MinLabel = min(MinLabel, InLabel); } } for (int EdgeN = 0; EdgeN < NI.GetOutDeg(); EdgeN++) { if (PRM.Capacity(NI.GetOutEId(EdgeN)) > PRM.Flow(NI.GetOutEId(EdgeN))) { int OutLabel = PRM.Label(NI.GetOutNId(EdgeN)); MinLabel = min(MinLabel, OutLabel); } } if (MinLabel == MaxLabel) { PRM.SetLabel(NId, MaxLabel); } else { PRM.SetLabel(NId, MinLabel + 1); } }
// Test node, edge creation void ManipulateNodesEdges() { int NNodes = 1000; int NEdges = 100000; const char *FName = "demo.graph.dat"; PNEANet Graph; PNEANet Graph1; PNEANet Graph2; int i; int n; int NCount; int ECount1; int ECount2; int x,y; bool t; Graph = TNEANet::New(); t = Graph->Empty(); // create the nodes for (i = 0; i < NNodes; i++) { Graph->AddNode(i); } n = Graph->GetNodes(); t = Graph->Empty(); // create random edges NCount = NEdges; while (NCount > 0) { x = rand() % NNodes; y = rand() % NNodes; n = Graph->AddEdge(x, y); NCount--; } PrintGStats("ManipulateNodesEdges:Graph",Graph); // get all the nodes NCount = 0; for (TNEANet::TNodeI NI = Graph->BegNI(); NI < Graph->EndNI(); NI++) { NCount++; } // get all the edges for all the nodes ECount1 = 0; for (TNEANet::TNodeI NI = Graph->BegNI(); NI < Graph->EndNI(); NI++) { for (int e = 0; e < NI.GetOutDeg(); e++) { ECount1++; } } // get all the edges directly ECount2 = 0; for (TNEANet::TEdgeI EI = Graph->BegEI(); EI < Graph->EndEI(); EI++) { ECount2++; } printf("graph ManipulateNodesEdges:Graph, nodes %d, edges1 %d, edges2 %d\n", NCount, ECount1, ECount2); // assignment Graph1 = TNEANet::New(); *Graph1 = *Graph; PrintGStats("ManipulateNodesEdges:Graph1",Graph1); // save the graph { TFOut FOut(FName); Graph->Save(FOut); FOut.Flush(); } // load the graph { TFIn FIn(FName); Graph2 = TNEANet::Load(FIn); } PrintGStats("ManipulateNodesEdges:Graph2",Graph2); // remove all the nodes and edges for (i = 0; i < NNodes; i++) { n = Graph->GetRndNId(); Graph->DelNode(n); } PrintGStats("ManipulateNodesEdges:Graph",Graph); Graph1->Clr(); PrintGStats("ManipulateNodesEdges:Graph1",Graph1); }
int GetWeightedPageRankMP2(const PNEANet Graph, TIntFltH& PRankH, const TStr& Attr, const double& C, const double& Eps, const int& MaxIter) { if (!Graph->IsFltAttrE(Attr)) return -1; const int NNodes = Graph->GetNodes(); TVec<TNEANet::TNodeI> NV; //const double OneOver = 1.0/double(NNodes); PRankH.Gen(NNodes); int MxId; for (TNEANet::TNodeI NI = Graph->BegNI(); NI < Graph->EndNI(); NI++) { NV.Add(NI); PRankH.AddDat(NI.GetId(), 1.0/NNodes); int Id = NI.GetId(); if (Id > MxId) { MxId = Id; } } TFltV PRankV(MxId+1); TFltV OutWeights(MxId+1); TFltV Weights = Graph->GetFltAttrVecE(Attr); #pragma omp parallel for schedule(dynamic,10000) for (int j = 0; j < NNodes; j++) { TNEANet::TNodeI NI = NV[j]; int Id = NI.GetId(); OutWeights[Id] = Graph->GetWeightOutEdges(NI, Attr); PRankV[Id] = 1/NNodes; } TFltV TmpV(NNodes); for (int iter = 0; iter < MaxIter; iter++) { #pragma omp parallel for schedule(dynamic,10000) for (int j = 0; j < NNodes; j++) { TNEANet::TNodeI NI = NV[j]; TFlt Tmp = 0; for (int e = 0; e < NI.GetInDeg(); e++) { const int InNId = NI.GetInNId(e); const TFlt OutWeight = OutWeights[InNId]; int EId = Graph->GetEId(InNId, NI.GetId()); const TFlt Weight = Weights[Graph->GetFltKeyIdE(EId)]; if (OutWeight > 0) { Tmp += PRankH.GetDat(InNId) * Weight / OutWeight; } } TmpV[j] = C*Tmp; // Berkhin (the correct way of doing it) //TmpV[j] = C*TmpV[j] + (1.0-C)*OneOver; // iGraph } double sum = 0; #pragma omp parallel for reduction(+:sum) schedule(dynamic,10000) for (int i = 0; i < TmpV.Len(); i++) { sum += TmpV[i]; } const double Leaked = (1.0-sum) / double(NNodes); double diff = 0; #pragma omp parallel for reduction(+:diff) schedule(dynamic,10000) for (int i = 0; i < NNodes; i++) { TNEANet::TNodeI NI = NV[i]; double NewVal = TmpV[i] + Leaked; // Berkhin //NewVal = TmpV[i] / sum; // iGraph int Id = NI.GetId(); diff += fabs(NewVal-PRankV[Id]); PRankV[Id] = NewVal; } if (diff < Eps) { break; } } #pragma omp parallel for schedule(dynamic,10000) for (int i = 0; i < NNodes; i++) { TNEANet::TNodeI NI = NV[i]; PRankH[i] = PRankV[NI.GetId()]; } return 0; }
// Test node, edge creation TEST(TNEANet, ManipulateNodesEdges) { int NNodes = 1000; int NEdges = 100000; const char *FName = "test.graph.dat"; PNEANet Graph; PNEANet Graph1; PNEANet Graph2; int i; int n; int NCount; int x,y; int Deg, InDeg, OutDeg; Graph = TNEANet::New(); EXPECT_EQ(1,Graph->Empty()); // create the nodes for (i = 0; i < NNodes; i++) { Graph->AddNode(i); } EXPECT_EQ(0,Graph->Empty()); EXPECT_EQ(NNodes,Graph->GetNodes()); // create random edges NCount = NEdges; while (NCount > 0) { x = (long) (drand48() * NNodes); y = (long) (drand48() * NNodes); n = Graph->AddEdge(x, y); NCount--; } EXPECT_EQ(NEdges,Graph->GetEdges()); EXPECT_EQ(0,Graph->Empty()); EXPECT_EQ(1,Graph->IsOk()); for (i = 0; i < NNodes; i++) { EXPECT_EQ(1,Graph->IsNode(i)); } EXPECT_EQ(0,Graph->IsNode(NNodes)); EXPECT_EQ(0,Graph->IsNode(NNodes+1)); EXPECT_EQ(0,Graph->IsNode(2*NNodes)); // nodes iterator NCount = 0; for (TNEANet::TNodeI NI = Graph->BegNI(); NI < Graph->EndNI(); NI++) { NCount++; } EXPECT_EQ(NNodes,NCount); // edges per node iterator NCount = 0; for (TNEANet::TNodeI NI = Graph->BegNI(); NI < Graph->EndNI(); NI++) { for (int e = 0; e < NI.GetOutDeg(); e++) { NCount++; } } EXPECT_EQ(NEdges,NCount); // edges iterator NCount = 0; for (TNEANet::TEdgeI EI = Graph->BegEI(); EI < Graph->EndEI(); EI++) { NCount++; } EXPECT_EQ(NEdges,NCount); // node degree for (TNEANet::TNodeI NI = Graph->BegNI(); NI < Graph->EndNI(); NI++) { Deg = NI.GetDeg(); InDeg = NI.GetInDeg(); OutDeg = NI.GetOutDeg(); EXPECT_EQ(Deg,InDeg+OutDeg); } // assignment Graph1 = TNEANet::New(); *Graph1 = *Graph; EXPECT_EQ(NNodes,Graph1->GetNodes()); EXPECT_EQ(NEdges,Graph1->GetEdges()); EXPECT_EQ(0,Graph1->Empty()); EXPECT_EQ(1,Graph1->IsOk()); // saving and loading { TFOut FOut(FName); Graph->Save(FOut); FOut.Flush(); } { TFIn FIn(FName); Graph2 = TNEANet::Load(FIn); } EXPECT_EQ(NNodes,Graph2->GetNodes()); EXPECT_EQ(NEdges,Graph2->GetEdges()); EXPECT_EQ(0,Graph2->Empty()); EXPECT_EQ(1,Graph2->IsOk()); // remove all the nodes and edges for (i = 0; i < NNodes; i++) { n = Graph->GetRndNId(); Graph->DelNode(n); } EXPECT_EQ(0,Graph->GetNodes()); EXPECT_EQ(0,Graph->GetEdges()); EXPECT_EQ(1,Graph->IsOk()); EXPECT_EQ(1,Graph->Empty()); Graph1->Clr(); EXPECT_EQ(0,Graph1->GetNodes()); EXPECT_EQ(0,Graph1->GetEdges()); EXPECT_EQ(1,Graph1->IsOk()); EXPECT_EQ(1,Graph1->Empty()); }