예제 #1
0
파일: mclcm.c 프로젝트: ANS-math/SBEToolbox
static void write_coarse
(  mcxIO* xf_coarse
,  mclx*  mx_coarse
)
   {  mclx* tmp = mclxCopy(mx_coarse)
   ;  double mv = mclxMaxValue(tmp)
   ;  double sc = mv ? mv / 100.0 : 1.0
   ;  mclxUnary(tmp, fltxScale, &sc)
   ;  mclxaWrite(tmp, xf_coarse, 4, RETURN_ON_FAIL)
   ;  mclxFree(&tmp)
;  }
예제 #2
0
파일: mclcm.c 프로젝트: ANS-math/SBEToolbox
static mclx* get_coarse
(  const mclx* mxbase
,  mclx* clprev
,  mcxbool add_transpose
)
   {  mclx* blockc   =  mclxBlocksC(mxbase, clprev)
   ;  mclx* clprevtp =  mclxTranspose(clprev)
   ;  mclx *p1       =  NULL     /* p_roduct */
   ;  mclx* mx_coarse=  NULL

   ;  mclxMakeStochastic(clprev)

/****************** <EXPERIMENTAL CRAP>  ************************************/
   ;  if (hdp_g)
      mclxUnary(clprev, fltxPower, &hdp_g)
                        /* parameter: use mxbase rather than blockc */
   ;  if (getenv("MCLCM_BLOCK_STOCHASTIC")) /* this works very badly! */
      mclxMakeStochastic(blockc)

   ;  else if (getenv("MCLCM_BASE_UNSCALE") && start_col_sums_g)
      {  dim i
      ;  for (i=0;i<N_COLS(blockc);i++)
         {  double f = start_col_sums_g->ivps[i].val
         ;  mclvUnary(blockc->cols+i, fltxMul, &f)
      ;  }
   ;  }
/****************** </EXPERIMENTAL> *****************************************/

      p1 = mclxCompose(blockc, clprev, 0)
;if (0)
{mcxIO* t = mcxIOnew("-", "w")
;mclxWrite(blockc, t, MCLXIO_VALUE_GETENV, EXIT_ON_FAIL)
;
}
   ;  mclxFree(&blockc)
   ;  mx_coarse = mclxCompose(clprevtp, p1, 0) 
   ;  if (add_transpose)
      mclxAddTranspose(mx_coarse, 0.0)
   ;  mclxAdjustLoops(mx_coarse, mclxLoopCBremove, NULL)

   ;  mclxFree(&p1)
   ;  mclxFree(&clprevtp)

   ;  mclxMakeCharacteristic(clprev)
   ;  return mx_coarse
;  }
예제 #3
0
int main
(  int                  argc
,  const char*          argv[]
)  
   {  mcxIO* xfmx          =  mcxIOnew("-", "r"), *xfout = mcxIOnew("-", "w")
   ;  mclx* mx             =  NULL
   ;  mclv* mx_diag        =  NULL

   ;  mcxstatus parseStatus = STATUS_OK
   ;  mcxOption* opts, *opt
   ;  dim N_edge = 0
   ;  dim*  offsets

   ;  dim template_n_nodes = 0
   ;  mcxbool plus = FALSE

   ;  double e_min  = 1.0
   ;  double e_max  = 0.0
   ;  double skew = 0.0

   ;  double radius = 0.0
   ;  double n_sdev  = 0.5
   ;  double n_range = 2.0

   ;  double g_radius  = 0.0
   ;  double g_mean   = 0.0
   ;  double g_sdev = 0.0
   ;  double g_min  = 1.0
   ;  double g_max  = 0.0
   ;  mcxbool do_gaussian = FALSE

   ;  dim i = 0

   ;  dim N_remove  = 0
   ;  dim N_add     = 0
   ;  dim N_shuffle = 0

   ;  unsigned long random_ignore = 0

   ;  srandom(mcxSeed(2308947))
   ;  mcxOptAnchorSortById(options, sizeof(options)/sizeof(mcxOptAnchor) -1)

   ;  if
      (!(opts = mcxOptParse(options, (char**) argv, argc, 1, 0, &parseStatus)))
      exit(0)

   ;  mcxLogLevel =
      MCX_LOG_AGGR | MCX_LOG_MODULE | MCX_LOG_IO | MCX_LOG_GAUGE | MCX_LOG_WARN
   ;  mclxIOsetQMode("MCLXIOVERBOSITY", MCL_APP_VB_YES)
   ;  mclx_app_init(stderr)

   ;  for (opt=opts;opt->anch;opt++)
      {  mcxOptAnchor* anch = opt->anch

      ;  switch(anch->id)
         {  case MY_OPT_HELP
         :  case MY_OPT_APROPOS
         :  mcxOptApropos(stdout, me, syntax, 20, MCX_OPT_DISPLAY_SKIP, options)
         ;  return 0
         ;

            case MY_OPT_VERSION
         :  app_report_version(me)
         ;  return 0
         ;

            case MY_OPT_SKEW
         :  skew = atof(opt->val)
         ;  break
         ;

            case MY_OPT_GEN
         :  template_n_nodes = atoi(opt->val)
         ;  break
         ;

            case MY_OPT_IMX
         :  mcxIOrenew(xfmx, opt->val, NULL)
         ;  break
         ;

            case MY_OPT_PLUS
         :  case MY_OPT_WB
         :  plus = TRUE
         ;  break
         ;

            case MY_OPT_OUT
         :  mcxIOrenew(xfout, opt->val, NULL)
         ;  break
         ;

            case MY_OPT_E_MAX
         :  if (!strcmp(opt->val, "copy"))
            e_max = -DBL_MAX
         ;  else
            e_max = atof(opt->val)
         ;  break
         ;  

            case MY_OPT_E_MIN
         :  e_min = atof(opt->val)
         ;  break
         ;  

            case MY_OPT_G_MIN
         :  g_min = atof(opt->val)
         ;  break
         ;  

            case MY_OPT_G_MAX
         :  g_max = atof(opt->val)
         ;  break
         ;  

            case MY_OPT_G_SDEV
         :  g_sdev = atof(opt->val)
         ;  break
         ;  

            case MY_OPT_G_MEAN
         :  g_mean = atof(opt->val)
         ;  do_gaussian = TRUE
         ;  break
         ;  

            case MY_OPT_G_RADIUS
         :  g_radius = atof(opt->val)
         ;  break
         ;  

            case MY_OPT_N_RANGE
         :  n_range = atof(opt->val)
         ;  break
         ;  

            case MY_OPT_N_SDEV
         :  n_sdev = atof(opt->val)
         ;  break
         ;  

            case MY_OPT_N_RADIUS
         :  radius = atof(opt->val)
         ;  break
         ;  

            case MY_OPT_SHUFFLE
         :  N_shuffle = atoi(opt->val)
         ;  break
         ;  

            case MY_OPT_ADD
         :  N_add = atoi(opt->val)
         ;  break
         ;  
            
            case MY_OPT_REMOVE
         :  N_remove  = atoi(opt->val)
         ;  break
      ;  }
      }

                                 /* hitting y% in vi tells me the size of this block */
      {  if (template_n_nodes)
         mx =  mclxAllocZero
               (  mclvCanonical(NULL, template_n_nodes, 1.0)
               ,  mclvCanonical(NULL, template_n_nodes, 1.0)
               )
      ;  else
         mx =  mclxReadx
               (  xfmx
               ,  EXIT_ON_FAIL
               ,  MCLX_REQUIRE_GRAPH
               )

      ;  mx_diag = mclxDiagValues(mx, MCL_VECTOR_COMPLETE)

      ;  if (N_shuffle)
         mclxAdjustLoops(mx, mclxLoopCBremove, NULL)
      ;  else
         mclxSelectUpper(mx)
      /* ^ apparently we always work on single arc representation (docme andsoon) */

      ;  offsets = mcxAlloc(sizeof offsets[0] * N_COLS(mx), EXIT_ON_FAIL)

      ;  N_edge = 0
      ;  for (i=0;i<N_COLS(mx);i++)
         {  offsets[i] = N_edge
         ;  N_edge += mx->cols[i].n_ivps
      ;  }

         if (N_edge < N_remove)
         {  mcxErr
            (  me
            ,  "removal count %ld exceeds edge count %ld"
            ,  (long) N_remove
            ,  (long) N_edge
            )
         ;  N_remove = N_edge
      ;  }

         random_ignore = RAND_MAX - (N_edge ? RAND_MAX % N_edge : 0)

      ;  if (RAND_MAX / 2 < N_edge)
         mcxDie(1, me, "graph too large!")

      ;  if (N_shuffle)
         {  do_the_shuffle(mx, N_shuffle, offsets, N_edge, random_ignore)
         ;  mx_readd_diagonal(mx, mx_diag)
         ;  mclxWrite(mx, xfout, MCLXIO_VALUE_GETENV, RETURN_ON_FAIL)
         ;  exit(0)
      ;  }

      ;  if (N_remove)
         {  dim n_remove = do_remove(mx, N_remove, offsets, N_edge, random_ignore)
               /* Need to recompute N_edge and random_ignore.
                * NOTE we work with *upper* matrix; this counts graph edges.
               */
         ;  N_edge = mclxNrofEntries(mx) - n_remove
         ;  random_ignore = RAND_MAX - (RAND_MAX % N_COLS(mx))
      ;  }

         if (g_mean)
         {  if (!g_radius)
            {  if (g_sdev)
               g_radius = 2 * g_sdev
            ;  mcxWarn(me, "set radius to %.5f\n", g_radius)
         ;  }
         }

      ;  if (N_add)
         N_edge +=   do_add
                     (  mx
                     ,  N_add  ,  N_edge
                     ,  do_gaussian ? &g_mean : NULL,  g_radius ,  g_sdev ,  g_min ,  g_max
                     ,  skew
                     ,  e_min ,  e_max
                     )

      ;  if (radius)
         {  for (i=0;i<N_COLS(mx);i++)
            {  mclp* ivp = mx->cols[i].ivps, *ivpmax = ivp + mx->cols[i].n_ivps
;if(DEBUG)fprintf(stderr, "here %d\n", (int) i)
            ;  while (ivp < ivpmax)
               {  double val = ivp->val
               ;  double r = mcxNormalCut(n_range * n_sdev, n_sdev)
               ;  double newval = val + radius * (r / (n_range * n_sdev))

               ;  if (e_min < e_max && newval >= e_min && newval <= e_max)
               ;  ivp->val = newval
               ;  ivp++
            ;  }
            }
         }

         mclxUnary(mx, fltxCopy, NULL)    /* remove zeroes */
      ;  mclxAddTranspose(mx, 0.0)
      ;  mx_readd_diagonal(mx, mx_diag)

      ;  if (plus)
         mclxbWrite(mx, xfout, RETURN_ON_FAIL)
      ;  else
         mclxWrite(mx, xfout, MCLXIO_VALUE_GETENV, RETURN_ON_FAIL)
   ;  }
      return 0
;  }
예제 #4
0
static dim clm_clm_prune
(  mclx*    mx
,  mclx*    cl
,  dim      prune_sz
,  mclx**   cl_adjustedpp
,  dim*     n_sink
,  dim*     n_source
)
   {  dim d, n_adjusted = 0
   ;  mclx* cl_adj = mclxCopy(cl)
   ;  mclv* cid_affected = mclvClone(cl->dom_cols)
   ;  const char* me = "clmAssimilate"

   ;  double bar_affected = 1.5

   ;  mclx *el_to_cl = NULL
   ;  mclx *el_on_cl = NULL
   ;  mclx *cl_on_cl = NULL
   ;  mclx *cl_on_el = NULL

   ;  *n_sink = 0
   ;  *n_source = 0

   ;  mclvMakeConstant(cid_affected, 1.0)
   ;  mclxColumnsRealign(cl_adj, mclvSizeCmp)

   ;  *cl_adjustedpp = NULL

   ;  clmCastActors
      (&mx, &cl_adj, &el_to_cl, &el_on_cl, &cl_on_cl, &cl_on_el, 0.95)
   ;  mclxFree(&cl_on_el)

   ;  for (d=0;d<N_COLS(cl_on_cl);d++)
      {  mclv* clthis   =  cl_adj->cols+d
      ;  mclv* cllist   =  cl_on_cl->cols+d
      ;  mclp* pself    =  mclvGetIvp(cllist, clthis->vid, NULL)
      ;  double self_val = -1.0
      
      ;  if (pself)
            self_val = pself->val
         ,  pself->val *= 1.001  /* to push it up in case of equal weights */

;if(0)fprintf(stderr, "test size %d\n", (int) clthis->n_ivps)
      ;  if (prune_sz && clthis->n_ivps > prune_sz)
         continue

      ;  while (1)
         {  mclv* clthat
         ;  dim e
         ;  if (cllist->n_ivps < 2)
            break
         ;  mclvSort(cllist, mclpValRevCmp)

                     /* now get biggest mass provided that cluster
                      * ranks higher (has at least as many entries)
                      *
                      * fixme/todo: we probably have a slight order
                      * dependency for some fringe cases. If provable
                      * then either solve or document it.
                     */
         ;  for (e=0;e<cllist->n_ivps;e++)
            if (cllist->ivps[e].idx >= clthis->vid)
            break

                     /* found none or itself */
         ;  if (e == cllist->n_ivps || cllist->ivps[e].idx == clthis->vid)
            break

         ;  if       /* Should Not Happen */
            (!(clthat
            =  mclxGetVector(cl_adj, cllist->ivps[e].idx, RETURN_ON_FAIL, NULL)
            ) )
            break

                     /*    works for special case prune_sz == 0               */
                     /*    if (clthat->n_ivps + clthis->n_ivps > prune_sz)    */
                     /*    ^iced. inconsistent behaviour as k grows.          */
         ;  {  mcxLog
               (  MCX_LOG_LIST
               ,  me
               ,  "source %ld|%lu|%.3f absorbed by %ld|%lu|%.3f"
               ,  clthis->vid, (ulong) clthis->n_ivps, self_val
               ,  clthat->vid, (ulong) clthat->n_ivps, cllist->ivps[0].val
               )
            ;  n_adjusted += clthis->n_ivps
            ;  (*n_sink)++
                     /* note: we could from our precomputed cl_on_cl
                      * obtain that A is absorbed in B, B is absorbed in C.
                      * below we see that A will be merged with B,
                      * and the result will then be merged with C.
                      * This depends on the fact that cl_adj is ordered
                      * on increasing cluster size.
                     */
            ;  mcldMerge(cl_adj->cols+d, clthat, clthat)
            ;  mclvResize(cl_adj->cols+d, 0)
            ;  mclvInsertIdx(cid_affected, clthat->vid, 2.0)
         ;  }
            break
      ;  }
         mclvSort(cllist, mclpIdxCmp)
   ;  }

      mclxFree(&cl_on_cl)
   ;  mclxFree(&el_on_cl)
   ;  mclxFree(&el_to_cl)

   ;  mclxMakeCharacteristic(cl)

   ;  mclvUnary(cid_affected, fltxGT, &bar_affected)
   ;  *n_source = cid_affected->n_ivps
   ;  mclvFree(&cid_affected)

   ;  mclxColumnsRealign(cl_adj, mclvSizeRevCmp)

   ;  if (!n_adjusted)
      {  mclxFree(&cl_adj)
      ;  return 0
   ;  }

      mclxUnary(cl_adj, fltxCopy, NULL)
   ;  mclxMakeCharacteristic(cl_adj)   

   ;  *cl_adjustedpp  =  cl_adj
   ;  return n_adjusted
;  }
예제 #5
0
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
;  }