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 }