#include "MatchBoxPC.h" #include #include // *********************************************************************** // // MatchboxP: A C++ library for approximate weighted matching // Mahantesh Halappanavar (hala@pnnl.gov) // Pacific Northwest National Laboratory // // *********************************************************************** // // Copyright (2021) Battelle Memorial Institute // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions // are met: // // 1. Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // // 2. Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // 3. Neither the name of the copyright holder nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE // COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. // // ************************************************************************ ////////////////////////////////////////////////////////////////////////////////////// /////////////////////////// DOMINATING EDGES MODEL /////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////// /* Function : algoDistEdgeApproxDomEdgesLinearSearchMesgBndlSmallMate() * * Date : New update: Feb 17, 2019, Richland, Washington. * Date : Original development: May 17, 2009, E&CS Bldg. * * Purpose : Compute Approximate Maximum Weight Matching in Linear Time * * Args : inputMatrix - instance of Compressed-Col format of Matrix * Mate - The Mate array * * Returns : By Value: (void) * By Reference: Mate * * Comments : 1/2 Approx Algorithm. Picks the locally available heaviest edge. * Assumption: The Mate Array is empty. */ /* NLVer = #of vertices, NLEdge = #of edges CSR/CSC/Compressed format: verLocPtr = Pointer, verLocInd = Index, edgeLocWeight = edge weights (positive real numbers) verDistance = A vector of size |P|+1 containing the cumulative number of vertices per process Mate = A vector of size |V_p| (local subgraph) to store the output (matching) MPI: myRank, numProcs, comm, Statistics: msgIndSent, msgActualSent, msgPercent : Size: |P| number of processes in the comm-world Statistics: ph0_time, ph1_time, ph2_time: Runtimes Statistics: ph1_card, ph2_card : Size: |P| number of processes in the comm-world (number of matched edges in Phase 1 and Phase 2) */ #ifdef SERIAL_MPI #else //MPI type map template MPI_Datatype TypeMap(); template<> inline MPI_Datatype TypeMap() { return MPI_LONG_LONG; } template<> inline MPI_Datatype TypeMap() { return MPI_INT; } template<> inline MPI_Datatype TypeMap() { return MPI_DOUBLE; } template<> inline MPI_Datatype TypeMap() { return MPI_FLOAT; } // DOUBLE PRECISION VERSION //WARNING: The vertex block on a given rank is contiguous void dalgoDistEdgeApproxDomEdgesLinearSearchMesgBndlSmallMateCMP( MilanLongInt NLVer, MilanLongInt NLEdge, MilanLongInt* verLocPtr, MilanLongInt* verLocInd, MilanReal* edgeLocWeight, MilanLongInt* verDistance, MilanLongInt* Mate, MilanInt myRank, MilanInt numProcs, MPI_Comm comm, MilanLongInt* msgIndSent, MilanLongInt* msgActualSent, MilanReal* msgPercent, MilanReal* ph0_time, MilanReal* ph1_time, MilanReal* ph2_time, MilanLongInt* ph1_card, MilanLongInt* ph2_card ) { /* * verDistance: it's a vector long as the number of processors. * verDistance[i] contains the first node index of the i-th processor * verDistance[i + 1] contains the last node index of the i-th processor * NLVer: number of elements in the LocPtr * NLEdge: number of edges assigned to the current processor * * Contains the portion of matrix assigned to the processor in * Yale notation * verLocInd: contains the positions on row of the matrix * verLocPtr: i-th value is the position of the first element on the i-th row and * i+1-th value is the position of the first element on the i+1-th row */ #if !defined(SERIAL_MPI) #ifdef PRINT_DEBUG_INFO_ cout<<"\n("<::iterator verLocPtr = inputSubGraph.getVerPtr_b(); //vector::iterator verLocInd = inputSubGraph.getVerInd_b(); //vector::iterator edgeLocWeight = inputSubGraph.getEdgeWt_b(); //Data structures for sending and receiving messages: vector Message; // [ u, v, message_type ] Message.resize(3,-1); const MilanLongInt REQUEST = 1; const MilanLongInt SUCCESS = 2; const MilanLongInt FAILURE = 3; const MilanLongInt SIZEINFO = 4; MilanLongInt message_type = 0; //Data structures for Message Bundling: //Although up to two messages can be sent along any cross edge, //only one message will be sent in the initialization phase - //one of: REQUEST/FAILURE/SUCCESS vector QLocalVtx, QGhostVtx, QMsgType; vector QOwner; // Changed by Fabio to be an integer, addresses needs to be integers! MilanLongInt* PCounter = new MilanLongInt [numProcs]; for (int i = 0; i < numProcs; i++) PCounter[i] = 0; MilanLongInt NumMessagesBundled; MilanInt ghostOwner; // Changed by Fabio to be an integer, addresses needs to be integers! //vector candidateMate; MilanLongInt* candidateMate = new MilanLongInt[1]; #ifdef PRINT_DEBUG_INFO_ cout<<"\n("< Ghost2LocalMap; //Map each ghost vertex to a local vertex // index that starts with zero to |Vg| - 1 map::iterator storedAlready; vector Counter; //Store the edge count for each ghost vertex MilanLongInt numGhostVertices = 0, numGhostEdges = 0, insertMe = 0; //Number of Ghost vertices #ifdef PRINT_DEBUG_INFO_ cout<<"\n("< verGhostPtr, verGhostInd, tempCounter; //Mate array for ghost vertices: vector GMate; //Proportional to the number of ghost vertices MilanLongInt S; staticQueue U; #ifdef TIME_TRACKER double Ghost2LocalInitialization = MPI_Wtime(); #endif #pragma omp parallel private(insertMe, k, k1, adj1, adj2, adj11, adj12, heaviestEdgeWt, w, ghostOwner) firstprivate(StartIndex, EndIndex) default(shared) num_threads(4) { // TODO comments about the reduction #pragma omp for reduction(+ : numGhostEdges) for (i = 0; i < NLEdge; i++) { //O(m) - Each edge stored twice insertMe = verLocInd[i]; //cout<<"InsertMe on Process "< EndIndex)) { //Find a ghost numGhostEdges++; #pragma omp critical { storedAlready = Ghost2LocalMap.find(insertMe); if (storedAlready != Ghost2LocalMap.end()) { //Has already been added //cout<<"Process "<first<<" - "<second<second]++; //Increment the counter } else { //Insert an entry for the ghost: //cout<<"Process "<second<<" - "<first<<" : "<second]< 0 ) cout< EndIndex)) { //Find a ghost #pragma omp critical { insertMe = verGhostPtr[Ghost2LocalMap[w]] + tempCounter[Ghost2LocalMap[w]]; //Where to insert verGhostInd[insertMe] = v + StartIndex; //Add the adjacency tempCounter[Ghost2LocalMap[w]]++; //Increment the counter } } //End of if((w < StartIndex) || (w > EndIndex)) } //End of for(k) } //End of for (v) #pragma omp single { #ifdef TIME_TRACKER verGhostIndInitialization = MPI_Wtime() - verGhostIndInitialization; fprintf(stderr, "verGhostIndInitialization time: %f\n", verGhostIndInitialization); #endif #ifdef PRINT_DEBUG_INFO_ cout<<"\n("<= 0) { //This piece of code is actually executed under 0.01% of the times #pragma omp critical { if (isAlreadyMatched(k, verLocInd, StartIndex, EndIndex, GMate, Mate, Ghost2LocalMap)) { w = computeCandidateMate(verLocPtr[v], verLocPtr[v + 1], edgeLocWeight, 0, verLocInd, StartIndex, EndIndex, GMate, Mate, Ghost2LocalMap); candidateMate[v] = w; } } if (w >= 0) { myCard++; if ((w < StartIndex) || (w > EndIndex)) { //w is a ghost vertex //Build the Message Packet: //Message[0] = v+StartIndex; //LOCAL //Message[1] = w; //GHOST //Message[2] = REQUEST; //TYPE //Send a Request (Asynchronous) #ifdef PRINT_DEBUG_INFO_ cout<<"\n("< 0) { Counter[Ghost2LocalMap[w]] = Counter[Ghost2LocalMap[w]] - 1; //Decrement if (Counter[Ghost2LocalMap[w]] == 0) { S--; //Decrement S #ifdef PRINT_DEBUG_INFO_ cout<<"\n("< 0 //End: PARALLEL_PROCESS_CROSS_EDGE_B(v) } //End of if CandidateMate[w] = v } // end of critical region } //End of if a Ghost Vertex else { // w is a local vertex if (candidateMate[w - StartIndex] == (v + StartIndex)) { #pragma omp critical { Mate[v] = w; //v is local Mate[w - StartIndex] = v + StartIndex; //w is local //Q.push_back(u); U.push_back(v + StartIndex); U.push_back(w); #ifdef PRINT_DEBUG_INFO_ cout<<"\n("<=0) //if (w < 0) { -- if it arrives here this one if is useless, it is certainly -1 adj11 = verLocPtr[v]; adj12 = verLocPtr[v + 1]; for (k1 = adj11; k1 < adj12; k1++) { w = verLocInd[k1]; if ((w < StartIndex) || (w > EndIndex)) { //A ghost //Build the Message Packet: //Message[0] = v+StartIndex; //LOCAL //Message[1] = w; //GHOST //Message[2] = FAILURE; //TYPE //Send a Request (Asynchronous) #ifdef PRINT_DEBUG_INFO_ cout<<"\n("<= StartIndex) && (u <= EndIndex) ) { //Process Only the Local Vertices //Get the Adjacency list for u adj1 = verLocPtr[u-StartIndex]; //Pointer adj2 = verLocPtr[u-StartIndex+1]; for( k = adj1; k < adj2; k++ ) { v = verLocInd[k]; if ( (v >= StartIndex) && (v <= EndIndex) ) { //If Local Vertex: if ( (vEndIndex) ) { //Is it a ghost vertex? if(GMate[Ghost2LocalMap[v]] >= 0 )// Already matched continue; } else { //A local vertex if( Mate[v-StartIndex] >= 0 ) // Already matched continue; } //End of else #ifdef PRINT_DEBUG_INFO_ cout<<"\n("<EndIndex) ) { //Is it a ghost vertex? if(GMate[Ghost2LocalMap[verLocInd[k1]]] >= 0 )// Already matched continue; } else { //A local vertex if( Mate[verLocInd[k1]-StartIndex] >= 0 ) // Already matched continue; } if( (edgeLocWeight[k1] > heaviestEdgeWt) || ((edgeLocWeight[k1] == heaviestEdgeWt)&&(w < verLocInd[k1])) ) { heaviestEdgeWt = edgeLocWeight[k1]; w = verLocInd[k1]; } } //End of for loop candidateMate[v-StartIndex] = w; //End: PARALLEL_COMPUTE_CANDIDATE_MATE_B(v) #ifdef PRINT_DEBUG_INFO_ cout<<"\n("<= 0 ) { if ( (w < StartIndex) || (w > EndIndex) ) { //A ghost //Build the Message Packet: //Message[0] = v; //LOCAL //Message[1] = w; //GHOST //Message[2] = REQUEST; //TYPE //Send a Request (Asynchronous) #ifdef PRINT_DEBUG_INFO_ cout<<"\n("< 0 ) { Counter[Ghost2LocalMap[w]] = Counter[Ghost2LocalMap[w]] - 1; //Decrement if ( Counter[Ghost2LocalMap[w]] == 0 ) { S--; //Decrement S #ifdef PRINT_DEBUG_INFO_ cout<<"\n("< 0 //End: PARALLEL_PROCESS_CROSS_EDGE_B(v,w) } //End of if CandidateMate[w] = v } //End of if a Ghost Vertex else { //w is a local vertex if ( candidateMate[w-StartIndex] == v ) { Mate[v-StartIndex] = w; //v is a local vertex Mate[w-StartIndex] = v; //w is a local vertex //Q.push_back(u); U.push_back(v); U.push_back(w); myCard++; #ifdef PRINT_DEBUG_INFO_ cout<<"\n("<=0) else { adj11 = verLocPtr[v-StartIndex]; adj12 = verLocPtr[v-StartIndex+1]; for( k1 = adj11; k1 < adj12; k1++ ) { w = verLocInd[k1]; if ( (w < StartIndex) || (w > EndIndex) ) { //A ghost //Build the Message Packet: //Message[0] = v; //LOCAL //Message[1] = w; //GHOST //Message[2] = FAILURE; //TYPE //Send a Request (Asynchronous) #ifdef PRINT_DEBUG_INFO_ cout<<"\n("<= StartIndex) && (v <= EndIndex) ) //If Local Vertex: else { //Neighbor is a ghost vertex if ( candidateMate[NLVer+Ghost2LocalMap[v]] == u ) candidateMate[NLVer+Ghost2LocalMap[v]] = -1; if ( v != Mate[u-StartIndex] ) { //u is local //Build the Message Packet: //Message[0] = u; //LOCAL //Message[1] = v; //GHOST //Message[2] = SUCCESS; //TYPE //Send a Request (Asynchronous) #ifdef PRINT_DEBUG_INFO_ cout<<"\n("<= StartIndex) && (u <= EndIndex) ) //Process Only If a Local Vertex } //End of while ( /*!Q.empty()*/ !U.empty() ) ///////////////////////// END OF PROCESS MATCHED VERTICES ///////////////////////// #ifdef DEBUG_HANG_ if (myRank == 0) cout<<"\n("< PCumulative, PMessageBundle, PSizeInfoMessages; MilanLongInt myIndex=0; try { PMessageBundle.reserve(NumMessagesBundled*3); //Three integers per message PCumulative.reserve(numProcs+1); //Similar to Row Pointer vector in CSR data structure PSizeInfoMessages.reserve(numProcs*3); //Buffer to hold the Size info message packets } catch ( length_error ) { cout<<"Error in function algoDistEdgeApproxDominatingEdgesMessageBundling: \n"; cout<<"Not enough memory to allocate the internal variables \n"; exit(1); } PMessageBundle.resize(NumMessagesBundled*3, -1);//Initialize PCumulative.resize(numProcs+1, 0); //Only initialize the counter variable PSizeInfoMessages.resize(numProcs*3, 0); for (MilanInt i=0; i SRequest; //Requests that are used for each send message vector SStatus; //Status of sent messages, used in MPI_Wait MilanLongInt MessageIndex=0; //Pointer for current message try { SRequest.reserve(numProcs*2); //At most two messages per processor SStatus.reserve(numProcs*2);//At most two messages per processor } catch ( length_error ) { cout<<"Error in function algoDistEdgeApproxDominatingEdgesLinearSearchImmediateSend: \n"; cout<<"Not enough memory to allocate the internal variables \n"; exit(1); } MPI_Request myReq; //A sample request SRequest.resize(numProcs*2,myReq); MPI_Status myStat; //A sample status SStatus.resize(numProcs*2,myStat); //Send the Messages for (MilanInt i=0; i 0 ) { //Send only if it is a nonempty packet MPI_Isend(&PSizeInfoMessages[i*3+0], 3, TypeMap(), i, ComputeTag, comm, &SRequest[MessageIndex]); msgActual++; MessageIndex++; //Now Send the message with the data packet: #ifdef PRINT_DEBUG_INFO_ cout<<"\n("<(), i, BundleTag, comm, &SRequest[MessageIndex]); MessageIndex++; } //End of if size > 0 } //Free up temporary memory: PCumulative.clear(); QLocalVtx.clear(); QGhostVtx.clear(); QMsgType.clear(); QOwner.clear(); #ifdef PRINT_DEBUG_INFO_ cout<<"\n("<(), comm, &OneMessageSize); //Size of one message packet //How many messages to send? //Potentially three kinds of messages will be sent/received: //Request, Success, Failure. //But only two will be sent from a given processor. //Substract the number of messages that have already been sent as bundled messages: MilanLongInt numMessagesToSend = numGhostEdges*2 - NumMessagesBundled; MilanInt BufferSize = (OneMessageSize+MPI_BSEND_OVERHEAD)*numMessagesToSend; MilanLongInt *Buffer=0; #ifdef PRINT_DEBUG_INFO_ cout<<"\n("< 0 ) { Buffer = (MilanLongInt *) malloc(BufferSize); //Allocate memory if ( Buffer == 0 ) { cout<<"Error in function algoDistEdgeApproxDominatingEdgesLinearSearch: \n"; cout<<"Not enough memory to allocate for send buffer on process "< ReceiveBuffer; MilanLongInt bundleSize=0, bundleCounter=0; try { ReceiveBuffer.reserve(numGhostEdges*2*3); //Three integers per cross edge } catch ( length_error ) { cout<<"Error in function algoDistEdgeApproxDominatingEdgesMessageBundling: \n"; cout<<"Not enough memory to allocate the internal variables \n"; exit(1); } while ( true ) { #ifdef DEBUG_HANG_ if (myRank == 0) cout<<"\n("<= StartIndex) && (u <= EndIndex) ) { //Process Only If a Local Vertex //Get the Adjacency list for u adj1 = verLocPtr[u-StartIndex]; //Pointer adj2 = verLocPtr[u-StartIndex+1]; for( k = adj1; k < adj2; k++ ) { v = verLocInd[k]; if ( (v >= StartIndex) && (v <= EndIndex) ) { //v is a Local Vertex: if ( Mate[v-StartIndex] >= 0 ) // v is already matched continue; #ifdef PRINT_DEBUG_INFO_ cout<<"\n("<EndIndex) ) { //Is it a ghost vertex? if(GMate[Ghost2LocalMap[verLocInd[k1]]] >= 0 )// Already matched continue; } else { //A local vertex if( Mate[verLocInd[k1]-StartIndex] >= 0 ) // Already matched continue; } if( (edgeLocWeight[k1] > heaviestEdgeWt) || ((edgeLocWeight[k1] == heaviestEdgeWt)&&(w < verLocInd[k1])) ) { heaviestEdgeWt = edgeLocWeight[k1]; w = verLocInd[k1]; } } //End of for loop candidateMate[v-StartIndex] = w; //End: PARALLEL_COMPUTE_CANDIDATE_MATE_B(v) #ifdef PRINT_DEBUG_INFO_ cout<<"\n("<= 0 ) { if ( (w < StartIndex) || (w > EndIndex) ) { //w is a ghost //Build the Message Packet: Message[0] = v; //LOCAL Message[1] = w; //GHOST Message[2] = REQUEST; //TYPE //Send a Request (Asynchronous) #ifdef PRINT_DEBUG_INFO_ cout<<"\n("<(), ghostOwner, ComputeTag, comm); msgInd++; msgActual++; if ( candidateMate[NLVer+Ghost2LocalMap[w]] == v ) { Mate[v-StartIndex] = w; //v is local GMate[Ghost2LocalMap[w]] = v; //w is ghost //Q.push_back(u); U.push_back(v); U.push_back(w); myCard++; #ifdef PRINT_DEBUG_INFO_ cout<<"\n("< 0 ) { Counter[Ghost2LocalMap[w]] = Counter[Ghost2LocalMap[w]] - 1; //Decrement if ( Counter[Ghost2LocalMap[w]] == 0 ) { S--; //Decrement S #ifdef PRINT_DEBUG_INFO_ cout<<"\n("< 0 //End: PARALLEL_PROCESS_CROSS_EDGE_B(v,w) } //End of if CandidateMate[w] = v } //End of if a Ghost Vertex else { //w is a local vertex if ( candidateMate[w-StartIndex] == v ) { Mate[v-StartIndex] = w; //v is local Mate[w-StartIndex] = v; //w is local //Q.push_back(u); U.push_back(v); U.push_back(w); myCard++; #ifdef PRINT_DEBUG_INFO_ cout<<"\n("<=0) else { //no dominating edge found: w == -1 adj11 = verLocPtr[v-StartIndex]; adj12 = verLocPtr[v-StartIndex+1]; for( k1 = adj11; k1 < adj12; k1++ ) { w = verLocInd[k1]; if ( (w < StartIndex) || (w > EndIndex) ) { //A ghost //Build the Message Packet: Message[0] = v; //LOCAL Message[1] = w; //GHOST Message[2] = FAILURE; //TYPE //Send a Request (Asynchronous) #ifdef PRINT_DEBUG_INFO_ cout<<"\n("<(), ghostOwner, ComputeTag, comm); msgInd++; msgActual++; } //End of if(GHOST) } //End of for loop } // End of Else: w == -1 //End: PARALLEL_PROCESS_EXPOSED_VERTEX_B(v) } //End of If (candidateMate[v-StartIndex] == u) } //End of if ( (v >= StartIndex) && (v <= EndIndex) ) //If Local Vertex: else { //Neighbor v is a ghost vertex if ( candidateMate[NLVer+Ghost2LocalMap[v]] == u ) candidateMate[NLVer+Ghost2LocalMap[v]] = -1; if ( v != Mate[u-StartIndex] ) { //u is a local vertex //Build the Message Packet: Message[0] = u; //LOCAL Message[1] = v; //GHOST Message[2] = SUCCESS; //TYPE //Send a Request (Asynchronous) #ifdef PRINT_DEBUG_INFO_ cout<<"\n("<(), ghostOwner, ComputeTag, comm); msgInd++; msgActual++; #ifdef DEBUG_GHOST_ if ((uEndIndex)) { cout<<"\n("<= StartIndex) && (u <= EndIndex) ) //Process Only If a Local Vertex } //End of while ( /*!Q.empty()*/ !U.empty() ) ///////////////////////// END OF PROCESS MATCHED VERTICES ///////////////////////// //// BREAK IF NO MESSAGES EXPECTED ///////// #ifdef PRINT_DEBUG_INFO_ cout<<"\n("<(), MPI_ANY_SOURCE, ComputeTag, comm, &computeStatus); if (error_codeC != MPI_SUCCESS ) { MPI_Error_string(error_codeC, error_message, &message_length); cout<<"\n*Error in call to MPI_Receive on Slave: "<(), Sender, BundleTag, comm, &computeStatus); if (error_codeC != MPI_SUCCESS ) { MPI_Error_string(error_codeC, error_message, &message_length); cout<<"\n*Error in call to MPI_Receive on processor "<NLVer)) { cout<<"\n("< 0 ) { Counter[Ghost2LocalMap[u]] = Counter[Ghost2LocalMap[u]] - 1; //Decrement if ( Counter[Ghost2LocalMap[u]] == 0 ) { S--; //Decrement S #ifdef PRINT_DEBUG_INFO_ cout<<"\n("< 0 //End: PARALLEL_PROCESS_CROSS_EDGE_B(v,u) } //End of if ( candidateMate[v-StartIndex] == u )e } //End of if ( Mate[v] == -1 ) } //End of REQUEST else { //CASE II: SUCCESS if ( message_type == SUCCESS ) { #ifdef PRINT_DEBUG_INFO_ cout<<"\n("< 0 ) { Counter[Ghost2LocalMap[u]] = Counter[Ghost2LocalMap[u]] - 1; //Decrement if ( Counter[Ghost2LocalMap[u]] == 0 ) { S--; //Decrement S #ifdef PRINT_DEBUG_INFO_ cout<<"\n("< 0 //End: PARALLEL_PROCESS_CROSS_EDGE_B(v,u) #ifdef DEBUG_GHOST_ if ((v<0)||(vNLVer)) { cout<<"\n("<EndIndex) ) { //Is it a ghost vertex? if(GMate[Ghost2LocalMap[verLocInd[k1]]] >= 0 )// Already matched continue; } else { //A local vertex if( Mate[verLocInd[k1]-StartIndex] >= 0 ) // Already matched continue; } if( (edgeLocWeight[k1] > heaviestEdgeWt) || ((edgeLocWeight[k1] == heaviestEdgeWt)&&(w < verLocInd[k1])) ) { heaviestEdgeWt = edgeLocWeight[k1]; w = verLocInd[k1]; } } //End of for loop candidateMate[v-StartIndex] = w; //End: PARALLEL_COMPUTE_CANDIDATE_MATE_B(v) #ifdef PRINT_DEBUG_INFO_ cout<<"\n("<= 0 ) { if ( (w < StartIndex) || (w > EndIndex) ) { //w is a ghost //Build the Message Packet: Message[0] = v; //LOCAL Message[1] = w; //GHOST Message[2] = REQUEST; //TYPE //Send a Request (Asynchronous) #ifdef PRINT_DEBUG_INFO_ cout<<"\n("<(), ghostOwner, ComputeTag, comm); msgInd++; msgActual++; if ( candidateMate[NLVer+Ghost2LocalMap[w]] == v ) { Mate[v-StartIndex] = w; //v is local GMate[Ghost2LocalMap[w]] = v; //w is ghost //Q.push_back(u); U.push_back(v); U.push_back(w); myCard++; #ifdef PRINT_DEBUG_INFO_ cout<<"\n("< 0 ) { Counter[Ghost2LocalMap[w]] = Counter[Ghost2LocalMap[w]] - 1; //Decrement if ( Counter[Ghost2LocalMap[w]] == 0 ) { S--; //Decrement S #ifdef PRINT_DEBUG_INFO_ cout<<"\n("< 0 //End: PARALLEL_PROCESS_CROSS_EDGE_B(v,w) } //End of if CandidateMate[w] = v } //End of if a Ghost Vertex else { //w is a local vertex if ( candidateMate[w-StartIndex] == v ) { Mate[v-StartIndex] = w; //v is local Mate[w-StartIndex] = v; //w is local //Q.push_back(u); U.push_back(v); U.push_back(w); myCard++; #ifdef PRINT_DEBUG_INFO_ cout<<"\n("<=0) else { //No dominant edge found adj11 = verLocPtr[v-StartIndex]; adj12 = verLocPtr[v-StartIndex+1]; for( k1 = adj11; k1 < adj12; k1++ ) { w = verLocInd[k1]; if ( (w < StartIndex) || (w > EndIndex) ) { //A ghost //Build the Message Packet: Message[0] = v; //LOCAL Message[1] = w; //GHOST Message[2] = FAILURE; //TYPE //Send a Request (Asynchronous) #ifdef PRINT_DEBUG_INFO_ cout<<"\n("<(), ghostOwner, ComputeTag, comm); msgInd++; msgActual++; } //End of if(GHOST) } //End of for loop } // End of Else: w == -1 //End: PARALLEL_PROCESS_EXPOSED_VERTEX_B(v) } //End of if ( candidateMate[v-StartIndex] == u ) } //End of if ( Mate[v] == -1 ) } //End of if ( message_type == SUCCESS ) else { //CASE III: FAILURE #ifdef PRINT_DEBUG_INFO_ cout<<"\n("< 0 ) { Counter[Ghost2LocalMap[u]] = Counter[Ghost2LocalMap[u]] - 1; //Decrement if ( Counter[Ghost2LocalMap[u]] == 0 ) { S--; //Decrement S #ifdef PRINT_DEBUG_INFO_ cout<<"\n("< 0 //End: PARALLEL_PROCESS_CROSS_EDGE_B(v,u) } //End of else: CASE III } //End of else: CASE I } //End of if (!MsgQ.empty()) ///////////////////////// END OF PROCESS MESSAGES ///////////////////////////////// #ifdef PRINT_DEBUG_INFO_ cout<<"\n("< 0 ) { MPI_Buffer_detach(&Buffer, &BufferSize); //Detach the Buffer free(Buffer); //Free the memory that was allocated } finishTime = MPI_Wtime(); *ph2_time = finishTime-startTime; //Time taken for Phase-2 *ph2_card = myCard ; //Cardinality at the end of Phase-2 #ifdef PRINT_DEBUG_INFO_ cout<<"\n("< 0) { *msgPercent = ((double)NumMessagesBundled/(double)(msgInd))*100.0; } else { *msgPercent = 0; } #ifdef DEBUG_HANG_ if (myRank == 0) cout<<"\n("< vtxIndex ) End = Current - 1; else //CASE 3: Start = Current + 1; } } //End of While() if ( Current == 0 ) return (Current); else { if ( mVerDistance[Current] > vtxIndex ) return (Current-1); else return (Current); } //End of else return (-1); //It should not reach here! } //End of findOwnerOfGhost() /** * Execute the research fr the Candidate Mate without controlling if the vertices are already matched. * Returns the vertices with the highest weight * @param adj1 * @param adj2 * @param verLocInd * @param edgeLocWeight * @return */ inline MilanLongInt firstComputeCandidateMate(MilanLongInt adj1, MilanLongInt adj2, MilanLongInt* verLocInd, MilanReal* edgeLocWeight) { MilanInt w = -1; MilanReal heaviestEdgeWt = MilanRealMin; //Assign the smallest Value possible first LDBL_MIN int finalK; for (int k = adj1; k < adj2; k++) { if ((edgeLocWeight[k] > heaviestEdgeWt) || ((edgeLocWeight[k] == heaviestEdgeWt) && (w < verLocInd[k]))) { heaviestEdgeWt = edgeLocWeight[k]; w = verLocInd[k]; finalK = k; } } //End of for loop return finalK; } /** * //TODO documentation * @param k * @param verLocInd * @param StartIndex * @param EndIndex * @param GMate * @param Mate * @param Ghost2LocalMap * @return */ inline bool isAlreadyMatched(MilanLongInt k, MilanLongInt* verLocInd, MilanLongInt StartIndex, MilanLongInt EndIndex, vector &GMate, MilanLongInt* Mate, map &Ghost2LocalMap ) { if ((verLocInd[k] < StartIndex) || (verLocInd[k] > EndIndex)) { //Is it a ghost vertex? if (GMate[Ghost2LocalMap[verLocInd[k]]] >= 0)// Already matched return true; } else { //A local vertex if (Mate[verLocInd[k] - StartIndex] >= 0) // Already matched return true; } return false; } /** * //TODO documentation * @param adj1 * @param adj2 * @param edgeLocWeight * @param k * @param verLocInd * @param StartIndex * @param EndIndex * @param GMate * @param Mate * @param Ghost2LocalMap * @return */ inline MilanLongInt computeCandidateMate(MilanLongInt adj1, MilanLongInt adj2, MilanReal* edgeLocWeight, MilanLongInt k, MilanLongInt* verLocInd, MilanLongInt StartIndex, MilanLongInt EndIndex, vector & GMate, MilanLongInt* Mate, map & Ghost2LocalMap) { MilanInt w = -1; MilanReal heaviestEdgeWt = MilanRealMin; //Assign the smallest Value possible first LDBL_MIN for (k = adj1; k < adj2; k++) { if (isAlreadyMatched(k, verLocInd, StartIndex, EndIndex, GMate, Mate, Ghost2LocalMap)) continue; if ((edgeLocWeight[k] > heaviestEdgeWt) || ((edgeLocWeight[k] == heaviestEdgeWt) && (w < verLocInd[k]))) { heaviestEdgeWt = edgeLocWeight[k]; w = verLocInd[k]; } } //End of for loop return w; } #endif #endif