aib.c
Go to the documentation of this file.
00001 
00007 /*
00008 Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson.
00009 All rights reserved.
00010 
00011 This file is part of the VLFeat library and is made available under
00012 the terms of the BSD license (see the COPYING file).
00013 */
00014 
00120 #include "aib.h"
00121 #include <stdio.h>
00122 #include <stdlib.h>
00123 #include <float.h>
00124 #include <math.h>
00125 
00126 /* The maximum value which beta may take */
00127 #define BETA_MAX DBL_MAX
00128 
00139 void vl_aib_normalize_P (double * P, vl_uint nelem)
00140 {
00141     vl_uint i;
00142     double sum = 0;
00143     for(i=0; i<nelem; i++)
00144         sum += P[i];
00145     for(i=0; i<nelem; i++)
00146         P[i] /= sum;
00147 }
00148 
00158 vl_uint *vl_aib_new_nodelist (vl_uint nentries)
00159 {
00160     vl_uint * nodelist = vl_malloc(sizeof(vl_uint)*nentries);
00161     vl_uint n;
00162     for(n=0; n<nentries; n++)
00163         nodelist[n] = n;
00164 
00165     return nodelist;
00166 }
00167 
00180 double * vl_aib_new_Px(double * Pcx, vl_uint nvalues, vl_uint nlabels)
00181 {
00182     double * Px = vl_malloc(sizeof(double)*nvalues);
00183     vl_uint r,c;
00184     for(r=0; r<nvalues; r++)
00185     {
00186         double sum = 0;
00187         for(c=0; c<nlabels; c++)
00188             sum += Pcx[r*nlabels+c];
00189         Px[r] = sum;
00190     }
00191     return Px;
00192 }
00193 
00205 double * vl_aib_new_Pc(double * Pcx, vl_uint nvalues, vl_uint nlabels)
00206 {
00207     double * Pc = vl_malloc(sizeof(double)*nlabels);
00208     vl_uint r, c;
00209     for(c=0; c<nlabels; c++)
00210     {
00211         double sum = 0;
00212         for(r=0; r<nvalues; r++)
00213             sum += Pcx[r*nlabels+c];
00214         Pc[c] = sum;
00215     }
00216     return Pc;
00217 }
00218 
00232 void vl_aib_min_beta
00233 (VlAIB * aib, vl_uint * besti, vl_uint * bestj, double * minbeta)
00234 {
00235     vl_uint i;
00236     *minbeta = aib->beta[0];
00237     *besti   = 0;
00238     *bestj   = aib->bidx[0];
00239 
00240     for(i=0; i<aib->nentries; i++)
00241     {
00242         if(aib->beta[i] < *minbeta)
00243         {
00244             *minbeta = aib->beta[i];
00245             *besti = i;
00246             *bestj = aib->bidx[i];
00247         }
00248     }
00249 }
00250 
00271 void
00272 vl_aib_merge_nodes (VlAIB * aib, vl_uint i, vl_uint j, vl_uint new)
00273 {
00274   vl_uint last_entry = aib->nentries - 1 ;
00275   vl_uint c, n ;
00276 
00277   /* clear the list of nodes to update */
00278   aib->nwhich = 0;
00279 
00280   /* make sure that i is smaller than j */
00281   if(i > j) { vl_uint tmp = j; j = i; i = tmp; }
00282 
00283   /* -----------------------------------------------------------------
00284    *                    Merge entries i and j, storing the result in i
00285    * -------------------------------------------------------------- */
00286 
00287   aib-> Px   [i] += aib->Px[j] ;
00288   aib-> beta [i]  = BETA_MAX ;
00289   aib-> nodes[i]  = new ;
00290 
00291   for (c = 0; c < aib->nlabels; c++)
00292     aib-> Pcx [i*aib->nlabels + c] += aib-> Pcx [j*aib->nlabels + c] ;
00293 
00294   /* -----------------------------------------------------------------
00295    *                                              Move last entry to j
00296    * -------------------------------------------------------------- */
00297 
00298   aib-> Px    [j]  = aib-> Px    [last_entry];
00299   aib-> beta  [j]  = aib-> beta  [last_entry];
00300   aib-> bidx  [j]  = aib-> bidx  [last_entry];
00301   aib-> nodes [j]  = aib-> nodes [last_entry];
00302 
00303   for (c = 0 ;  c < aib->nlabels ; c++)
00304     aib-> Pcx[j*aib->nlabels + c] = aib-> Pcx [last_entry*aib->nlabels + c] ;
00305 
00306   /* delete last entry */
00307   aib-> nentries -- ;
00308 
00309   /* -----------------------------------------------------------------
00310    *                                        Scan for entries to update
00311    * -------------------------------------------------------------- */
00312 
00313   /*
00314    * After mergin entries i and j, we need to update all other entries
00315    * that had one of these two as closest match. We also need to
00316    * update the renewend entry i. This is added by the loop below
00317    * since bidx [i] = j exactly because i was merged.
00318    *
00319    * Additionaly, since we moved the last entry back to the entry j,
00320    * we need to adjust the valeus of bidx to reflect this.
00321    */
00322 
00323   for (n = 0 ; n < aib->nentries; n++) {
00324     if(aib->bidx[n] == i || aib->bidx[n] == j) {
00325         aib->bidx  [n] = 0;
00326         aib->beta  [n] = BETA_MAX;
00327         aib->which [aib->nwhich++] = n ;
00328       }
00329     else if(aib->bidx[n] == last_entry) {
00330       aib->bidx[n] = j ;
00331     }
00332   }
00333 }
00334 
00350 void
00351 vl_aib_update_beta (VlAIB * aib)
00352 {
00353 
00354 #define PLOGP(x) ((x)*log((x)))
00355 
00356   vl_uint i;
00357   double * Px  = aib->Px;
00358   double * Pcx = aib->Pcx;
00359   double * tmp = vl_malloc(sizeof(double)*aib->nentries);
00360   vl_uint a, b, c ;
00361 
00362   /*
00363    * T1 = I(x,c) - I([x]_ij) = A + B - C
00364    *
00365    * A  = \sum_c p(xa,c)           \log ( p(xa,c)          /  p(xa)       )
00366    * B  = \sum_c p(xb,c)           \log ( p(xb,c)          /  p(xb)       )
00367    * C  = \sum_c (p(xa,c)+p(xb,c)) \log ((p(xa,c)+p(xb,c)) / (p(xa)+p(xb)))
00368    *
00369    * C  = C1 + C2
00370    * C1 = \sum_c (p(xa,c)+p(xb,c)) \log (p(xa,c)+p(xb,c))
00371    * C2 = - (p(xa)+p(xb) \log (p(xa)+p(xb))
00372    */
00373 
00374   /* precalculate A and B */
00375   for (a = 0; a < aib->nentries; a++) {
00376     tmp[a] = 0;
00377     for (c = 0; c < aib->nlabels; c++) {
00378         double Pac = Pcx [a*aib->nlabels + c] ;
00379         if(Pac != 0) tmp[a] += Pac * log (Pac / Px[a]) ;
00380     }
00381   }
00382 
00383   /* for each entry listed in which */
00384   for (i = 0 ; i < aib->nwhich; i++) {
00385     a = aib->which[i];
00386 
00387     /* for each other entry */
00388     for(b = 0 ; b < aib->nentries ; b++) {
00389       double T1 = 0 ;
00390 
00391       if (a == b || Px [a] == 0 || Px [b] == 0) continue ;
00392 
00393 
00394       T1 = PLOGP ((Px[a] + Px[b])) ;                  /* - C2 */
00395       T1 += tmp[a] + tmp[b] ;                         /* + A + B */
00396 
00397       for (c = 0 ; c < aib->nlabels; ++ c) {
00398         double Pac = Pcx [a*aib->nlabels + c] ;
00399         double Pbc = Pcx [b*aib->nlabels + c] ;
00400         if (Pac == 0 && Pbc == 0) continue;
00401         T1 += - PLOGP ((Pac + Pbc)) ;                 /* - C1 */
00402       }
00403 
00404       /*
00405        * Now we have beta(a,b). We check wether this is the best beta
00406        * for entries a and b.
00407        */
00408       {
00409         double beta = T1 ;
00410 
00411         if (beta < aib->beta[a])
00412           {
00413             aib->beta[a] = beta;
00414             aib->bidx[a] = b;
00415           }
00416         if (beta < aib->beta[b])
00417           {
00418             aib->beta[b] = beta;
00419             aib->bidx[b] = a;
00420           }
00421       }
00422     }
00423   }
00424   vl_free(tmp);
00425 }
00426 
00437 void vl_aib_calculate_information(VlAIB * aib, double * I, double * H)
00438 {
00439     vl_uint r, c;
00440     *H = 0;
00441     *I = 0;
00442 
00443     /*
00444      * H(x)   = - sum_x p(x)    \ log p(x)
00445      * I(x,c) =   sum_xc p(x,c) \ log (p(x,c) / p(x)p(c))
00446      */
00447 
00448     /* for each entry */
00449     for(r = 0 ; r< aib->nentries ; r++) {
00450 
00451       if (aib->Px[r] == 0) continue ;
00452       *H += -log(aib->Px[r]) * aib->Px[r] ;
00453 
00454       for(c=0; c<aib->nlabels; c++) {
00455         if (aib->Pcx[r*aib->nlabels+c] == 0) continue;
00456         *I += aib->Pcx[r*aib->nlabels+c] *
00457           log (aib->Pcx[r*aib->nlabels+c] / (aib->Px[r]*aib->Pc[c])) ;
00458       }
00459     }
00460 }
00461 
00489 VlAIB * vl_aib_new(double * Pcx, vl_uint nvalues, vl_uint nlabels)
00490 {
00491     VlAIB * aib = vl_malloc(sizeof(VlAIB));
00492     vl_uint i ;
00493 
00494     aib->verbosity = 0 ;
00495     aib->Pcx   = Pcx ;
00496     aib->nvalues = nvalues ;
00497     aib->nlabels = nlabels ;
00498 
00499     vl_aib_normalize_P (aib->Pcx, aib->nvalues * aib->nlabels) ;
00500 
00501     aib->Px = vl_aib_new_Px (aib->Pcx, aib->nvalues, aib->nlabels) ;
00502     aib->Pc = vl_aib_new_Pc (aib->Pcx, aib->nvalues, aib->nlabels) ;
00503 
00504     aib->nentries = aib->nvalues ;
00505     aib->nodes    = vl_aib_new_nodelist(aib->nentries) ;
00506     aib->beta     = vl_malloc(sizeof(double) * aib->nentries) ;
00507     aib->bidx     = vl_malloc(sizeof(vl_uint)   * aib->nentries) ;
00508 
00509     for(i = 0 ; i < aib->nentries ; i++)
00510       aib->beta [i] = BETA_MAX ;
00511 
00512     /* Initially we must consider all nodes */
00513     aib->nwhich = aib->nvalues;
00514     aib->which  = vl_aib_new_nodelist (aib->nwhich) ;
00515 
00516     aib->parents = vl_malloc(sizeof(vl_uint)*(aib->nvalues*2-1));
00517     /* Initially, all parents point to a nonexistent node */
00518     for (i = 0 ; i < 2 * aib->nvalues - 1 ; i++)
00519       aib->parents [i] = 2 * aib->nvalues ;
00520 
00521     /* Allocate cost output vector */
00522     aib->costs = vl_malloc (sizeof(double) * (aib->nvalues - 1 + 1)) ;
00523 
00524 
00525     return aib ;
00526 }
00527 
00533 void
00534 vl_aib_delete (VlAIB * aib)
00535 {
00536   if (aib) {
00537     if (aib-> nodes)   vl_free (aib-> nodes);
00538     if (aib-> beta)    vl_free (aib-> beta);
00539     if (aib-> bidx)    vl_free (aib-> bidx);
00540     if (aib-> which)   vl_free (aib-> which);
00541     if (aib-> Px)      vl_free (aib-> Px);
00542     if (aib-> Pc)      vl_free (aib-> Pc);
00543     if (aib-> parents) vl_free (aib-> parents);
00544     if (aib-> costs)   vl_free (aib-> costs);
00545 
00546     vl_free (aib) ;
00547   }
00548 }
00549 
00587 VL_EXPORT
00588 void vl_aib_process(VlAIB *aib)
00589 {
00590     vl_uint i, besti, bestj, newnode, nodei, nodej;
00591     double I, H;
00592     double minbeta;
00593 
00594     /* Calculate initial value of cost function */
00595     vl_aib_calculate_information (aib, &I, &H) ;
00596     aib->costs[0] = I;
00597 
00598     /* Initially which = all */
00599 
00600     /* For each merge */
00601     for(i = 0 ; i < aib->nvalues - 1 ; i++) {
00602 
00603       /* update entries in aib-> which */
00604       vl_aib_update_beta(aib);
00605 
00606       /* find best pair of nodes to merge */
00607       vl_aib_min_beta (aib, &besti, &bestj, &minbeta);
00608 
00609       if(minbeta == BETA_MAX)
00610         /* only null-probability entries remain */
00611         break;
00612 
00613       /* Add the parent pointers for the new node */
00614       newnode = aib->nvalues + i ;
00615       nodei = aib->nodes[besti];
00616       nodej = aib->nodes[bestj];
00617 
00618       aib->parents [nodei] = newnode ;
00619       aib->parents [nodej] = newnode ;
00620       aib->parents [newnode] = 0 ;
00621 
00622       /* Merge the nodes which produced the minimum beta */
00623       vl_aib_merge_nodes (aib, besti, bestj, newnode) ;
00624       vl_aib_calculate_information (aib, &I, &H) ;
00625 
00626       aib->costs[i+1] = I;
00627 
00628       if (aib->verbosity > 0) {
00629         VL_PRINTF ("aib: (%5d,%5d)=%5d dE: %10.3g I: %6.4g H: %6.4g updt: %5d\n",
00630                    nodei,
00631                    nodej,
00632                    newnode,
00633                    minbeta,
00634                    I,
00635                    H,
00636                    aib->nwhich) ;
00637       }
00638     }
00639 
00640     /* fill ignored entries with NaNs */
00641     for(; i < aib->nvalues - 1 ; i++)
00642         aib->costs[i+1] = VL_NAN_D ;
00643 }


libvlfeat
Author(s): Andrea Vedaldi
autogenerated on Thu Jun 6 2019 20:25:51