void mclvRemoveIdx ( mclVector* vec , long idx ) { ofs offset = mclvGetIvpOffset(vec, idx, -1) /* check for nonnull vector is done in mclvIdxVal */ ; if (offset >= 0) { memmove ( vec->ivps + offset , vec->ivps + offset + 1 , (vec->n_ivps - offset - 1) * sizeof(mclIvp) ) ; mclvResize(vec, vec->n_ivps - 1) ; } }
double mclvIdxVal ( const mclVector* vec , long idx , ofs* p_offset ) { ofs offset = mclvGetIvpOffset(vec, idx, -1) ; double value = 0.0 ; if (p_offset) *p_offset = offset ; if (offset >= 0) value = (vec->ivps+offset)->val ; return value ; }
mclVector* mclvInsertIdx ( mclVector* vec , long idx , double val ) { ofs offset ; if (!vec) { vec = mclvInstantiate(NULL, 1, NULL) ; mclpInstantiate(vec->ivps+0, idx, val) ; } else if ((offset = mclvGetIvpOffset(vec, idx, -1)) >= 0) vec->ivps[offset].val = val ; else { dim d = vec->n_ivps ; mclvResize(vec, d+1) ; while (d && vec->ivps[d-1].idx > idx) vec->ivps[d] = vec->ivps[d-1] , d-- ; vec->ivps[d].val = val ; vec->ivps[d].idx = idx ; } return vec ; }
void static do_the_shuffle ( mclx* mx , dim N_shuffle , dim* offsets /* size N_COLS(mx) */ , dim N_edge , dim random_ignore ) { dim n_shuffle = 0 ; while (n_shuffle < N_shuffle) { unsigned long rx = (unsigned long) random() ; unsigned long ry = (unsigned long) random() ; mclp* ivpll, *ivplr, *ivprl, *ivprr ; dim edge_x, edge_y, *edge_px, *edge_py ; ofs xro, yro, xlo, ylo = -1, vxo, vyo ; long xl, xr, yl, yr ; mclv* vecxl, *vecxr, *vecyl, *vecyr ; double xlval, xrval, ylval, yrval ; if (rx >= random_ignore || ry >= random_ignore) continue ; edge_x = rx % N_edge /* fixme probably not optimal */ ; edge_y = ry % N_edge /* fixme probably not optimal */ ; if (!(edge_px = mcxBsearchFloor(&edge_x, offsets, N_COLS(mx), sizeof edge_x, dimCmp))) mcxDie(1, me, "edge %ld not found (max %ld)", (long) edge_x, (long) N_edge) ; if (!(edge_py = mcxBsearchFloor(&edge_y, offsets, N_COLS(mx), sizeof edge_y, dimCmp))) mcxDie(1, me, "edge %ld not found (max %ld)", (long) edge_y, (long) N_edge) ; vxo = edge_px - offsets ; xl = mx->dom_cols->ivps[vxo].idx ; vecxl = mx->cols+vxo ; xro = edge_x - offsets[vxo] ; vyo = edge_py - offsets ; yl = mx->dom_cols->ivps[vyo].idx ; vecyl = mx->cols+vyo ; yro = edge_y - offsets[vyo] /* Offset computation gone haywire */ ; if (xro >= vecxl->n_ivps || yro >= vecyl->n_ivps) /* note: mixed sign comparison */ mcxDie(1, me, "paradox 1 in %ld or %ld", xl, yl) ; xr = vecxl->ivps[xro].idx ; yr = vecyl->ivps[yro].idx ; xrval = vecxl->ivps[xro].val ; yrval = vecyl->ivps[yro].val /* Impossible, should have graph */ ; vecxr = mclxGetVector(mx, xr, EXIT_ON_FAIL, NULL) ; vecyr = mclxGetVector(mx, yr, EXIT_ON_FAIL, NULL) /* check that we have four different nodes * loops are not present so no need to check those */ ; if (xl == yl || xl == yr || xr == yl || xr == yr) continue ; if ( (0 > (xlo = mclvGetIvpOffset(vecxr, xl, -1))) || (0 > (ylo = mclvGetIvpOffset(vecyr, yl, -1))) ) mcxDie ( 1 , me , "symmetry violation 1" " %ld not found in %ld/%ld OR %ld not found in %ld/%ld" , (long) xl, (long) vecxr->vid, (long) vecxr->n_ivps , (long) yl, (long) vecyr->vid, (long) vecyr->n_ivps ) /* Now: xl yl : ivpll * xl yr : ivplr * xr yl : ivprl * xr yr : ivprr */ ; xlval = vecxr->ivps[xlo].val ; ylval = vecyr->ivps[ylo].val ; ivpll = mclvGetIvp(vecxl, yl, NULL) ; ivplr = mclvGetIvp(vecxl, yr, NULL) ; ivprl = mclvGetIvp(vecxr, yl, NULL) ; ivprr = mclvGetIvp(vecxr, yr, NULL) ; if ( (ivpll && !mclvGetIvp(vecyl, xl, NULL)) || (ivplr && !mclvGetIvp(vecyr, xl, NULL)) || (ivprl && !mclvGetIvp(vecyl, xr, NULL)) || (ivprr && !mclvGetIvp(vecyr, xr, NULL)) ) mcxDie(1, me, "symmetry violation 2") ; if ((ivpll && ivplr) || (ivprl && ivprr)) continue ; { if (!ivpll && !ivprr) { /* vecxl <-> xr becomes vecxl <-> yl * vecxr <-> xl becomes vecxr <-> yr * vecyl <-> yr becomes vecyl <-> xl * vecyr <-> yl becomes vecyr <-> xr */ ; if ( mclvReplaceIdx(vecxl, xro, yl, xrval) || mclvReplaceIdx(vecyl, yro, xl, xrval) || mclvReplaceIdx(vecxr, xlo, yr, ylval) || mclvReplaceIdx(vecyr, ylo, xr, ylval) ) mcxDie(1, me, "parallel replacement failure\n") #if DEBUG ;fprintf(stderr, "parallel edge change remove %d-%d %d-%d add %d-%d %d-%d\n", vecxl->vid, xr, vecyr->vid, yl, vecxl->vid, yl, vecyr->vid, xr) #endif ; } else if (!ivplr && !ivprl) { /* vecxl -> xr becomes vecxl <-> yr * vecxr -> xl becomes vecxr <-> yl * vecyl -> yr becomes vecyl <-> xr * vecyr -> yl becomes vecyr <-> xl */ if ( mclvReplaceIdx(vecxl, xro, yr, xrval) || mclvReplaceIdx(vecyr, ylo, xl, xlval) || mclvReplaceIdx(vecxr, xlo, yl, yrval) || mclvReplaceIdx(vecyl, yro, xr, yrval) ) mcxDie(1, me, "cross replacement failure\n") #if DEBUG ;fprintf(stderr, "cross edge change remove %d-%d %d-%d add %d-%d %d-%d\n", vecxl->vid, xr, vecyl->vid, yr, vecxl->vid, yr, vecyl->vid, xr) #endif ; } } n_shuffle++ ; } }
static dim clm_clm_adjust ( mclx* mx , mclx* cl , dim cls_size_max , mclx** cl_adjustedpp , mclv** cid_affectedpp , mclv** nid_affectedpp ) { dim i, j, n_adjusted = 0 ; mclx* cl_adj = mclxCopy(cl) ; mclv* cid_affected = mclvClone(cl->dom_cols) ; mclv* nid_affected = mclvClone(mx->dom_cols) ; double bar_affected = 1.5 ; const char* e1 = getenv("MCL_ADJ_FMAX") ; const char* e2 = getenv("MCL_ADJ_EMASS") ; double f1 = e1 ? atof(e1) : 2 ; double f2 = e2 ? atof(e2) : 3 ; mcxbool loggit = mcxLogGet( MCX_LOG_CELL | MCX_LOG_INFO ) ; clmVScore sc ; mclx *el_to_cl = NULL ; mclx *el_on_cl = NULL ; mclx *cl_on_cl = NULL ; mclx *cl_on_el = NULL ; *cl_adjustedpp = NULL ; *cid_affectedpp = NULL ; *nid_affectedpp = NULL ; clmCastActors (&mx, &cl, &el_to_cl, &el_on_cl, &cl_on_cl, &cl_on_el, 0.95) ; mclxFree(&cl_on_cl) ; mclxFree(&cl_on_el) ; mclvMakeConstant(cid_affected, 1.0) ; mclvMakeConstant(nid_affected, 1.0) ; for (i=0;i<N_COLS(cl_adj);i++) cl_adj->cols[i].val = 0.5 /* Proceed with smallest clusters first. * Caller has to take care of mclxColumnsRealign */ ; for (i=0;i<N_COLS(cl);i++) { mclv* clself = cl->cols+i /* Only consider nodes in clusters of * size <= cls_size_max */ ; if (cls_size_max && clself->n_ivps > cls_size_max) break /* Clusters that have been marked for inclusion * cannot play. */ ; if (cl_adj->cols[i].val > 1) continue ; for (j=0;j<clself->n_ivps;j++) { long nid = clself->ivps[j].idx ; long nos = mclvGetIvpOffset(mx->dom_cols, nid, -1) ; mclv* clidvec = mclxGetVector(el_on_cl, nid, RETURN_ON_FAIL, NULL) ; double eff_alien_bsf = 0.0, eff_alien_max_bsf = 0.0 /* best so far*/ ; double eff_self = 0.0, eff_self_max = 0.0 ; long cid_alien = -1, cid_self = -1 ; clmVScore sc_self = { 0 }, sc_alien = { 0 } ; dim f ; if (nos < 0 || !clidvec) { mcxErr ("clmDumpNodeScores panic", "node <%ld> does not belong", nid) ; continue ; } clmVScanDomain(mx->cols+nos, clself, &sc) ; clmVScoreCoverage(&sc, &eff_self, &eff_self_max) ; cid_self = clself->vid ; sc_self = sc ; if (loggit) mcxLog2 ( us , "node %ld in cluster %ld eff %.3f,%.3f sum %.3f" , nid , cid_self , eff_self , eff_self_max , sc.sum_i ) ; for (f=0;f<clidvec->n_ivps;f++) { long cid = clidvec->ivps[f].idx ; mclv* clvec = mclxGetVector(cl, cid, RETURN_ON_FAIL, NULL) /* ^ overdoing: cid == clvec->vid */ ; double eff, eff_max ; if (!clvec) { mcxErr ( "clmAdjust panic" , "cluster <%ld> node <%ld> mishap" , cid , nid ) ; continue ; } /* fixme: document or remove first condition * */ if ((0 && clvec->n_ivps <= clself->n_ivps) || clvec->vid == cid_self) continue ; clmVScanDomain(mx->cols+nos, clvec, &sc) ; clmVScoreCoverage(&sc, &eff, &eff_max) #if 0 # define PIVOT eff > eff_alien_bsf #else # define PIVOT eff_max > eff_alien_max_bsf #endif ; if ( PIVOT || sc.sum_i >= 0.5 ) eff_alien_bsf = eff , eff_alien_max_bsf = eff_max , cid_alien = clvec->vid , sc_alien = sc ; if (sc.sum_i >= 0.5) break ; } if (loggit) mcxLog2 ( us , " -> best alien %ld eff %.3f,%.3f sum %.3f" , cid_alien , eff_alien_bsf , eff_alien_max_bsf , sc_alien.sum_i ) /* below: use sum_i as mass fraction * (clmAdjust framework uses stochastic * matrix) */ ; if ( cid_alien >= 0 && cid_self >= 0 && f1 * sc_alien.max_i >= sc_self.max_i && ( ( eff_alien_bsf > eff_self && sc_alien.sum_i > sc_self.sum_i ) || ( pow(sc_alien.sum_i, f2) >= sc_self.sum_i && pow(eff_self, f2) <= eff_alien_bsf ) ) /* So, if max is reasonable * and efficiency is better and mass is better * or if mass is ridiculously better -> move * Somewhat intricate and contrived, yes. */ ) { mclv* acceptor = mclxGetVector(cl_adj, cid_alien, RETURN_ON_FAIL, NULL) ; mclv* donor = mclxGetVector(cl_adj, cid_self, RETURN_ON_FAIL, NULL) ; if (!donor || !acceptor || acceptor == donor) continue ; mclvInsertIdx(donor, nid, 0.0) ; mclvInsertIdx(acceptor, nid, 1.0) ; acceptor->val = 1.5 ; if (mcxLogGet(MCX_LOG_LIST)) { mclv* nb = mx->cols+nos ; double mxv = mclvMaxValue(nb) ; double avg = nb->n_ivps ? mclvSum(nb) / nb->n_ivps : -1.0 ; mcxLog ( MCX_LOG_LIST , us , "mov %ld (%ld %.2f %.2f)" " %ld (cv=%.2f cm=%.2f s=%.2f m=%.2f #=%lu)" " to %ld (cv=%.2f cm=%.2f s=%.2f m=%.2f #=%lu)" , nid , (long) nb->n_ivps, mxv, avg , cid_self , eff_self, eff_self_max, sc_self.sum_i, sc_self.max_i , (ulong) (sc_self.n_meet + sc_self.n_ddif) , cid_alien , eff_alien_bsf, eff_alien_max_bsf, sc_alien.sum_i, sc_alien.max_i , (ulong) (sc_alien.n_meet + sc_alien.n_ddif) ) ; } n_adjusted++ ; mclvInsertIdx(cid_affected, cid_alien, 2.0) ; mclvInsertIdx(cid_affected, cid_self, 2.0) ; mclvInsertIdx(nid_affected, nid, 2.0) ; } } } mclxFree(&el_on_cl) ; mclxFree(&el_to_cl) ; for (i=0;i<N_COLS(cl_adj);i++) cl_adj->cols[i].val = 0.0 ; mclxMakeCharacteristic(cl) ; if (!n_adjusted) { mclxFree(&cl_adj) ; mclvFree(&cid_affected) ; mclvFree(&nid_affected) ; return 0 ; } mclxUnary(cl_adj, fltxCopy, NULL) ; mclxMakeCharacteristic(cl_adj) /* FIRST REMOVE ENTRIES set to zero (sssst now .. */ /* ...) and THEN make it characteristic again */ ; mclvUnary(cid_affected, fltxGT, &bar_affected) ; mclvUnary(nid_affected, fltxGT, &bar_affected) ; *cl_adjustedpp = cl_adj ; *cid_affectedpp = cid_affected ; *nid_affectedpp = nid_affected ; return n_adjusted ; }