00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00026 #include <string.h>
00027
00028 #include "libavutil/avassert.h"
00029 #include "libavutil/common.h"
00030 #include "libavutil/lfg.h"
00031 #include "elbg.h"
00032 #include "avcodec.h"
00033
00034 #define DELTA_ERR_MAX 0.1
00035
00036
00039 typedef struct cell_s {
00040 int index;
00041 struct cell_s *next;
00042 } cell;
00043
00047 typedef struct{
00048 int error;
00049 int dim;
00050 int numCB;
00051 int *codebook;
00052 cell **cells;
00053 int *utility;
00054 int *utility_inc;
00055 int *nearest_cb;
00056 int *points;
00057 AVLFG *rand_state;
00058 int *scratchbuf;
00059 } elbg_data;
00060
00061 static inline int distance_limited(int *a, int *b, int dim, int limit)
00062 {
00063 int i, dist=0;
00064 for (i=0; i<dim; i++) {
00065 dist += (a[i] - b[i])*(a[i] - b[i]);
00066 if (dist > limit)
00067 return INT_MAX;
00068 }
00069
00070 return dist;
00071 }
00072
00073 static inline void vect_division(int *res, int *vect, int div, int dim)
00074 {
00075 int i;
00076 if (div > 1)
00077 for (i=0; i<dim; i++)
00078 res[i] = ROUNDED_DIV(vect[i],div);
00079 else if (res != vect)
00080 memcpy(res, vect, dim*sizeof(int));
00081
00082 }
00083
00084 static int eval_error_cell(elbg_data *elbg, int *centroid, cell *cells)
00085 {
00086 int error=0;
00087 for (; cells; cells=cells->next)
00088 error += distance_limited(centroid, elbg->points + cells->index*elbg->dim, elbg->dim, INT_MAX);
00089
00090 return error;
00091 }
00092
00093 static int get_closest_codebook(elbg_data *elbg, int index)
00094 {
00095 int i, pick=0, diff, diff_min = INT_MAX;
00096 for (i=0; i<elbg->numCB; i++)
00097 if (i != index) {
00098 diff = distance_limited(elbg->codebook + i*elbg->dim, elbg->codebook + index*elbg->dim, elbg->dim, diff_min);
00099 if (diff < diff_min) {
00100 pick = i;
00101 diff_min = diff;
00102 }
00103 }
00104 return pick;
00105 }
00106
00107 static int get_high_utility_cell(elbg_data *elbg)
00108 {
00109 int i=0;
00110
00111 int r = av_lfg_get(elbg->rand_state)%elbg->utility_inc[elbg->numCB-1] + 1;
00112 while (elbg->utility_inc[i] < r)
00113 i++;
00114
00115 av_assert2(elbg->cells[i]);
00116
00117 return i;
00118 }
00119
00123 static int simple_lbg(elbg_data *elbg,
00124 int dim,
00125 int *centroid[3],
00126 int newutility[3],
00127 int *points,
00128 cell *cells)
00129 {
00130 int i, idx;
00131 int numpoints[2] = {0,0};
00132 int *newcentroid[2] = {
00133 elbg->scratchbuf + 3*dim,
00134 elbg->scratchbuf + 4*dim
00135 };
00136 cell *tempcell;
00137
00138 memset(newcentroid[0], 0, 2 * dim * sizeof(*newcentroid[0]));
00139
00140 newutility[0] =
00141 newutility[1] = 0;
00142
00143 for (tempcell = cells; tempcell; tempcell=tempcell->next) {
00144 idx = distance_limited(centroid[0], points + tempcell->index*dim, dim, INT_MAX)>=
00145 distance_limited(centroid[1], points + tempcell->index*dim, dim, INT_MAX);
00146 numpoints[idx]++;
00147 for (i=0; i<dim; i++)
00148 newcentroid[idx][i] += points[tempcell->index*dim + i];
00149 }
00150
00151 vect_division(centroid[0], newcentroid[0], numpoints[0], dim);
00152 vect_division(centroid[1], newcentroid[1], numpoints[1], dim);
00153
00154 for (tempcell = cells; tempcell; tempcell=tempcell->next) {
00155 int dist[2] = {distance_limited(centroid[0], points + tempcell->index*dim, dim, INT_MAX),
00156 distance_limited(centroid[1], points + tempcell->index*dim, dim, INT_MAX)};
00157 int idx = dist[0] > dist[1];
00158 newutility[idx] += dist[idx];
00159 }
00160
00161 return newutility[0] + newutility[1];
00162 }
00163
00164 static void get_new_centroids(elbg_data *elbg, int huc, int *newcentroid_i,
00165 int *newcentroid_p)
00166 {
00167 cell *tempcell;
00168 int *min = newcentroid_i;
00169 int *max = newcentroid_p;
00170 int i;
00171
00172 for (i=0; i< elbg->dim; i++) {
00173 min[i]=INT_MAX;
00174 max[i]=0;
00175 }
00176
00177 for (tempcell = elbg->cells[huc]; tempcell; tempcell = tempcell->next)
00178 for(i=0; i<elbg->dim; i++) {
00179 min[i]=FFMIN(min[i], elbg->points[tempcell->index*elbg->dim + i]);
00180 max[i]=FFMAX(max[i], elbg->points[tempcell->index*elbg->dim + i]);
00181 }
00182
00183 for (i=0; i<elbg->dim; i++) {
00184 int ni = min[i] + (max[i] - min[i])/3;
00185 int np = min[i] + (2*(max[i] - min[i]))/3;
00186 newcentroid_i[i] = ni;
00187 newcentroid_p[i] = np;
00188 }
00189 }
00190
00200 static void shift_codebook(elbg_data *elbg, int *indexes,
00201 int *newcentroid[3])
00202 {
00203 cell *tempdata;
00204 cell **pp = &elbg->cells[indexes[2]];
00205
00206 while(*pp)
00207 pp= &(*pp)->next;
00208
00209 *pp = elbg->cells[indexes[0]];
00210
00211 elbg->cells[indexes[0]] = NULL;
00212 tempdata = elbg->cells[indexes[1]];
00213 elbg->cells[indexes[1]] = NULL;
00214
00215 while(tempdata) {
00216 cell *tempcell2 = tempdata->next;
00217 int idx = distance_limited(elbg->points + tempdata->index*elbg->dim,
00218 newcentroid[0], elbg->dim, INT_MAX) >
00219 distance_limited(elbg->points + tempdata->index*elbg->dim,
00220 newcentroid[1], elbg->dim, INT_MAX);
00221
00222 tempdata->next = elbg->cells[indexes[idx]];
00223 elbg->cells[indexes[idx]] = tempdata;
00224 tempdata = tempcell2;
00225 }
00226 }
00227
00228 static void evaluate_utility_inc(elbg_data *elbg)
00229 {
00230 int i, inc=0;
00231
00232 for (i=0; i < elbg->numCB; i++) {
00233 if (elbg->numCB*elbg->utility[i] > elbg->error)
00234 inc += elbg->utility[i];
00235 elbg->utility_inc[i] = inc;
00236 }
00237 }
00238
00239
00240 static void update_utility_and_n_cb(elbg_data *elbg, int idx, int newutility)
00241 {
00242 cell *tempcell;
00243
00244 elbg->utility[idx] = newutility;
00245 for (tempcell=elbg->cells[idx]; tempcell; tempcell=tempcell->next)
00246 elbg->nearest_cb[tempcell->index] = idx;
00247 }
00248
00256 static void try_shift_candidate(elbg_data *elbg, int idx[3])
00257 {
00258 int j, k, olderror=0, newerror, cont=0;
00259 int newutility[3];
00260 int *newcentroid[3] = {
00261 elbg->scratchbuf,
00262 elbg->scratchbuf + elbg->dim,
00263 elbg->scratchbuf + 2*elbg->dim
00264 };
00265 cell *tempcell;
00266
00267 for (j=0; j<3; j++)
00268 olderror += elbg->utility[idx[j]];
00269
00270 memset(newcentroid[2], 0, elbg->dim*sizeof(int));
00271
00272 for (k=0; k<2; k++)
00273 for (tempcell=elbg->cells[idx[2*k]]; tempcell; tempcell=tempcell->next) {
00274 cont++;
00275 for (j=0; j<elbg->dim; j++)
00276 newcentroid[2][j] += elbg->points[tempcell->index*elbg->dim + j];
00277 }
00278
00279 vect_division(newcentroid[2], newcentroid[2], cont, elbg->dim);
00280
00281 get_new_centroids(elbg, idx[1], newcentroid[0], newcentroid[1]);
00282
00283 newutility[2] = eval_error_cell(elbg, newcentroid[2], elbg->cells[idx[0]]);
00284 newutility[2] += eval_error_cell(elbg, newcentroid[2], elbg->cells[idx[2]]);
00285
00286 newerror = newutility[2];
00287
00288 newerror += simple_lbg(elbg, elbg->dim, newcentroid, newutility, elbg->points,
00289 elbg->cells[idx[1]]);
00290
00291 if (olderror > newerror) {
00292 shift_codebook(elbg, idx, newcentroid);
00293
00294 elbg->error += newerror - olderror;
00295
00296 for (j=0; j<3; j++)
00297 update_utility_and_n_cb(elbg, idx[j], newutility[j]);
00298
00299 evaluate_utility_inc(elbg);
00300 }
00301 }
00302
00306 static void do_shiftings(elbg_data *elbg)
00307 {
00308 int idx[3];
00309
00310 evaluate_utility_inc(elbg);
00311
00312 for (idx[0]=0; idx[0] < elbg->numCB; idx[0]++)
00313 if (elbg->numCB*elbg->utility[idx[0]] < elbg->error) {
00314 if (elbg->utility_inc[elbg->numCB-1] == 0)
00315 return;
00316
00317 idx[1] = get_high_utility_cell(elbg);
00318 idx[2] = get_closest_codebook(elbg, idx[0]);
00319
00320 if (idx[1] != idx[0] && idx[1] != idx[2])
00321 try_shift_candidate(elbg, idx);
00322 }
00323 }
00324
00325 #define BIG_PRIME 433494437LL
00326
00327 void ff_init_elbg(int *points, int dim, int numpoints, int *codebook,
00328 int numCB, int max_steps, int *closest_cb,
00329 AVLFG *rand_state)
00330 {
00331 int i, k;
00332
00333 if (numpoints > 24*numCB) {
00334
00335
00336 int *temp_points = av_malloc(dim*(numpoints/8)*sizeof(int));
00337 for (i=0; i<numpoints/8; i++) {
00338 k = (i*BIG_PRIME) % numpoints;
00339 memcpy(temp_points + i*dim, points + k*dim, dim*sizeof(int));
00340 }
00341
00342 ff_init_elbg(temp_points, dim, numpoints/8, codebook, numCB, 2*max_steps, closest_cb, rand_state);
00343 ff_do_elbg(temp_points, dim, numpoints/8, codebook, numCB, 2*max_steps, closest_cb, rand_state);
00344
00345 av_free(temp_points);
00346
00347 } else
00348 for (i=0; i < numCB; i++)
00349 memcpy(codebook + i*dim, points + ((i*BIG_PRIME)%numpoints)*dim,
00350 dim*sizeof(int));
00351
00352 }
00353
00354 void ff_do_elbg(int *points, int dim, int numpoints, int *codebook,
00355 int numCB, int max_steps, int *closest_cb,
00356 AVLFG *rand_state)
00357 {
00358 int dist;
00359 elbg_data elbg_d;
00360 elbg_data *elbg = &elbg_d;
00361 int i, j, k, last_error, steps=0;
00362 int *dist_cb = av_malloc(numpoints*sizeof(int));
00363 int *size_part = av_malloc(numCB*sizeof(int));
00364 cell *list_buffer = av_malloc(numpoints*sizeof(cell));
00365 cell *free_cells;
00366 int best_dist, best_idx = 0;
00367
00368 elbg->error = INT_MAX;
00369 elbg->dim = dim;
00370 elbg->numCB = numCB;
00371 elbg->codebook = codebook;
00372 elbg->cells = av_malloc(numCB*sizeof(cell *));
00373 elbg->utility = av_malloc(numCB*sizeof(int));
00374 elbg->nearest_cb = closest_cb;
00375 elbg->points = points;
00376 elbg->utility_inc = av_malloc(numCB*sizeof(int));
00377 elbg->scratchbuf = av_malloc(5*dim*sizeof(int));
00378
00379 elbg->rand_state = rand_state;
00380
00381 do {
00382 free_cells = list_buffer;
00383 last_error = elbg->error;
00384 steps++;
00385 memset(elbg->utility, 0, numCB*sizeof(int));
00386 memset(elbg->cells, 0, numCB*sizeof(cell *));
00387
00388 elbg->error = 0;
00389
00390
00391
00392 for (i=0; i < numpoints; i++) {
00393 best_dist = distance_limited(elbg->points + i*elbg->dim, elbg->codebook + best_idx*elbg->dim, dim, INT_MAX);
00394 for (k=0; k < elbg->numCB; k++) {
00395 dist = distance_limited(elbg->points + i*elbg->dim, elbg->codebook + k*elbg->dim, dim, best_dist);
00396 if (dist < best_dist) {
00397 best_dist = dist;
00398 best_idx = k;
00399 }
00400 }
00401 elbg->nearest_cb[i] = best_idx;
00402 dist_cb[i] = best_dist;
00403 elbg->error += dist_cb[i];
00404 elbg->utility[elbg->nearest_cb[i]] += dist_cb[i];
00405 free_cells->index = i;
00406 free_cells->next = elbg->cells[elbg->nearest_cb[i]];
00407 elbg->cells[elbg->nearest_cb[i]] = free_cells;
00408 free_cells++;
00409 }
00410
00411 do_shiftings(elbg);
00412
00413 memset(size_part, 0, numCB*sizeof(int));
00414
00415 memset(elbg->codebook, 0, elbg->numCB*dim*sizeof(int));
00416
00417 for (i=0; i < numpoints; i++) {
00418 size_part[elbg->nearest_cb[i]]++;
00419 for (j=0; j < elbg->dim; j++)
00420 elbg->codebook[elbg->nearest_cb[i]*elbg->dim + j] +=
00421 elbg->points[i*elbg->dim + j];
00422 }
00423
00424 for (i=0; i < elbg->numCB; i++)
00425 vect_division(elbg->codebook + i*elbg->dim,
00426 elbg->codebook + i*elbg->dim, size_part[i], elbg->dim);
00427
00428 } while(((last_error - elbg->error) > DELTA_ERR_MAX*elbg->error) &&
00429 (steps < max_steps));
00430
00431 av_free(dist_cb);
00432 av_free(size_part);
00433 av_free(elbg->utility);
00434 av_free(list_buffer);
00435 av_free(elbg->cells);
00436 av_free(elbg->utility_inc);
00437 av_free(elbg->scratchbuf);
00438 }