int CNBipartiteGraph::calcFullSrcMatch_IIIsortedSnks(CNBiGrMtc& mtc, int noFull)
{
CNBiGrVtxIdxVec& result = mtc.getSrcToSnk();
CNBiGrVtxIdxVec& usedBy = mtc.getSnkToSrc();
// Perform a typed full source match where priority of types is
// given by order of sinks. Sources are dense and order is not
// important.
// Parameter indicates that we don't search for full match -> max match
// only, were max means maxim. number of matched sinks or srcs.
// First sinks are taken first to match sources, therefore we store types
// which are to be used as late as possible at the end. All sinks with
// same type could be sorted by nearness to request (-> near objects
// are calculated more often).
//
// Algorithm:
// The (typed) net in this bipartite graph is not used directly. Instead
// of we use a local bipartite graph for representation of actual graph.
// This local graph consists only of locSnks, the used sinks which are
// inserted with all their edges (because they represent alternatives
// which can be used in augmenting paths). Initially locSnk is empty.
//
// We iterate about given sorted sinks. For each we try to find a match.
// If there is a directly connected free source we use it. If all
// connected sources are used we try to find an augmenting (or a switch)
// path to a free source. If there are no free sources at all we have
// reached a full (and therefore max) match and can return. If there is
// no path this means all connected sources use sinks which can not
// be switched.
// A path starts from a sink and ends at a source. So unused sinks are not
// of interest (if we search from a sink) because they can never be in a
// path (As start they were a flop as tested just now. As middle they
// can't be used because there is no matching edge to switch. As end
// they can't be used because if we start from sinks we need a source
// at the end.)
//
// We don't use a first guess. It could cause use of sinks which may
// be avoided by finding an augmenting path for a sink with lesser index.
//
// Complexity is better than #sinks * #edges because we use local edges
// and the number of local edges is at first = 0 and then increasing by
// number of edges to a used sink.
//
CNBiGrVtxIdx numSnks = getNumSnks();
CNBiGrVtxIdx numSrcs = getNumSrcs();
if (noFull == 0 && numSnks < numSrcs)
return 0; // no full source match possible
result.resize(numSrcs); result.setAllToE0(); // stores actual match
usedBy.resize(numSnks); usedBy.setAllToE0(); // stores actual match
if (getNumSrcs() == 0) // no src -> always a match
return 1;
CNBiGrVtxVecFixed locSnks(numSnks,CNBiGrInvVtx); // local sinks & edges
CNBiGrVtxIdxBufFixed snkX(numSnks); // snks to expand
CNBiGrVtxIdxVecFixed snkC(numSnks,CNBiGrInvVtxIdx); // to track paths
CNBiGrVtxIdxVecFixed srcL(numSrcs,CNBiGrInvVtxIdx); // layer info
CNBiGrVtxIdx matches = 0; // actual number of matches
CNBiGrVtxIdx reserve = numSnks - numSrcs; // max number of unmatched snks
// reserve is only used in full matches !!!
CNBiGrVtxIdx snk0, snk, src, nxt, i, n;
for (snk0 = 0; snk0 < numSnks; snk0++){
// search a path from snk0 to an unused source
snkX.clear();
nxt = 0; // initially a valid idx
// generate first generation (we prefer special test and do not
// insert snk0 into locSnks before we know that it is ok)
snk = snk0;
n = snks[snk].getNumEdgs();
for(i=1;i<=n;i++){ // orig: 0..<n @@@1
src = snks[snk].getEdgTo(n-i); // @@@1
nxt = result[src];
if (nxt == CNBiGrInvVtxIdx) // path end found (src is the end)
break;
else{ // nxt is index of next possible snk in path
snkC[nxt] = snk; // we came from snk0
snkX.append(nxt); // expand this snk too
}
srcL[src] = snk0; // now in layer for processing snk0
}
while(snkX.getLen() != 0 && nxt != CNBiGrInvVtxIdx){
snk = snkX.pop();
n = locSnks[snk].getNumEdgs();
for(i=1;i<=n;i++){ // orig: 0..<n @@@1
// In second generation one of these srcs is src from which we
// reached this snk, don't worry it's detected fast via srcL.
src = locSnks[snk].getEdgTo(n-i); // @@@1
if (srcL[src] == snk0)
continue; // this src is already checked
srcL[src] = snk0; // now in layer for processing snk0
nxt = result[src];
if (nxt == CNBiGrInvVtxIdx) // path end found (src is the end)
break;
else{ // nxt is index of next possible snk in path
snkC[nxt] = snk; // we came from snk
snkX.append(nxt); // expand this snk too
}
}
}
if (nxt != CNBiGrInvVtxIdx){ // snk not usable without making other unused
if (noFull == 0 && reserve-- == 0 ) // test reserve for full match
return 0; // # no reserve for a FULL match
continue; // this sink could not be used -> try next sink
}
// switch the path beginning from src, snk is first sink to switch
do {
nxt = usedBy[snk]; // next src to process
usedBy[snk] = src;
result[src] = snk;
src = nxt;
snk = snkC[snk];
} while(nxt != CNBiGrInvVtxIdx);
// this sink could be used, test if full match reached now
if (++matches == numSrcs)
return 1; // each full match is a max match too
// store new sink and its edges in locSnks
locSnks[snk0]=snks[snk0];
}
return noFull; // noFull (max) matches are OK here, full matches NOT
}