static void backtrack(int *out, int *rowsum, int *colsum, int fill, int nr, int nc, int *rfill, int *cfill, int *ind) { int tmp, i, j, k, ir, ic; int izero = nr * nc - 1, ielig = nr * nc - 1, npick = 0, oldpick = 0, ndrop = 1, dropouts[BACKSTEP], idrop = 0, lastpick = 0; /* initialize */ for(i = 0; i < nr * nc; i++) ind[i] = i; memset(rfill, 0, nr * sizeof(int)); memset(cfill, 0, nc * sizeof(int)); /* check for empty rows/columns and move their indices from eligible */ for (ir=0; ir < nr; ir++) if (rowsum[ir] <= 0) for (i = ielig; i > EMPTY; i--) if (ind[i] % nr == ir) { SWAP(ind[i], ind[ielig]); ielig--; } for (ic=0; ic < nc; ic++) if (colsum[ic] <= 0) for (i = ielig; i > EMPTY; i--) if (ind[i] / nr == ic) { SWAP(ind[i], ind[ielig]); ielig--; } /* Start working */ while(npick < fill) { /* outermost loop (placeholder) */ /* fill */ #if LOUD Rprintf("\nFILL "); #endif while(ielig > EMPTY) { i = IRAND(ielig); /* eligible: always succeed */ #if LOUD Rprintf("pick %d ", i); #endif ir = ind[i] % nr; /* row */ ic = ind[i] / nr; /* column */ npick++; SWAP(ind[i], ind[ielig]); /* move after izero */ if (ielig < izero) { SWAP(ind[ielig], ind[izero]); } ielig--; izero--; /* update fills and move from eligible if marginal sum reached */ if (++rfill[ir] == rowsum[ir]) for(i = ielig; i > EMPTY; i--) if (ind[i] % nr == ir) { #if LOUD Rprintf("ban %d ", i); #endif SWAP(ind[i], ind[ielig]); ielig--; } if (++cfill[ic] == colsum[ic]) for (i = ielig; i > EMPTY; i--) if (ind[i] / nr == ic) { #if LOUD Rprintf("ban %d ", i); #endif SWAP(ind[i], ind[ielig]); ielig--; } } /* get out */ #if LOUD if (npick != oldpick) Rprintf("\n*** PICKED %d ", npick); #endif R_CheckUserInterrupt(); if (npick == fill) break; #if RESET /* if we did worse than previously, undo: remove picked items * and put back the ones removed as dropouts */ if (npick < oldpick) { #if LOUD Rprintf("\nRESET "); #endif /* first items after izero were added in the last cycle -- * these should be removed except for the originally * dropped items (dropouts) that should be kept */ lastpick = izero + ndrop - oldpick + npick; for (i = izero+1; i <= lastpick; i++) { k = imatch(ind[i], dropouts, idrop+1); if (k == EMPTY) { /* remove pick: not a dropout */ #if LOUD Rprintf("drop %d ", i); #endif rfill[ind[i] % nr]--; cfill[ind[i] / nr]--; npick--; izero++; if (izero < i) { SWAP(ind[i], ind[izero]); } } else { /* remove from dropouts */ #if LOUD Rprintf("keep %d ", i); #endif dropouts[k] = dropouts[idrop--]; } } /* The dropouts are among first items of ind: search these and * add back to picked. */ i = EMPTY; while(idrop > EMPTY) { k = imatch(ind[++i], dropouts, idrop+1); if (k != EMPTY) { /* pick back this item */ #if LOUD Rprintf("pick %d ", i); #endif rfill[ind[i] % nr]++; cfill[ind[i] / nr]++; SWAP(ind[i], ind[izero]); izero--; npick++; dropouts[k] = dropouts[idrop--]; } } } #endif /* RESET */ /* backtrack: remove picked items and update marginal totals * and see if any items become eligible. If 'npick' did not * improve from the best 'oldpick', increase 'ndrop' up to * BACKSTEP, and reset 'ndrop' to 1 if 'npick' improved. */ if (oldpick < npick) { ndrop = 1; oldpick = npick; } else if (ndrop < BACKSTEP && ndrop < npick) { ndrop++; } #if LOUD Rprintf("\nBACKTRACK %d: ", ndrop); #endif for (j = 0, idrop = EMPTY; j < ndrop; j++) { i = IRAND(npick-1) + izero + 1; #if LOUD Rprintf("%d ", i); #endif dropouts[++idrop] = ind[i]; /* save removed */ rfill[ind[i] % nr]--; cfill[ind[i] / nr]--; npick--; ielig++; izero++; SWAP(ind[i], ind[izero]); SWAP(ind[izero], ind[ielig]); /* if elig is EMPTY: move to ind[0] */ } /* see what can be moved to eligible */ for (i = izero; i > ielig; i--) { ir = ind[i] % nr; ic = ind[i] / nr; if (rfill[ir] < rowsum[ir] && cfill[ic] < colsum[ic]) { #if LOUD Rprintf("free %d ", i); #endif ielig++; SWAP(ind[i], ind[ielig]); } } } /* output */ memset(out, 0, nr * nc * sizeof(int)); /* put 1's in their places */ for (i = izero+1; i < nr*nc; i++) out[ind[i]] = 1; }
inline static dt::boolean call(const dt::istring &pattern, const dt::istring &haystack) { return imatch(pattern, haystack); }