/** * Evaluate if a shift lower the error. If it does, call shift_codebooks * and update elbg->error, elbg->utility and elbg->nearest_cb. * * @param elbg Internal elbg data * @param idx {luc (low utility cell, huc (high utility cell), cluc (closest cell to low utility cell)} */ static void try_shift_candidate(elbg_data *elbg, int idx[3]) { int j, k, olderror = 0, newerror, cont = 0; int newutility[3]; int *newcentroid[3] = { elbg->scratchbuf, elbg->scratchbuf + elbg->dim, elbg->scratchbuf + 2 * elbg->dim }; cell *tempcell; for (j = 0; j < 3; j++) olderror += elbg->utility[idx[j]]; memset(newcentroid[2], 0, elbg->dim * sizeof(int)); for (k = 0; k < 2; k++) for (tempcell = elbg->cells[idx[2*k]]; tempcell; tempcell = tempcell->next) { cont++; for (j = 0; j < elbg->dim; j++) newcentroid[2][j] += elbg->points[tempcell->index*elbg->dim + j]; } vect_division(newcentroid[2], newcentroid[2], cont, elbg->dim); get_new_centroids(elbg, idx[1], newcentroid[0], newcentroid[1]); newutility[2] = eval_error_cell(elbg, newcentroid[2], elbg->cells[idx[0]]); newutility[2] += eval_error_cell(elbg, newcentroid[2], elbg->cells[idx[2]]); newerror = newutility[2]; newerror += simple_lbg(elbg, elbg->dim, newcentroid, newutility, elbg->points, elbg->cells[idx[1]]); if (olderror > newerror) { shift_codebook(elbg, idx, newcentroid); elbg->error += newerror - olderror; for (j = 0; j < 3; j++) update_utility_and_n_cb(elbg, idx[j], newutility[j]); evaluate_utility_inc(elbg); } }
/** * Implementation of the ELBG block */ static void do_shiftings(elbg_data *elbg) { int idx[3]; evaluate_utility_inc(elbg); for (idx[0]=0; idx[0] < elbg->numCB; idx[0]++) if (elbg->numCB*elbg->utility[idx[0]] < elbg->error) { if (elbg->utility_inc[elbg->numCB-1] == 0) return; idx[1] = get_high_utility_cell(elbg); idx[2] = get_closest_codebook(elbg, idx[0]); try_shift_candidate(elbg, idx); } }