Esempio n. 1
0
//' C++ wrapper for Gale-Shapley Algorithm
//'
//' This function provides an R wrapper for the C++ backend. Users should not
//' call this function directly and instead use
//' \code{\link{galeShapley.marriageMarket}} or
//' \code{\link{galeShapley.collegeAdmissions}}.
//'
//' @param proposerPref is a matrix with the preference order of the proposing
//'   side of the market. If there are \code{n} proposers and \code{m} reviewers
//'   in the market, then this matrix will be of dimension \code{m} by \code{n}.
//'   The \code{i,j}th element refers to \code{j}'s \code{i}th most favorite
//'   partner. Preference orders must be complete and specified using C++
//'   indexing (starting at 0).
//' @param reviewerUtils is a matrix with cardinal utilities of the courted side
//'   of the market. If there are \code{n} proposers and \code{m} reviewers, then
//'   this matrix will be of dimension \code{n} by \code{m}. The \code{i,j}th
//'   element refers to the payoff that individual \code{j} receives from being
//'   matched to individual \code{i}.
//'  @return  A list with elements that specify who is matched to whom. Suppose
//'    there are \code{n} proposers and \code{m} reviewers. The list contains
//'    the following items:
//'   \itemize{
//'    \item{\code{proposals} is a vector of length \code{n} whose \code{i}th
//'    element contains the number of the reviewer that proposer \code{i} is
//'    matched to using C++ indexing. Proposers that remain unmatched will be
//'    listed as being matched to \code{m}.}
//'    \item{\code{engagements} is a vector of length \code{m} whose \code{j}th
//'    element contains the number of the proposer that reviewer \code{j} is
//'    matched to using C++ indexing. Reviwers that remain unmatched will be
//'    listed as being matched to \code{n}.}
//'   }
// [[Rcpp::export]]
List cpp_wrapper_galeshapley(const umat& proposerPref, const mat& reviewerUtils) {

    // number of proposers (men)
    int M = proposerPref.n_cols;
    
    // number of reviewers (women)
    int N = proposerPref.n_rows;
    
    // initialize engagements, proposals
    vec engagements(N), proposals(M);
    
    // create an integer queue of bachelors 
    // the idea of using queues for this problem is borrowed from
    // http://rosettacode.org/wiki/Stable_marriage_problem#C.2B.2B
    queue<int> bachelors;
    
    // set all proposals to N (aka no proposals)
    proposals.fill(N);
    
    // set all engagements to M (aka no engagements)
    engagements.fill(M);
    
    // every proposer starts out as a bachelor
    for(int iX=M-1; iX >= 0; iX--) {
        bachelors.push(iX);
    }

    // loop until there are no more proposals to be made
    while (!bachelors.empty()) {
        
        // get the index of the proposer
        int proposer = bachelors.front();
        
        // get the proposer's preferences: we use a raw pointer to the memory 
        // used by the column `proposer` for performance reasons (this is to avoid
        // making a copy of the proposers vector of preferences)
        const uword * proposerPrefcol = proposerPref.colptr(proposer);
        
        // find the best available match for proposer
        for(int jX=0; jX<N; jX++) {
        
            // get the index of the reviewer that the proposer is interested in
            // by dereferencing the pointer; increment the pointer after use (not its value)
            const uword wX = *proposerPrefcol++;
        
            // check if wX is available (`M` means unmatched)
            if(engagements(wX)==M) {
        
                // if available, then form a match
                engagements(wX) = proposer;
                proposals(proposer) = wX;
        
                // go to the next proposer
                break;
            }
          
            // wX is already matched, let's see if wX can be poached
            if(reviewerUtils(proposer, wX) > reviewerUtils(engagements(wX), wX)) {
          
                // wX's previous partner becomes unmatched (`N` means unmatched)
                proposals(engagements(wX)) = N;
                bachelors.push(engagements(wX));
          
                // proposer and wX form a match
                engagements(wX) = proposer;
                proposals(proposer) = wX;
          
                // go to the next proposer
                break;
            }
        }
        
        // remove proposer from bachelor queue: proposer will remain unmatched
        bachelors.pop();
    }

    return List::create(
      _["proposals"]   = proposals,
      _["engagements"] = engagements);
}
Esempio n. 2
0
//------------------------------------------------------------------------------
void NiceGraph::makeStrangersBanquetGraph(int numVertices, int groups, float density, float mu)
{

	makeEmptyGraph(numVertices); 	// first initialize all the vertices

	makeUndirected(); // the SB is only undirected for now...

	if (groups > numVertices)		// bounds checking on number of groups
		groups = numVertices;
	
	for (int c = 0; c < numVertices; c++)	// now subdivide into groups
	{
		for (int g = 0; g < groups; g++)
		{
			if (c % groups == g)
				setVertexColor(c,g);
		}
	}

	// make declining edge scheme to speed things up
	int total_edges = numVertices * (numVertices - 1) / 2;
	vector<Edge> proposals (total_edges);
	
	int edgeIndex = 0;
	for (int froms = 0; froms < numVertices; froms++)
	{
		for (int tos = 0; tos < numVertices; tos++)
		{
			if ((froms != tos) && (froms < tos))
			{
				proposals[edgeIndex].from = vertexList[froms];
				proposals[edgeIndex].to = vertexList[tos];
				edgeIndex++;
			}
		}
	}
	// propose connections and build graph
	int num_edges = (int) (density * (float) total_edges);
	int edge_counter = 0;

	    while (edge_counter < num_edges)
	    {
		// use declining proposal list to speed things up...
		int randIndex = rand() % proposals.size();
		
	    	// choose two vertices to make the proposal
	    	int vertex1 = proposals[randIndex].from->vID;
	    	int vertex2 = proposals[randIndex].to->vID;
	    	
	    	if ((vertex1 != vertex2) && (!testConnected(vertex1,vertex2))) 			// if isn't itself, and aren't already connected
    		{
				// now check to see if they are accepted
				if (vertexList[vertex1]->vColor == vertexList[vertex2]->vColor) 
				{
					// if same color approve match
					addEdge(vertex1, vertex2);		// add edge
					edge_counter++;
					if (!proposals.empty()) 
						proposals.erase(proposals.begin()+randIndex);	// remove from list

				}
				else		// if different colors check against mu
				{
					float chance1 = rand() / (RAND_MAX+1.0);
					float chance2 = rand() / (RAND_MAX+1.0);
	
					if ((chance1 < mu) || (chance2 < mu))
							continue; // if either one rejects the connection do nothing
					else	
					{	// approve the connection
						addEdge(vertex1, vertex2);		// add edge
						edge_counter++;
						if (!proposals.empty()) 
							proposals.erase(proposals.begin()+randIndex);	// remove from list

					}	
				}		
		}
	}
}