void Compute(graph<vertex>& GA, commandLine P) { t10.start(); char* oFile = P.getOptionValue("-out"); //file to write eccentricites srand (time(NULL)); uintT seed = rand(); cout << "seed = " << seed << endl; t0.start(); long n = GA.n; uintE* ecc = newA(uintE,n); {parallel_for(long i=0;i<n;i++) ecc[i] = UINT_E_MAX;} t0.stop(); //BEGIN COMPUTE CONNECTED COMPONENTS t1.start(); intE* Labels = newA(intE,n); {parallel_for(long i=0;i<n;i++) { if(GA.V[i].getOutDegree() == 0) Labels[i] = -i-1; //singletons else Labels[i] = INT_E_MAX; }} //get max degree vertex uintE maxV = sequence::reduce<uintE>((intE)0,(intE)n,maxF<intE>(),getDegree<vertex>(GA.V)); //visit large component with BFS CCBFS(maxV,GA,Labels); //visit small components with label propagation Components(GA, Labels); //sort by component ID intPair* CCpairs = newA(intPair,n); {parallel_for(long i=0;i<n;i++) if(Labels[i] < 0) CCpairs[i] = make_pair(-Labels[i]-1,i); else CCpairs[i] = make_pair(Labels[i],i); } free(Labels); intSort::iSort(CCpairs, n, n+1, firstF<uintE,uintE>()); uintE* changes = newA(uintE,n); changes[0] = 0; {parallel_for(long i=1;i<n;i++) changes[i] = (CCpairs[i].first != CCpairs[i-1].first) ? i : UINT_E_MAX;} uintE* CCoffsets = newA(uintE,n); uintE numCC = sequence::filter(changes, CCoffsets, n, nonMaxF()); CCoffsets[numCC] = n; free(changes); t1.stop(); //END COMPUTE CONNECTED COMPONENTS uintE maxS = min((uintE)n,(uintE)sqrt(n*log2(n))); uintE maxSampleSize = max((uintE)10,max((uintE)((n/maxS)*log2(n)),maxS)); //data structures to be shared by all components uintE** Dists = newA(uintE*,maxSampleSize); uintE* Dist = newA(uintE,maxSampleSize*n); {parallel_for(long i=0;i<maxSampleSize;i++) Dists[i] = Dist+i*n;} {parallel_for(long i=0;i<n*maxSampleSize;i++) Dist[i] = UINT_E_MAX;} intPair* wDist = newA(intPair,n); {parallel_for(long i=0;i<n;i++) wDist[i] = make_pair(UINT_E_MAX,UINT_E_MAX);} intPair* minDists = newA(intPair,n); uintE* starts = newA(uintE,n); uintE* starts2 = newA(uintE,n); uintE* maxDists = newA(uintE,n); //BEGIN COMPUTE ECCENTRICITES PER COMPONENT t4.start(); for(long k = 0; k < numCC; k++) { uintE o = CCoffsets[k]; uintE CCsize = CCoffsets[k+1] - o; if(CCsize == 1) ecc[CCpairs[o].second] = 0; //singletons have ecc of 0 if(CCsize == 2) { //size 2 CC's have ecc of 1 ecc[CCpairs[o].second] = ecc[CCpairs[o+1].second] = 1; } else if(CCsize > 1) { //do main computation t2.start(); uintE s = min(CCsize,(uintE)sqrt(CCsize*log2(CCsize))); //pick sample of about \sqrt{n\log n} vertices long sampleSize = min(CCsize,max((uintE)10,(uintE)((CCsize/s)*log2(CCsize)))); //pick random vertices {parallel_for(ulong i=0;i<CCsize;i++) { //pick with probability sampleSize/CCsize uintT index = hash(i+seed) % CCsize; if(index < sampleSize) starts[i] = CCpairs[o+i].second; else starts[i] = UINT_E_MAX; }} //pack down uintE numUnique = sequence::filter(starts,starts2,CCsize,nonMaxF()); //sample cannot be empty! if(numUnique == 0) { starts2[0] = CCpairs[o+(hash(seed)%CCsize)].second; numUnique++; } if(numUnique > maxSampleSize) numUnique = maxSampleSize; //cap at maxSampleSize t2.stop(); t3.start(); //execute BFS per sample {for(long i=0;i<numUnique;i++) { uintE v = starts2[i]; Dists[i][v] = 0; //set source dist to 0 vertexSubset Frontier(n,v); uintE round = 0; while(!Frontier.isEmpty()){ round++; vertexSubset output = edgeMap(GA, Frontier, BFS_F(Dists[i],round),GA.m/20); Frontier.del(); Frontier = output; } Frontier.del(); ecc[v] = round-1; //set radius for sample vertex }} t3.stop(); t4.start(); //store max distance from sample for each vertex so that we can //reuse Distance arrays {parallel_for(long i=0;i<CCsize;i++) { uintE v = CCpairs[o+i].second; //if not one of the vertices we did BFS on if(ecc[v] == UINT_E_MAX) { uintE max_from_sample = 0; //compute max distance from sampled vertex for(long j=0;j<numUnique;j++) { uintE d = Dists[j][v]; if(d > max_from_sample) max_from_sample = d; } maxDists[i] = max_from_sample; }}} t4.stop(); t5.start(); //find furthest vertex from sample set S {parallel_for(long j=0;j<CCsize;j++) { uintE v = CCpairs[o+j].second; uintE m = UINT_E_MAX; for(long i=0;i<numUnique;i++) { uintE d = Dists[i][v]; if(d < m) m = d; if(d == 0) break; } minDists[j] = make_pair(m,v); }} intPair furthest = sequence::reduce<intPair>(minDists,(intE)CCsize,maxFirstF()); uintE w = furthest.second; t5.stop(); t3.start(); //reset Dist array entries {parallel_for(long i=0;i<numUnique;i++) { parallel_for(long j=0;j<CCsize;j++) { uintE v = CCpairs[o+j].second; Dists[i][v] = UINT_E_MAX; } }} t3.stop(); t6.start(); //execute BFS from w and find \sqrt{n log n} neighborhood of w uintE nghSize = min(CCsize,max((uintE)10,s)); uintE* Ngh_s = starts; //reuse starts array bool filled_Ngh = 0; //stores distance from w and index of closest vertex in Ngh_s on //path from w to v wDist[w] = make_pair(0,0); //set source dist to 0 vertexSubset Frontier(n,w); uintE round = 0; uintE numVisited = 0; while(!Frontier.isEmpty()){ round++; if(!filled_Ngh) { Frontier.toSparse(); //Note: if frontier size < nghSize - visited, there is non-determinism in which vertices //get added to Ngh_s as the ordering of vertices on the frontier is non-deterministic {parallel_for(long i=0;i<min(nghSize-numVisited,(uintE)Frontier.numNonzeros());i++) { Ngh_s[numVisited+i] = Frontier.s[i]; wDist[Frontier.s[i]].second = numVisited+i; } numVisited += Frontier.numNonzeros(); if(numVisited >= nghSize) filled_Ngh = 1; }} vertexSubset output = edgeMap(GA, Frontier, BFS_Pair_F(wDist,round),GA.m/20); Frontier.del(); Frontier = output; } Frontier.del(); ecc[w] = round-1; //set radius for w t6.stop(); t7.start(); //execute BFS from each vertex in neighborhood of w uintE** Dists2 = Dists; //reuse distance array uintE* Dist2 = Dist; {for(long i=0;i<nghSize;i++) { uintE v = Ngh_s[i]; Dists2[i][v] = 0; //set source dist to 0 vertexSubset Frontier(n,v); uintE round = 0; while(!Frontier.isEmpty()){ round++; vertexSubset output = edgeMap(GA, Frontier, BFS_F(Dists2[i],round),GA.m/20); Frontier.del(); Frontier = output; } Frontier.del(); ecc[v] = round-1; //set radius of vertex in Ngh_s }} t7.stop(); t8.start(); //min radius of sample parallel_for(long i=0;i<numUnique;i++) starts2[i] = ecc[starts2[i]]; uintE min_r_sample = sequence::reduce<uintE>(starts2,numUnique,minF<uintE>()); //compute ecc values {parallel_for(long i=0;i<CCsize;i++) { uintE v = CCpairs[o+i].second; //if not one of the vertices we did BFS on if(ecc[v] == UINT_E_MAX) { uintE d_vw = wDist[v].first; uintE rv = max(maxDists[i],d_vw); //index in Ngh_s of closest vertex in Ngh_s on path from w to v uintE index_vt = wDist[v].second; uintE vt = Ngh_s[index_vt]; uintE d_vt_v = Dists2[index_vt][v]; uintE d_vt_w = Dists2[index_vt][w]; if(d_vt_v <= d_vt_w) ecc[v] = max(rv,ecc[vt]); else ecc[v] = max(rv,min_r_sample); } }} t8.stop(); t7.start(); //reset Dist array entries {parallel_for(long i=0;i<nghSize;i++) { parallel_for(long j=0;j<CCsize;j++) { uintE v = CCpairs[o+j].second; Dists2[i][v] = UINT_E_MAX; } }} t7.stop(); t6.start(); //reset wDist array entries {parallel_for(long i=0;i<CCsize;i++) { uintE v = CCpairs[o+i].second; wDist[v] = make_pair(UINT_E_MAX,UINT_E_MAX); }} t6.stop(); }
void Compute(graph<vertex>& GA, commandLine P) { t5.start(); long length = P.getOptionLongValue("-r",0); //number of words per vertex char* oFile = P.getOptionValue("-out"); //file to write eccentricites srand (time(NULL)); uintT seed = rand(); cout << "seed = " << seed << endl; t0.start(); long n = GA.n; uintE* ecc = newA(uintE,n); uintE* ecc2 = newA(uintE,n); {parallel_for(long i=0;i<n;i++) { ecc[i] = ecc2[i] = 0; }} t0.stop(); //BEGIN COMPUTE CONNECTED COMPONENTS t1.start(); intE* Labels = newA(intE,n); {parallel_for(long i=0;i<n;i++) { if(GA.V[i].getOutDegree() == 0) Labels[i] = -i-1; //singletons else Labels[i] = INT_E_MAX; }} //get max degree vertex uintE maxV = sequence::reduce<uintE>((intE)0,(intE)n,maxF<intE>(),getDegree<vertex>(GA.V)); //visit large component with BFS CCBFS(maxV,GA,Labels); //visit small components with label propagation Components(GA, Labels); //sort by component ID intPair* CCpairs = newA(intPair,n); {parallel_for(long i=0;i<n;i++) if(Labels[i] < 0) CCpairs[i] = make_pair(-Labels[i]-1,i); else CCpairs[i] = make_pair(Labels[i],i); } free(Labels); intSort::iSort(CCpairs, n, n+1,firstF<uintE,uintE>()); uintE* changes = newA(uintE,n); changes[0] = 0; {parallel_for(long i=1;i<n;i++) changes[i] = (CCpairs[i].first != CCpairs[i-1].first) ? i : UINT_E_MAX;} uintE* CCoffsets = newA(uintE,n); uintE numCC = sequence::filter(changes, CCoffsets, n, nonMaxF()); CCoffsets[numCC] = n; free(changes); t1.stop(); //END COMPUTE CONNECTED COMPONENTS //init data structures t0.start(); length = max((long)1,min((n+63)/64,(long)length)); long* VisitedArray = newA(long,n*length); long* NextVisitedArray = newA(long,n*length); int* flags = newA(int,n); {parallel_for(long i=0;i<n;i++) flags[i] = -1;} uintE* starts = newA(uintE,n); intPair* pairs = newA(intPair,n); t0.stop(); //BEGIN COMPUTE ECCENTRICITES PER COMPONENT for(long k = 0; k < numCC; k++) { t2.start(); uintE o = CCoffsets[k]; uintE CCsize = CCoffsets[k+1] - o; if(CCsize == 2) { //size 2 CC's have ecc of 1 ecc[CCpairs[o].second] = ecc[CCpairs[o+1].second] = 1; t2.stop(); } else if(CCsize > 1) { //size 1 CC's already have ecc of 0 //do main computation long myLength = min((long)length,((long)CCsize+63)/64); //initialize bit vectors for component vertices {parallel_for(long i=0;i<CCsize;i++) { uintT v = CCpairs[o+i].second; parallel_for(long j=0;j<myLength;j++) VisitedArray[v*myLength+j] = NextVisitedArray[v*myLength+j] = 0; }} long sampleSize = min((long)CCsize,(long)64*myLength); uintE* starts2 = newA(uintE,sampleSize); //pick random vertices (could have duplicates) {parallel_for(ulong i=0;i<sampleSize;i++) { uintT index = hashInt(i+seed) % CCsize; if(flags[index] == -1 && CAS(&flags[index],-1,(int)i)) { starts[i] = CCpairs[o+index].second; NextVisitedArray[CCpairs[o+index].second*myLength + i/64] = (long) 1<<(i%64); } else starts[i] = UINT_E_MAX; }} //remove duplicates uintE numUnique = sequence::filter(starts,starts2,sampleSize,nonMaxF()); //reset flags parallel_for(ulong i=0;i<sampleSize;i++) { uintT index = hashInt(i+seed) % CCsize; if(flags[index] == i) flags[index] = -1; } //first phase vertexSubset Frontier(n,numUnique,starts2); //initial frontier //note: starts2 will be freed inside the following loop uintE round = 0; while(!Frontier.isEmpty()){ round++; vertexMap(Frontier, Ecc_Vertex_F(myLength,VisitedArray,NextVisitedArray)); vertexSubset output = edgeMap(GA, Frontier, Ecc_F(myLength,VisitedArray,NextVisitedArray,ecc,round), GA.m/20); Frontier.del(); Frontier = output; } Frontier.del(); t2.stop(); //second phase if size of CC > 64 if(CCsize > 1024) { //sort by ecc t3.start(); {parallel_for(long i=0;i<CCsize;i++) { pairs[i] = make_pair(ecc[CCpairs[o+i].second],CCpairs[o+i].second); }} intPair maxR = sequence::reduce(pairs,CCsize,maxFirstF()); intSort::iSort(pairs, CCsize, 1+maxR.first, firstF<uintE,uintE>()); t3.stop(); t4.start(); //reset bit vectors for component vertices {parallel_for(long i=0;i<CCsize;i++) { uintT v = CCpairs[o+i].second; parallel_for(long j=0;j<myLength;j++) VisitedArray[v*myLength+j] = NextVisitedArray[v*myLength+j] = 0; }} starts2 = newA(uintE,sampleSize); //pick starting points with highest ecc ("fringe" vertices) {parallel_for(long i=0;i<sampleSize;i++) { intE v = pairs[CCsize-i-1].second; starts2[i] = v; NextVisitedArray[v*myLength + i/64] = (long) 1<<(i%64); }} vertexSubset Frontier2(n,sampleSize,starts2); //initial frontier //note: starts2 will be freed inside the following loop round = 0; while(!Frontier2.isEmpty()){ round++; vertexMap(Frontier2, Ecc_Vertex_F(myLength,VisitedArray,NextVisitedArray)); vertexSubset output = edgeMap(GA, Frontier2,Ecc_F(myLength,VisitedArray,NextVisitedArray,ecc2,round), GA.m/20); Frontier2.del(); Frontier2 = output; } Frontier2.del(); {parallel_for(long i=0;i<n;i++) ecc[i] = max(ecc[i],ecc2[i]);} t4.stop(); } }