int main(int argc, char* argv[]) { Env = TEnv(argc, argv, TNotify::StdNotify); Env.PrepArgs(TStr::Fmt("ragm. build: %s, %s. Time: %s", __TIME__, __DATE__, TExeTm::GetCurTm())); TExeTm ExeTm; Try TStr OutFPrx = Env.GetIfArgPrefixStr("-o:", "", "Output Graph data prefix"); const TStr InFNm = Env.GetIfArgPrefixStr("-i:", "../as20graph.txt", "Input edgelist file name"); const TStr LabelFNm = Env.GetIfArgPrefixStr("-l:", "", "Input file name for node names (Node ID, Node label) "); int OptComs = Env.GetIfArgPrefixInt("-c:", -1, "The number of communities to detect (-1: detect automatically)"); const int MinComs = Env.GetIfArgPrefixInt("-mc:", 5, "Minimum number of communities to try"); const int MaxComs = Env.GetIfArgPrefixInt("-xc:", 100, "Maximum number of communities to try"); const int DivComs = Env.GetIfArgPrefixInt("-nc:", 10, "How many trials for the number of communities"); const int NumThreads = Env.GetIfArgPrefixInt("-nt:", 1, "Number of threads for parallelization"); const double StepAlpha = Env.GetIfArgPrefixFlt("-sa:", 0.3, "Alpha for backtracking line search"); const double StepBeta = Env.GetIfArgPrefixFlt("-sb:", 0.3, "Beta for backtracking line search"); PUNGraph G; TIntStrH NIDNameH; if (InFNm.IsStrIn(".ungraph")) { TFIn GFIn(InFNm); G = TUNGraph::Load(GFIn); } else { G = TAGMUtil::LoadEdgeListStr<PUNGraph>(InFNm, NIDNameH); } if (LabelFNm.Len() > 0) { TSsParser Ss(LabelFNm, ssfTabSep); while (Ss.Next()) { if (Ss.Len() > 0) { NIDNameH.AddDat(Ss.GetInt(0), Ss.GetFld(1)); } } } else { } printf("Graph: %d Nodes %d Edges\n", G->GetNodes(), G->GetEdges()); TVec<TIntV> EstCmtyVV; TExeTm RunTm; TAGMFast RAGM(G, 10, 10); if (OptComs == -1) { printf("finding number of communities\n"); OptComs = RAGM.FindComsByCV(NumThreads, MaxComs, MinComs, DivComs, OutFPrx, StepAlpha, StepBeta); } RAGM.NeighborComInit(OptComs); if (NumThreads == 1 || G->GetEdges() < 1000) { RAGM.MLEGradAscent(0.0001, 1000 * G->GetNodes(), "", StepAlpha, StepBeta); } else { RAGM.MLEGradAscentParallel(0.0001, 1000, NumThreads, "", StepAlpha, StepBeta); } RAGM.GetCmtyVV(EstCmtyVV); TAGMUtil::DumpCmtyVV(OutFPrx + "cmtyvv.txt", EstCmtyVV, NIDNameH); TAGMUtil::SaveGephi(OutFPrx + "graph.gexf", G, EstCmtyVV, 1.5, 1.5, NIDNameH); Catch printf("\nrun time: %s (%s)\n", ExeTm.GetTmStr(), TSecTm::GetCurTm().GetTmStr().CStr()); return 0; }
// Test node subgraph conversion void TestConvertSubGraphs() { PNGraph NGraph; PUNGraph UNGraph; int N1, N2, N3; int E1, E2, E3; TIntV NIdV; int i; NGraph = GetTestTNGraph(); N1 = NGraph->GetNodes(); E1 = NGraph->GetEdges(); for (i = 0; i < 20; i += 2) { NIdV.Add(i); } // TODO: fix TSnap::ConvertSubGraph<PUNGraph>(NGraph, NIdV, true), it fails // UNGraph = TSnap::ConvertSubGraph<PUNGraph>(NGraph, NIdV, true); UNGraph = TSnap::ConvertSubGraph<PUNGraph>(NGraph, NIdV); N2 = UNGraph->GetNodes(); E2 = UNGraph->GetEdges(); NGraph = TSnap::ConvertSubGraph<PNGraph>(UNGraph, NIdV); N3 = NGraph->GetNodes(); E3 = NGraph->GetEdges(); printf("---- TestConvertSubGraphs -----\n"); printf("nodes: %d,%d,%d, edges: %d,%d,%d\n", N1, N2, N3, E1, E2, E3); printf("\n"); }
///Generate graph using the AGM model. CProbV = vector of Pc PUNGraph TAGM::GenAGM(TVec<TIntV>& CmtyVV, const TFltV& CProbV, TRnd& Rnd, const double PNoCom) { PUNGraph G = TUNGraph::New(100 * CmtyVV.Len(), -1); printf("AGM begins\n"); for (int i = 0; i < CmtyVV.Len(); i++) { TIntV& CmtyV = CmtyVV[i]; for (int u = 0; u < CmtyV.Len(); u++) { if ( G->IsNode(CmtyV[u])) { continue; } G->AddNode(CmtyV[u]); } double Prob = CProbV[i]; RndConnectInsideCommunity(G, CmtyV, Prob, Rnd); } if (PNoCom > 0.0) { //if we want to connect nodes that do not share any community TIntSet NIDS; for (int c = 0; c < CmtyVV.Len(); c++) { for (int u = 0; u < CmtyVV[c].Len(); u++) { NIDS.AddKey(CmtyVV[c][u]); } } TIntV NIDV; NIDS.GetKeyV(NIDV); RndConnectInsideCommunity(G,NIDV,PNoCom,Rnd); } printf("AGM completed (%d nodes %d edges)\n",G->GetNodes(),G->GetEdges()); G->Defrag(); return G; }
/// Clique Percolation method communities void TCliqueOverlap::GetCPMCommunities(const PUNGraph& G, int MinMaxCliqueSize, TVec<TIntV>& NIdCmtyVV) { printf("Clique Percolation Method\n"); TExeTm ExeTm; TVec<TIntV> MaxCliques; TCliqueOverlap::GetMaxCliques(G, MinMaxCliqueSize, MaxCliques); // op RS 2012/05/15, commented out next line, a parameter is missing, // creating a warning on OS X // printf("...%d cliques found\n"); // get clique overlap matrix (graph) PUNGraph OverlapGraph = TCliqueOverlap::CalculateOverlapMtx(MaxCliques, MinMaxCliqueSize-1); printf("...overlap matrix (%d, %d)\n", G->GetNodes(), G->GetEdges()); // connected components are communities TCnComV CnComV; TSnap::GetWccs(OverlapGraph, CnComV); NIdCmtyVV.Clr(false); TIntSet CmtySet; for (int c = 0; c < CnComV.Len(); c++) { CmtySet.Clr(false); for (int i = 0; i <CnComV[c].Len(); i++) { const TIntV& CliqueNIdV = MaxCliques[CnComV[c][i]]; CmtySet.AddKeyV(CliqueNIdV); } NIdCmtyVV.Add(); CmtySet.GetKeyV(NIdCmtyVV.Last()); NIdCmtyVV.Last().Sort(); } printf("done [%s].\n", ExeTm.GetStr()); }
double TAGMUtil::GetConductance(const PUNGraph& Graph, const TIntSet& CmtyS, const int Edges) { const int Edges2 = Edges >= 0 ? 2*Edges : Graph->GetEdges(); int Vol = 0, Cut = 0; double Phi = 0.0; for (int i = 0; i < CmtyS.Len(); i++) { if (! Graph->IsNode(CmtyS[i])) { continue; } TUNGraph::TNodeI NI = Graph->GetNI(CmtyS[i]); for (int e = 0; e < NI.GetOutDeg(); e++) { if (! CmtyS.IsKey(NI.GetOutNId(e))) { Cut += 1; } } Vol += NI.GetOutDeg(); } // get conductance if (Vol != Edges2) { if (2 * Vol > Edges2) { Phi = Cut / double (Edges2 - Vol); } else if (Vol == 0) { Phi = 0.0; } else { Phi = Cut / double(Vol); } } else { if (Vol == Edges2) { Phi = 1.0; } } return Phi; }
///////////////////////////////////////////////// // Spectral graph properties void PlotEigValRank(const PUNGraph& Graph, const int& EigVals, const TStr& FNmPref, TStr DescStr) { TFltV EigValV; TSnap::GetEigVals(Graph, EigVals, EigValV); EigValV.Sort(false); if (DescStr.Empty()) { DescStr = FNmPref; } TGnuPlot::PlotValV(EigValV, "eigVal."+FNmPref, TStr::Fmt("%s. G(%d, %d). Largest eig val = %f", DescStr.CStr(), Graph->GetNodes(), Graph->GetEdges(), EigValV[0].Val), "Rank", "Eigen value", gpsLog10XY, false, gpwLinesPoints); }
// Inverse participation ratio: normalize EigVec to have L2=1 and then I=sum_k EigVec[i]^4 // see Spectra of "real-world" graphs: Beyond the semicircle law by Farkas, Derenyi, Barabasi and Vicsek void PlotInvParticipRat(const PUNGraph& Graph, const int& MaxEigVecs, const int& TimeLimit, const TStr& FNmPref, TStr DescStr) { TFltPrV EigIprV; GetInvParticipRat(Graph, MaxEigVecs, TimeLimit, EigIprV); if (DescStr.Empty()) { DescStr = FNmPref; } if (EigIprV.Empty()) { DescStr+=". FAIL"; EigIprV.Add(TFltPr(-1,-1)); return; } TGnuPlot::PlotValV(EigIprV, "eigIPR."+FNmPref, TStr::Fmt("%s. G(%d, %d). Largest eig val = %f (%d values)", DescStr.CStr(), Graph->GetNodes(), Graph->GetEdges(), EigIprV.Last().Val1(), EigIprV.Len()), "Eigenvalue", "Inverse Participation Ratio of corresponding Eigenvector", gpsLog10Y, false, gpwPoints); }
// Test the default constructor TEST(TUNGraph, DefaultConstructor) { PUNGraph Graph; Graph = TUNGraph::New(); EXPECT_EQ(0,Graph->GetNodes()); EXPECT_EQ(0,Graph->GetEdges()); EXPECT_EQ(1,Graph->IsOk()); EXPECT_EQ(1,Graph->Empty()); EXPECT_EQ(0,Graph->HasFlag(gfDirected)); }
// Test small graph TEST(TUNGraph, GetSmallGraph) { PUNGraph Graph; Graph = TUNGraph::GetSmallGraph(); EXPECT_EQ(5,Graph->GetNodes()); EXPECT_EQ(5,Graph->GetEdges()); EXPECT_EQ(1,Graph->IsOk()); EXPECT_EQ(0,Graph->Empty()); EXPECT_EQ(0,Graph->HasFlag(gfDirected)); }
int main(int argc, char* argv[]) { Env = TEnv(argc, argv, TNotify::StdNotify); Env.PrepArgs(TStr::Fmt("Cascades. build: %s, %s. Time: %s", __TIME__, __DATE__, TExeTm::GetCurTm())); TExeTm ExeTm; Try const TStr InFNm = Env.GetIfArgPrefixStr("-i:", "demo", "Input undirected graph"); const TStr OutFNm = Env.GetIfArgPrefixStr("-o:", "demo", "Output file name prefix"); const double Beta = Env.GetIfArgPrefixFlt("-b:", 0.1, "Beta (infection (i.e., cascade propagation) probability)"); // load printf("Loading %s...", InFNm.CStr()); PUNGraph Graph; if (InFNm == "demo") { Graph = TSnap::GenRndGnm<PUNGraph>(100, 200); } else { Graph = TSnap::LoadEdgeList<PUNGraph>(InFNm); } printf("nodes:%d edges:%d\n", Graph->GetNodes(), Graph->GetEdges()); // Simulate SI model Graph = TSnap::GetMxWcc(Graph); bool DivByM = true; TCascadeStat CascStat; printf("\nGraph:%s -- Beta: %g\n", OutFNm.CStr(), Beta); for (int Run = 0; Run < 10; Run++) { // number of runs TIntH NIdInfTmH; // incluence cascade PNGraph InfCasc = RunSICascade(Graph, Beta, 100, NIdInfTmH); if (InfCasc->GetNodes() < 10) { printf("."); continue; } // min cascade size // network cascade PNGraph NetCasc = AddSpuriousEdges(Graph, InfCasc, NIdInfTmH); // sample the cascade CascStat.SampleCascade(InfCasc, NetCasc, NIdInfTmH, 0.1, 10, DivByM); // div-by-M printf("."); } CascStat.PlotAll(TStr::Fmt("%s-B%03d", OutFNm.CStr(), int(100*Beta)), TStr::Fmt("%s N=%d E=%d Beta=%g", OutFNm.CStr(), Graph->GetNodes(), Graph->GetEdges(), Beta), DivByM); Catch printf("\nrun time: %s (%s)\n", ExeTm.GetTmStr(), TSecTm::GetCurTm().GetTmStr().CStr()); return 0; }
int main(int argc, char* argv[]) { Env = TEnv(argc, argv, TNotify::StdNotify); Env.PrepArgs(TStr::Fmt("Network community detection. build: %s, %s. Time: %s", __TIME__, __DATE__, TExeTm::GetCurTm())); TExeTm ExeTm; Try const TStr InFNm = Env.GetIfArgPrefixStr("-i:", "graph.txt", "Input graph (undirected graph)"); const TStr OutFNm = Env.GetIfArgPrefixStr("-o:", "communities.txt", "Output file"); const int CmtyAlg = Env.GetIfArgPrefixInt("-a:", 2, "Algorithm: 1:Girvan-Newman, 2:Clauset-Newman-Moore, 3:Infomap"); PUNGraph Graph = TSnap::LoadEdgeList<PUNGraph>(InFNm, false); //PUNGraph Graph = TSnap::LoadEdgeList<PUNGraph>("../as20graph.txt", false); //PUNGraph Graph = TSnap::GenRndGnm<PUNGraph>(5000, 10000); // generate a random graph TSnap::DelSelfEdges(Graph); TCnComV CmtyV; double Q = 0.0; TStr CmtyAlgStr; if (CmtyAlg == 1) { CmtyAlgStr = "Girvan-Newman"; Q = TSnap::CommunityGirvanNewman(Graph, CmtyV); } else if (CmtyAlg == 2) { CmtyAlgStr = "Clauset-Newman-Moore"; Q = TSnap::CommunityCNM(Graph, CmtyV); } else if (CmtyAlg == 3) { CmtyAlgStr = "Infomap"; Q = TSnap::Infomap(Graph, CmtyV); } else { Fail; } FILE *F = fopen(OutFNm.CStr(), "wt"); fprintf(F, "# Input: %s\n", InFNm.CStr()); fprintf(F, "# Nodes: %d Edges: %d\n", Graph->GetNodes(), Graph->GetEdges()); fprintf(F, "# Algoritm: %s\n", CmtyAlgStr.CStr()); if (CmtyAlg!=3) { fprintf(F, "# Modularity: %f\n", Q); } else { fprintf(F, "# Average code length: %f\n", Q); } fprintf(F, "# Communities: %d\n", CmtyV.Len()); fprintf(F, "# NId\tCommunityId\n"); for (int c = 0; c < CmtyV.Len(); c++) { for (int i = 0; i < CmtyV[c].Len(); i++) { fprintf(F, "%d\t%d\n", CmtyV[c][i].Val, c); } } fclose(F); Catch printf("\nrun time: %s (%s)\n", ExeTm.GetTmStr(), TSecTm::GetCurTm().GetTmStr().CStr()); return 0; }
// Test graph conversion TEST(subgraph, TestConvertGraphs) { PNGraph NGraph; PUNGraph UNGraph; NGraph = GetTestTNGraph(); EXPECT_EQ(20,NGraph->GetNodes()); EXPECT_EQ(60,NGraph->GetEdges()); UNGraph = TSnap::ConvertGraph<PUNGraph>(NGraph); EXPECT_EQ(20,UNGraph->GetNodes()); EXPECT_EQ(60,UNGraph->GetEdges()); NGraph = TSnap::ConvertGraph<PNGraph>(UNGraph); EXPECT_EQ(20,NGraph->GetNodes()); EXPECT_EQ(120,NGraph->GetEdges()); }
double GetAsstyCor(const PUNGraph& Graph) { TIntFltH deg(Graph->GetNodes()), deg_sq(Graph->GetNodes()); for (TUNGraph::TNodeI NI = Graph->BegNI(); NI < Graph->EndNI(); NI++) { deg.AddDat(NI.GetId()) = NI.GetOutDeg(); deg_sq.AddDat(NI.GetId()) = NI.GetOutDeg() * NI.GetOutDeg(); } double m = Graph->GetEdges(), num1 = 0.0, num2 = 0.0, den1 = 0.0; for (TUNGraph::TEdgeI EI = Graph->BegEI(); EI < Graph->EndEI(); EI++) { double t1 = deg.GetDat(EI.GetSrcNId()).Val, t2 = deg.GetDat(EI.GetDstNId()).Val; num1 += t1 * t2; num2 += t1 + t2; den1 += deg_sq.GetDat(EI.GetSrcNId()).Val + deg_sq.GetDat(EI.GetDstNId()).Val; } num1 /= m; den1 /= (2.0 * m); num2 = (num2 / (2.0 * m)) * (num2 / (2.0 * m)); return (num1 - num2) / (den1 - num2); }
/// Rewire the network. Keeps node degrees as is but randomly rewires the edges. /// Use this function to generate a random graph with the same degree sequence /// as the OrigGraph. /// See: On the uniform generation of random graphs with prescribed degree /// sequences by R. Milo, N. Kashtan, S. Itzkovitz, M. E. J. Newman, U. Alon /// URL: http://arxiv.org/abs/cond-mat/0312028 PUNGraph GenRewire(const PUNGraph& OrigGraph, const int& NSwitch, TRnd& Rnd) { const int Nodes = OrigGraph->GetNodes(); const int Edges = OrigGraph->GetEdges(); PUNGraph GraphPt = TUNGraph::New(); TUNGraph& Graph = *GraphPt; Graph.Reserve(Nodes, -1); TExeTm ExeTm; // generate a graph that satisfies the constraints printf("Randomizing edges (%d, %d)...\n", Nodes, Edges); TIntPrSet EdgeSet(Edges); for (TUNGraph::TNodeI NI = OrigGraph->BegNI(); NI < OrigGraph->EndNI(); NI++) { const int NId = NI.GetId(); for (int e = 0; e < NI.GetOutDeg(); e++) { if (NId <= NI.GetOutNId(e)) { continue; } EdgeSet.AddKey(TIntPr(NId, NI.GetOutNId(e))); } Graph.AddNode(NI.GetId()); } // edge switching uint skip=0; for (uint swps = 0; swps < 2*uint(Edges)*uint(NSwitch); swps++) { const int keyId1 = EdgeSet.GetRndKeyId(Rnd); const int keyId2 = EdgeSet.GetRndKeyId(Rnd); if (keyId1 == keyId2) { skip++; continue; } const TIntPr& E1 = EdgeSet[keyId1]; const TIntPr& E2 = EdgeSet[keyId2]; TIntPr NewE1(E1.Val1, E2.Val1), NewE2(E1.Val2, E2.Val2); if (NewE1.Val1 > NewE1.Val2) { Swap(NewE1.Val1, NewE1.Val2); } if (NewE2.Val1 > NewE2.Val2) { Swap(NewE2.Val1, NewE2.Val2); } if (NewE1!=NewE2 && NewE1.Val1!=NewE1.Val2 && NewE2.Val1!=NewE2.Val2 && ! EdgeSet.IsKey(NewE1) && ! EdgeSet.IsKey(NewE2)) { EdgeSet.DelKeyId(keyId1); EdgeSet.DelKeyId(keyId2); EdgeSet.AddKey(TIntPr(NewE1)); EdgeSet.AddKey(TIntPr(NewE2)); } else { skip++; } if (swps % Edges == 0) { printf("\r %uk/%uk: %uk skip [%s]", swps/1000u, 2*uint(Edges)*uint(NSwitch)/1000u, skip/1000u, ExeTm.GetStr()); if (ExeTm.GetSecs() > 2*3600) { printf(" *** Time limit!\n"); break; } // time limit 2 hours } } printf("\r total %uk switchings attempted, %uk skiped [%s]\n", 2*uint(Edges)*uint(NSwitch)/1000u, skip/1000u, ExeTm.GetStr()); for (int e = 0; e < EdgeSet.Len(); e++) { Graph.AddEdge(EdgeSet[e].Val1, EdgeSet[e].Val2); } return GraphPt; }
void Init(const PUNGraph& Graph) { const double M = 0.5/Graph->GetEdges(); // 1/2m Q = 0.0; for (TUNGraph::TNodeI NI = Graph->BegNI(); NI < Graph->EndNI(); NI++) { CmtyIdUF.Add(NI.GetId()); const int OutDeg = NI.GetOutDeg(); if (OutDeg == 0) { continue; } TCmtyDat& Dat = CmtyQH.AddDat(NI.GetId(), TCmtyDat(M * OutDeg, OutDeg)); for (int e = 0; e < NI.GetOutDeg(); e++) { const int DstNId = NI.GetOutNId(e); const double DstMod = 2 * M * (1.0 - OutDeg * Graph->GetNI(DstNId).GetOutDeg() * M); Dat.AddQ(DstNId, DstMod); } Q += -1.0*TMath::Sqr(OutDeg*M); if (NI.GetId() < Dat.GetMxQNId()) { MxQHeap.Add(TFltIntIntTr(Dat.GetMxQ(), NI.GetId(), Dat.GetMxQNId())); } } MxQHeap.MakeHeap(); }
void PlotEigValDistr(const PUNGraph& Graph, const int& EigVals, const TStr& FNmPref, TStr DescStr) { const int NBuckets = 50; TFltV EigValV; for (int f = 1; EigValV.Empty() && f < 4; f++) { TSnap::GetEigVals(Graph, f*EigVals, EigValV); } EigValV.Sort(true); THash<TFlt, TFlt> BucketCntH; double Step = (EigValV.Last()-EigValV[0]) / double(NBuckets-1); for (int i = 0; i < NBuckets; i++) { BucketCntH.AddDat(EigValV[0]+Step*(i+0.5), 0); } for (int i = 0; i < EigValV.Len(); i++) { const int Bucket = (int) floor((EigValV[i]-EigValV[0]) / Step); BucketCntH[Bucket] += 1; } TFltPrV EigCntV; BucketCntH.GetKeyDatPrV(EigCntV); if (DescStr.Empty()) { DescStr = FNmPref; } TGnuPlot::PlotValV(EigCntV, "eigDistr."+FNmPref, TStr::Fmt("%s. G(%d, %d). Largest eig val = %f", DescStr.CStr(), Graph->GetNodes(), Graph->GetEdges(), EigValV.Last().Val), "Eigen value", "Count", gpsAuto, false, gpwLinesPoints); }
// Maximum modularity clustering by Girvan-Newman algorithm (slow) // Girvan M. and Newman M. E. J., Community structure in social and biological networks, Proc. Natl. Acad. Sci. USA 99, 7821–7826 (2002) double CommunityGirvanNewman(PUNGraph& Graph, TCnComV& CmtyV) { TIntH OutDegH; const int NEdges = Graph->GetEdges(); for (TUNGraph::TNodeI NI = Graph->BegNI(); NI < Graph->EndNI(); NI++) { OutDegH.AddDat(NI.GetId(), NI.GetOutDeg()); } double BestQ = -1; // modularity TCnComV CurCmtyV; CmtyV.Clr(); TIntV Cmty1, Cmty2; while (true) { CmtyGirvanNewmanStep(Graph, Cmty1, Cmty2); const double Q = _GirvanNewmanGetModularity(Graph, OutDegH, NEdges, CurCmtyV); //printf("current modularity: %f\n", Q); if (Q > BestQ) { BestQ = Q; CmtyV.Swap(CurCmtyV); } if (Cmty1.Len()==0 || Cmty2.Len() == 0) { break; } } return BestQ; }
PUNGraph TAGM::GenAGM(TVec<TIntV>& CmtyVV, const double& DensityCoef, const double& ScaleCoef, TRnd& Rnd){ TFltV CProbV; double Prob; for(int i=0;i<CmtyVV.Len();i++) { Prob = ScaleCoef*pow(double(CmtyVV[i].Len()),-DensityCoef); if(Prob>1){Prob = 1;} CProbV.Add(Prob); } PUNGraph G = TUNGraph::New(); printf("AGM begins\n"); for(int i=0;i<CmtyVV.Len();i++) { TIntV& CmtyV = CmtyVV[i]; for(int u=0;u<CmtyV.Len();u++) { G->AddNode(CmtyV[u]); } Prob = CProbV[i]; printf("\r%d(%d)/%d",i,CmtyVV[i].Len(),CmtyVV.Len()); RndConnectInsideCommunity(G,CmtyV,Prob,Rnd); } printf("AGM completed (%d nodes %d edges)\n",G->GetNodes(),G->GetEdges()); return G; }
// Test graph conversion void TestConvertGraphs() { PNGraph NGraph; PUNGraph UNGraph; int N1, N2, N3; int E1, E2, E3; NGraph = GetTestTNGraph(); N1 = NGraph->GetNodes(); E1 = NGraph->GetEdges(); UNGraph = TSnap::ConvertGraph<PUNGraph>(NGraph); N2 = UNGraph->GetNodes(); E2 = UNGraph->GetEdges(); NGraph = TSnap::ConvertGraph<PNGraph>(UNGraph); N3 = NGraph->GetNodes(); E3 = NGraph->GetEdges(); printf("---- TestConvertGraphs -----\n"); printf("nodes: %d,%d,%d, edges: %d,%d,%d\n", N1, N2, N3, E1, E2, E3); printf("\n"); }
// Test subgraphs TEST(subgraph, TestSubTUNGraphs) { PUNGraph Graph; PUNGraph Graph1; PUNGraph Graph2; PUNGraph Graph3; PUNGraph Graph4; int i; TIntV NIdV; TIntV NIdV1; Graph = GetTestTUNGraph(); EXPECT_EQ(20,Graph->GetNodes()); EXPECT_EQ(60,Graph->GetEdges()); for (i = 10; i < 15; i++) { NIdV.Add(i); } Graph1 = TSnap::GetSubGraph(Graph, NIdV); EXPECT_EQ(5,Graph1->GetNodes()); EXPECT_EQ(9,Graph1->GetEdges()); Graph2 = TSnap::GetSubGraph(Graph, NIdV, true); EXPECT_EQ(5,Graph2->GetNodes()); EXPECT_EQ(9,Graph2->GetEdges()); for (i = 0; i < 20; i += 2) { NIdV1.Add(i); } Graph3 = TSnap::GetSubGraph(Graph, NIdV1, true); EXPECT_EQ(10,Graph3->GetNodes()); EXPECT_EQ(10,Graph3->GetEdges()); Graph4 = TSnap::GetSubGraphRenumber(Graph, NIdV1); EXPECT_EQ(10,Graph4->GetNodes()); EXPECT_EQ(10,Graph4->GetEdges()); }
// Test node subgraph conversion TEST(subgraph, TestConvertSubGraphs) { PNGraph NGraph; PUNGraph UNGraph; TIntV NIdV; int i; NGraph = GetTestTNGraph(); EXPECT_EQ(20,NGraph->GetNodes()); EXPECT_EQ(60,NGraph->GetEdges()); for (i = 0; i < 20; i += 2) { NIdV.Add(i); } // TODO: fix TSnap::ConvertSubGraph<PUNGraph>(NGraph, NIdV, true), it fails // UNGraph = TSnap::ConvertSubGraph<PUNGraph>(NGraph, NIdV, true); UNGraph = TSnap::ConvertSubGraph<PUNGraph>(NGraph, NIdV); EXPECT_EQ(10,UNGraph->GetNodes()); EXPECT_EQ(10,UNGraph->GetEdges()); NGraph = TSnap::ConvertSubGraph<PNGraph>(UNGraph, NIdV); EXPECT_EQ(10,NGraph->GetNodes()); EXPECT_EQ(20,NGraph->GetEdges()); }
int main(int argc, char* argv[]) { Env = TEnv(argc, argv, TNotify::StdNotify); Env.PrepArgs(TStr::Fmt("cesna. build: %s, %s. Time: %s", __TIME__, __DATE__, TExeTm::GetCurTm())); TExeTm ExeTm; Try TStr OutFPrx = Env.GetIfArgPrefixStr("-o:", "", "Output Graph data prefix"); const TStr InFNm = Env.GetIfArgPrefixStr("-i:", "./1912.edges", "Input edgelist file name"); const TStr LabelFNm = Env.GetIfArgPrefixStr("-l:", "", "Input file name for node names (Node ID, Node label) "); const TStr AttrFNm = Env.GetIfArgPrefixStr("-a:", "./1912.nodefeat", "Input node attribute file name"); const TStr ANameFNm = Env.GetIfArgPrefixStr("-n:", "./1912.nodefeatnames", "Input file name for node attribute names"); int OptComs = Env.GetIfArgPrefixInt("-c:", 10, "The number of communities to detect (-1: detect automatically)"); const int MinComs = Env.GetIfArgPrefixInt("-mc:", 3, "Minimum number of communities to try"); const int MaxComs = Env.GetIfArgPrefixInt("-xc:", 20, "Maximum number of communities to try"); const int DivComs = Env.GetIfArgPrefixInt("-nc:", 5, "How many trials for the number of communities"); const int NumThreads = Env.GetIfArgPrefixInt("-nt:", 4, "Number of threads for parallelization"); const double AttrWeight = Env.GetIfArgPrefixFlt("-aw:", 0.5, "We maximize (1 - aw) P(Network) + aw * P(Attributes)"); const double LassoWeight = Env.GetIfArgPrefixFlt("-lw:", 1.0, "Weight for l-1 regularization on learning the logistic model parameters"); const double StepAlpha = Env.GetIfArgPrefixFlt("-sa:", 0.05, "Alpha for backtracking line search"); const double StepBeta = Env.GetIfArgPrefixFlt("-sb:", 0.3, "Beta for backtracking line search"); const double MinFeatFrac = Env.GetIfArgPrefixFlt("-mf:", 0.0, "If the fraction of nodes with positive values for an attribute is smaller than this, we ignore that attribute"); #ifdef USE_OPENMP omp_set_num_threads(NumThreads); #endif PUNGraph G; TIntStrH NIDNameH; TStrHash<TInt> NodeNameH; TVec<TFltV> Wck; TVec<TIntV> EstCmtyVV; if (InFNm.IsStrIn(".ungraph")) { TFIn GFIn(InFNm); G = TUNGraph::Load(GFIn); } else { G = TAGMUtil::LoadEdgeListStr<PUNGraph>(InFNm, NodeNameH); NIDNameH.Gen(NodeNameH.Len()); for (int s = 0; s < NodeNameH.Len(); s++) { NIDNameH.AddDat(s, NodeNameH.GetKey(s)); } } if (LabelFNm.Len() > 0) { TSsParser Ss(LabelFNm, ssfTabSep); while (Ss.Next()) { if (Ss.Len() > 0) { NIDNameH.AddDat(Ss.GetInt(0), Ss.GetFld(1)); } } } printf("Graph: %d Nodes %d Edges\n", G->GetNodes(), G->GetEdges()); //load attribute TIntV NIDV; G->GetNIdV(NIDV); THash<TInt, TIntV> RawNIDAttrH, NIDAttrH; TIntStrH RawFeatNameH, FeatNameH; if (ANameFNm.Len() > 0) { TSsParser Ss(ANameFNm, ssfTabSep); while (Ss.Next()) { if (Ss.Len() > 0) { RawFeatNameH.AddDat(Ss.GetInt(0), Ss.GetFld(1)); } } } TCesnaUtil::LoadNIDAttrHFromNIDKH(NIDV, AttrFNm, RawNIDAttrH, NodeNameH); TCesnaUtil::FilterLowEntropy(RawNIDAttrH, NIDAttrH, RawFeatNameH, FeatNameH, MinFeatFrac); TExeTm RunTm; TCesna CS(G, NIDAttrH, 10, 10); if (OptComs == -1) { printf("finding number of communities\n"); OptComs = CS.FindComs(NumThreads, MaxComs, MinComs, DivComs, "", false, 0.1, StepAlpha, StepBeta); } CS.NeighborComInit(OptComs); CS.SetWeightAttr(AttrWeight); CS.SetLassoCoef(LassoWeight); if (NumThreads == 1 || G->GetEdges() < 1000) { CS.MLEGradAscent(0.0001, 1000 * G->GetNodes(), "", StepAlpha, StepBeta); } else { CS.MLEGradAscentParallel(0.0001, 1000, NumThreads, "", StepAlpha, StepBeta); } CS.GetCmtyVV(EstCmtyVV, Wck); TAGMUtil::DumpCmtyVV(OutFPrx + "cmtyvv.txt", EstCmtyVV, NIDNameH); FILE* F = fopen((OutFPrx + "weights.txt").CStr(), "wt"); if (FeatNameH.Len() == Wck[0].Len()) { fprintf(F, "#"); for (int k = 0; k < FeatNameH.Len(); k++) { fprintf(F, "%s", FeatNameH[k].CStr()); if (k < FeatNameH.Len() - 1) { fprintf(F, "\t"); } } fprintf(F, "\n"); } for (int c = 0; c < Wck.Len(); c++) { for (int k = 0; k < Wck[c].Len(); k++) { fprintf(F, "%f", Wck[c][k].Val); if (k < Wck[c].Len() - 1) { fprintf(F, "\t"); } } fprintf(F, "\n"); } fclose(F); Catch printf("\nrun time: %s (%s)\n", ExeTm.GetTmStr(), TSecTm::GetCurTm().GetTmStr().CStr()); return 0; }
// Print graph statistics void PrintGStats(const char s[], PUNGraph Graph) { printf("graph %s, nodes %d, edges %d, empty %s\n", s, Graph->GetNodes(), Graph->GetEdges(), Graph->Empty() ? "yes" : "no"); }
PUNGraph TAGM::GenAGM(TVec<TIntV>& CmtyVV, const double& DensityCoef, const int TargetEdges, TRnd& Rnd) { PUNGraph TryG = TAGM::GenAGM(CmtyVV, DensityCoef, 1.0, Rnd); const double ScaleCoef = (double) TargetEdges / (double) TryG->GetEdges(); return TAGM::GenAGM(CmtyVV, DensityCoef, ScaleCoef, Rnd); }
/// estimate number of communities using AGM int TAGMUtil::FindComsByAGM(const PUNGraph& Graph, const int InitComs, const int MaxIter, const int RndSeed, const double RegGap, const double PNoCom, const TStr PltFPrx) { TRnd Rnd(RndSeed); int LambdaIter = 100; if (Graph->GetNodes() < 200) { LambdaIter = 1; } if (Graph->GetNodes() < 200 && Graph->GetEdges() > 2000) { LambdaIter = 100; } //Find coms with large C TAGMFit AGMFitM(Graph, InitComs, RndSeed); if (PNoCom > 0.0) { AGMFitM.SetPNoCom(PNoCom); } AGMFitM.RunMCMC(MaxIter, LambdaIter, ""); int TE = Graph->GetEdges(); TFltV RegV; RegV.Add(0.3 * TE); for (int r = 0; r < 25; r++) { RegV.Add(RegV.Last() * RegGap); } TFltPrV RegComsV, RegLV, RegBICV; TFltV LV, BICV; //record likelihood and number of communities with nonzero P_c for (int r = 0; r < RegV.Len(); r++) { double RegCoef = RegV[r]; AGMFitM.SetRegCoef(RegCoef); AGMFitM.MLEGradAscentGivenCAG(0.01, 1000); AGMFitM.SetRegCoef(0.0); TVec<TIntV> EstCmtyVV; AGMFitM.GetCmtyVV(EstCmtyVV, 0.99); int NumLowQ = EstCmtyVV.Len(); RegComsV.Add(TFltPr(RegCoef, (double) NumLowQ)); if (EstCmtyVV.Len() > 0) { TAGMFit AFTemp(Graph, EstCmtyVV, Rnd); AFTemp.MLEGradAscentGivenCAG(0.001, 1000); double CurL = AFTemp.Likelihood(); LV.Add(CurL); BICV.Add(-2.0 * CurL + (double) EstCmtyVV.Len() * log((double) Graph->GetNodes() * (Graph->GetNodes() - 1) / 2.0)); } else { break; } } // if likelihood does not exist or does not change at all, report the smallest number of communities or 2 if (LV.Len() == 0) { return 2; } else if (LV[0] == LV.Last()) { return (int) TMath::Mx<TFlt>(2.0, RegComsV[LV.Len() - 1].Val2); } //normalize likelihood and BIC to 0~100 int MaxL = 100; { TFltV& ValueV = LV; TFltPrV& RegValueV = RegLV; double MinValue = TFlt::Mx, MaxValue = TFlt::Mn; for (int l = 0; l < ValueV.Len(); l++) { if (ValueV[l] < MinValue) { MinValue = ValueV[l]; } if (ValueV[l] > MaxValue) { MaxValue = ValueV[l]; } } while (ValueV.Len() < RegV.Len()) { ValueV.Add(MinValue); } double RangeVal = MaxValue - MinValue; for (int l = 0; l < ValueV.Len(); l++) { RegValueV.Add(TFltPr(RegV[l], double(MaxL) * (ValueV[l] - MinValue) / RangeVal)); } } { TFltV& ValueV = BICV; TFltPrV& RegValueV = RegBICV; double MinValue = TFlt::Mx, MaxValue = TFlt::Mn; for (int l = 0; l < ValueV.Len(); l++) { if (ValueV[l] < MinValue) { MinValue = ValueV[l]; } if (ValueV[l] > MaxValue) { MaxValue = ValueV[l]; } } while (ValueV.Len() < RegV.Len()) { ValueV.Add(MaxValue); } double RangeVal = MaxValue - MinValue; for (int l = 0; l < ValueV.Len(); l++) { RegValueV.Add(TFltPr(RegV[l], double(MaxL) * (ValueV[l] - MinValue) / RangeVal)); } } //fit logistic regression to normalized likelihood. TVec<TFltV> XV(RegLV.Len()); TFltV YV (RegLV.Len()); for (int l = 0; l < RegLV.Len(); l++) { XV[l] = TFltV::GetV(log(RegLV[l].Val1)); YV[l] = RegLV[l].Val2 / (double) MaxL; } TFltPrV LRVScaled, LRV; TLogRegFit LRFit; PLogRegPredict LRMd = LRFit.CalcLogRegNewton(XV, YV, PltFPrx); for (int l = 0; l < RegLV.Len(); l++) { LRV.Add(TFltPr(RegV[l], LRMd->GetCfy(XV[l]))); LRVScaled.Add(TFltPr(RegV[l], double(MaxL) * LRV.Last().Val2)); } //estimate # communities from fitted logistic regression int NumComs = 0, IdxRegDrop = 0; double LRThres = 1.1, RegDrop; // 1 / (1 + exp(1.1)) = 0.25 double LeftReg = 0.0, RightReg = 0.0; TFltV Theta; LRMd->GetTheta(Theta); RegDrop = (- Theta[1] - LRThres) / Theta[0]; if (RegDrop <= XV[0][0]) { NumComs = (int) RegComsV[0].Val2; } else if (RegDrop >= XV.Last()[0]) { NumComs = (int) RegComsV.Last().Val2; } else { //interpolate for RegDrop for (int i = 0; i < XV.Len(); i++) { if (XV[i][0] > RegDrop) { IdxRegDrop = i; break; } } if (IdxRegDrop == 0) { printf("Error!! RegDrop:%f, Theta[0]:%f, Theta[1]:%f\n", RegDrop, Theta[0].Val, Theta[1].Val); for (int l = 0; l < RegLV.Len(); l++) { printf("X[%d]:%f, Y[%d]:%f\n", l, XV[l][0].Val, l, YV[l].Val); } } IAssert(IdxRegDrop > 0); LeftReg = RegDrop - XV[IdxRegDrop - 1][0]; RightReg = XV[IdxRegDrop][0] - RegDrop; NumComs = (int) TMath::Round( (RightReg * RegComsV[IdxRegDrop - 1].Val2 + LeftReg * RegComsV[IdxRegDrop].Val2) / (LeftReg + RightReg)); } //printf("Interpolation coeff: %f, %f, index at drop:%d (%f), Left-Right Vals: %f, %f\n", LeftReg, RightReg, IdxRegDrop, RegDrop, RegComsV[IdxRegDrop - 1].Val2, RegComsV[IdxRegDrop].Val2); printf("Num Coms:%d\n", NumComs); if (NumComs < 2) { NumComs = 2; } if (PltFPrx.Len() > 0) { TStr PlotTitle = TStr::Fmt("N:%d, E:%d ", Graph->GetNodes(), TE); TGnuPlot GPC(PltFPrx + ".l"); GPC.AddPlot(RegComsV, gpwLinesPoints, "C"); GPC.AddPlot(RegLV, gpwLinesPoints, "likelihood"); GPC.AddPlot(RegBICV, gpwLinesPoints, "BIC"); GPC.AddPlot(LRVScaled, gpwLinesPoints, "Sigmoid (scaled)"); GPC.SetScale(gpsLog10X); GPC.SetTitle(PlotTitle); GPC.SavePng(PltFPrx + ".l.png"); } return NumComs; }
void GetMotifCount(const PUNGraph& G, const int MotifSize, TVec <int64> & MotifV, const int num) { if (MotifSize == 3) { MotifV = TVec <int64> (2); MotifV.PutAll(0); TSnap::GetTriads(G,MotifV[mtThreeClosed],MotifV[mtThreeOpen],num); } else { MotifV = TVec <int64> (6); MotifV.PutAll(0); TIntPrV V(G->GetEdges(), 0); for (TUNGraph::TEdgeI EI = G->BegEI(); EI < G->EndEI(); EI++) { V.Add(TIntPr(EI.GetSrcNId(), EI.GetDstNId())); } TRnd blargh; V.Shuffle(blargh); for (int z = 0; z < num; z++) { int SrcNId = V[z].Val1.Val, DstNId = V[z].Val2.Val; TUNGraph::TNodeI SrcNI = G->GetNI(SrcNId), DstNI = G->GetNI(DstNId); TIntV SrcV(SrcNI.GetOutDeg(),0), DstV(DstNI.GetOutDeg(),0), BothV(min(SrcNI.GetOutDeg(), DstNI.GetOutDeg()),0); SrcV.Clr(0,-1); DstV.Clr(0,-1); BothV.Clr(0,-1); //Grouping the vertices into sets for (int e = 0; e < SrcNI.GetOutDeg(); e++) { if (SrcNI.GetOutNId(e) == DstNId) continue; if (G->IsEdge(DstNId, SrcNI.GetOutNId(e)) ) { BothV.Add(SrcNI.GetOutNId(e)); } else { SrcV.Add(SrcNI.GetOutNId(e)); } } for (int e = 0; e < DstNI.GetOutDeg(); e++) { if (DstNI.GetOutNId(e) == SrcNId) continue; if (G->IsEdge(SrcNId, DstNI.GetOutNId(e)) == 0) { DstV.Add(DstNI.GetOutNId(e)); } } //Compute Motif 0 and 1 for (int i = 0; i < SrcV.Len(); i++) { for (int j = 0; j < DstV.Len(); j++) { if (G->IsEdge(SrcV[i], DstV[j]) ) { MotifV[mfFourSquare]++; } else MotifV[mfFourLine]++; } } //Compute Motif 2 and 3 for (int i = 0; i < SrcV.Len(); i++) { for (int j = i + 1; j < SrcV.Len(); j++) { if (G->IsEdge(SrcV[i], SrcV[j]) ) { MotifV[mfFourTriangleEdge]++; } else MotifV[mfFourStar]++; } } for (int i = 0; i < DstV.Len(); i++) { for (int j = i + 1; j < DstV.Len(); j++) { if (G->IsEdge(DstV[i], DstV[j]) ) { MotifV[mfFourTriangleEdge]++; } else MotifV[mfFourStar]++; } } //Compute Motif 4 and 5 for (int i = 0; i < BothV.Len(); i++) { for (int j = i + 1; j < BothV.Len(); j++) { if (G->IsEdge(BothV[i], BothV[j]) ) { MotifV[mfFourComplete]++; } else MotifV[mfFourSquareDiag]++; } } } MotifV[mfFourSquare] /= 4ll; MotifV[mfFourStar] /= 3ll; MotifV[mfFourComplete] /= 6ll; } }
int main(int argc, char* argv[]) { Env = TEnv(argc, argv, TNotify::StdNotify); Env.PrepArgs(TStr::Fmt("cpm. build: %s, %s. Time: %s", __TIME__, __DATE__, TExeTm::GetCurTm())); TExeTm ExeTm; Try TStr OutFPrx = Env.GetIfArgPrefixStr("-o:", "", "Output file name prefix"); const TStr InFNm = Env.GetIfArgPrefixStr("-i:", "football.edgelist", "Input edgelist file name. DEMO: AGM with 2 communities"); const TStr LabelFNm = Env.GetIfArgPrefixStr("-l:", "football.labels", "Input file name for node names (Node ID, Node label) "); const TInt RndSeed = Env.GetIfArgPrefixInt("-s:", 0, "Random seed for AGM"); const TFlt Epsilon = Env.GetIfArgPrefixFlt("-e:", 0, "Edge probability between the nodes that do not share any community (default (0.0): set it to be 1 / N^2)"); const TInt Coms = Env.GetIfArgPrefixInt("-c:", 0, "Number of communities (0: determine it by AGM)"); PUNGraph G = TUNGraph::New(); TVec<TIntV> CmtyVV; TIntStrH NIDNameH; if (InFNm == "DEMO") { TVec<TIntV> TrueCmtyVV; TRnd AGMRnd(RndSeed); //generate community bipartite affiliation const int ABegin = 0, AEnd = 70, BBegin = 30, BEnd = 100; TrueCmtyVV.Add(TIntV()); TrueCmtyVV.Add(TIntV()); for (int u = ABegin; u < AEnd; u++) { TrueCmtyVV[0].Add(u); } for (int u = BBegin; u < BEnd; u++) { TrueCmtyVV[1].Add(u); } G = TAGM::GenAGM(TrueCmtyVV, 0.0, 0.2, AGMRnd); } else if (LabelFNm.Len() > 0) { G = TSnap::LoadEdgeList<PUNGraph>(InFNm); TSsParser Ss(LabelFNm, ssfTabSep); while (Ss.Next()) { if (Ss.Len() > 0) { NIDNameH.AddDat(Ss.GetInt(0), Ss.GetFld(1)); } } } else { G = TAGMUtil::LoadEdgeListStr<PUNGraph>(InFNm, NIDNameH); } printf("Graph: %d Nodes %d Edges\n", G->GetNodes(), G->GetEdges()); int MaxIter = 50 * G->GetNodes() * G->GetNodes(); if (MaxIter < 0) { MaxIter = TInt::Mx; } int NumComs = Coms; if (NumComs < 2) { int InitComs; if (G->GetNodes() > 1000) { InitComs = G->GetNodes() / 5; NumComs = TAGMUtil::FindComsByAGM(G, InitComs, MaxIter, RndSeed, 1.5, Epsilon, OutFPrx); } else { InitComs = G->GetNodes() / 5; NumComs = TAGMUtil::FindComsByAGM(G, InitComs, MaxIter, RndSeed, 1.2, Epsilon, OutFPrx); } } TAGMFit AGMFit(G, NumComs, RndSeed); if (Epsilon > 0) { AGMFit.SetPNoCom(Epsilon); } AGMFit.RunMCMC(MaxIter, 10); AGMFit.GetCmtyVV(CmtyVV, 0.9999); TAGMUtil::DumpCmtyVV(OutFPrx + "cmtyvv.txt", CmtyVV, NIDNameH); TAGMUtil::SaveGephi(OutFPrx + "graph.gexf", G, CmtyVV, 1.5, 1.5, NIDNameH); AGMFit.PrintSummary(); Catch printf("\nrun time: %s (%s)\n", ExeTm.GetTmStr(), TSecTm::GetCurTm().GetTmStr().CStr()); return 0; }
// Test node, edge creation TEST(TUNGraph, ManipulateNodesEdges) { int NNodes = 10000; int NEdges = 100000; const char *FName = "test.graph"; PUNGraph Graph; PUNGraph Graph1; PUNGraph Graph2; int i; int n; int NCount; int x,y; int Deg, InDeg, OutDeg; Graph = TUNGraph::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); // Graph->GetEdges() is not correct for the loops (x == y), // skip the loops in this test if (x != y && !Graph->IsEdge(x,y)) { 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 (TUNGraph::TNodeI NI = Graph->BegNI(); NI < Graph->EndNI(); NI++) { NCount++; } EXPECT_EQ(NNodes,NCount); // edges per node iterator NCount = 0; for (TUNGraph::TNodeI NI = Graph->BegNI(); NI < Graph->EndNI(); NI++) { for (int e = 0; e < NI.GetOutDeg(); e++) { NCount++; } } EXPECT_EQ(NEdges*2,NCount); // edges iterator NCount = 0; for (TUNGraph::TEdgeI EI = Graph->BegEI(); EI < Graph->EndEI(); EI++) { NCount++; } EXPECT_EQ(NEdges,NCount); // node degree for (TUNGraph::TNodeI NI = Graph->BegNI(); NI < Graph->EndNI(); NI++) { Deg = NI.GetDeg(); InDeg = NI.GetInDeg(); OutDeg = NI.GetOutDeg(); EXPECT_EQ(Deg,InDeg); EXPECT_EQ(Deg,OutDeg); } // assignment Graph1 = TUNGraph::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 = TUNGraph::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()); }