Graphviz  2.29.20120524.0446
lib/neatogen/quad_prog_solve.c
Go to the documentation of this file.
00001 /* $Id$ $Revision$ */
00002 /* vim:set shiftwidth=4 ts=8: */
00003 
00004 /*************************************************************************
00005  * Copyright (c) 2011 AT&T Intellectual Property 
00006  * All rights reserved. This program and the accompanying materials
00007  * are made available under the terms of the Eclipse Public License v1.0
00008  * which accompanies this distribution, and is available at
00009  * http://www.eclipse.org/legal/epl-v10.html
00010  *
00011  * Contributors: See CVS logs. Details at http://www.graphviz.org/
00012  *************************************************************************/
00013 
00014 #include "digcola.h"
00015 #ifdef DIGCOLA
00016 #include <math.h>
00017 #include <stdlib.h>
00018 #include <time.h>
00019 #include <stdio.h>
00020 #include <float.h>
00021 #include <assert.h>
00022 #include "matrix_ops.h"
00023 #include "kkutils.h"
00024 #include "quad_prog_solver.h"
00025 
00026 #define quad_prog_tol 1e-2
00027 
00028 float **unpackMatrix(float *packedMat, int n)
00029 {
00030     float **mat;
00031     int i, j, k;
00032 
00033     mat = N_GNEW(n, float *);
00034     mat[0] = N_GNEW(n * n, float);
00035     set_vector_valf(n * n, 0, mat[0]);
00036     for (i = 1; i < n; i++) {
00037         mat[i] = mat[0] + i * n;
00038     }
00039 
00040     for (i = 0, k = 0; i < n; i++) {
00041         for (j = i; j < n; j++, k++) {
00042             mat[j][i] = mat[i][j] = packedMat[k];
00043         }
00044     }
00045     return mat;
00046 }
00047 
00048 static void ensureMonotonicOrdering(float *place, int n, int *ordering)
00049 {
00050     /* ensure that 'ordering' is monotonically increasing by 'place',  */
00051     /* this also implies that levels are separated in the initial layout */
00052     int i, node;
00053     float lower_bound = place[ordering[0]];
00054     for (i = 1; i < n; i++) {
00055         node = ordering[i];
00056         if (place[node] < lower_bound) {
00057             place[node] = lower_bound;
00058         }
00059         lower_bound = place[node];
00060     }
00061 }
00062 
00063 static void
00064 ensureMonotonicOrderingWithGaps(float *place, int n, int *ordering,
00065                                 int *levels, int num_levels,
00066                                 float levels_gap)
00067 {
00068     /* ensure that levels are separated in the initial layout and that 
00069      * places are monotonic increasing within layer
00070      */
00071 
00072     int i;
00073     int node, level, max_in_level;
00074     float lower_bound = (float) -1e9;
00075 
00076     level = -1;
00077     max_in_level = 0;
00078     for (i = 0; i < n; i++) {
00079         if (i >= max_in_level) {
00080             /* we are entering a new level */
00081             level++;
00082             if (level == num_levels) {
00083                 /* last_level */
00084                 max_in_level = n;
00085             } else {
00086                 max_in_level = levels[level];
00087             }
00088             lower_bound =
00089                 i > 0 ? place[ordering[i - 1]] + levels_gap : (float) -1e9;
00090             quicksort_placef(place, ordering, i, max_in_level - 1);
00091         }
00092 
00093         node = ordering[i];
00094         if (place[node] < lower_bound) {
00095             place[node] = lower_bound;
00096         }
00097     }
00098 }
00099 
00100 static void
00101 computeHierarchyBoundaries(float *place, int n, int *ordering, int *levels,
00102                            int num_levels, float *hierarchy_boundaries)
00103 {
00104     int i;
00105     for (i = 0; i < num_levels; i++) {
00106         hierarchy_boundaries[i] = place[ordering[levels[i] - 1]];
00107     }
00108 }
00109 
00110 
00111 int
00112 constrained_majorization_new(CMajEnv * e, float *b, float **coords,
00113                              int cur_axis, int dims, int max_iterations,
00114                              float *hierarchy_boundaries, float levels_gap)
00115 {
00116     int n = e->n;
00117     float *place = coords[cur_axis];
00118     float **lap = e->A;
00119     int *ordering = e->ordering;
00120     int *levels = e->levels;
00121     int num_levels = e->num_levels;
00122     int i, j;
00123     float new_place_i;
00124     boolean converged = FALSE;
00125     float upper_bound, lower_bound;
00126     int node;
00127     int left, right;
00128     float cur_place;
00129     float des_place_block;
00130     float block_deg;
00131     float toBlockConnectivity;
00132     float *lap_node;
00133     int block_len;
00134     int first_next_level;
00135     int level = -1, max_in_level = 0;
00136     float *desired_place;
00137     float *prefix_desired_place;
00138     float *suffix_desired_place;
00139     int *block;
00140     int *lev;
00141     int counter;
00142 
00143     if (max_iterations <= 0) {
00144         return 0;
00145     }
00146     if (levels_gap != 0) {
00147         return constrained_majorization_new_with_gaps(e, b, coords,
00148                                                       cur_axis, dims,
00149                                                       max_iterations,
00150                                                       hierarchy_boundaries,
00151                                                       levels_gap);
00152     }
00153 
00154     /* ensureMonotonicOrderingWithGaps(place, n, ordering, levels, num_levels);  */
00155     ensureMonotonicOrdering(place, n, ordering);
00156     /* it is important that in 'ordering' nodes are always sorted by layers, 
00157      * and within a layer by 'place'
00158      */
00159 
00160     /* the desired place of each individual node in the current block */
00161     desired_place = e->fArray1;
00162     /* the desired place of each prefix of current block */
00163     prefix_desired_place = e->fArray2;
00164     /* the desired place of each suffix of current block */
00165     suffix_desired_place = e->fArray3;
00166     /* current block (nodes connected by active constraints) */
00167     block = e->iArray1;
00168 
00169     lev = e->iArray2;           /* level of each node */
00170     for (i = 0; i < n; i++) {
00171         if (i >= max_in_level) {
00172             /* we are entering a new level */
00173             level++;
00174             if (level == num_levels) {
00175                 /* last_level */
00176                 max_in_level = n;
00177             } else {
00178                 max_in_level = levels[level];
00179             }
00180         }
00181         node = ordering[i];
00182         lev[node] = level;
00183     }
00184 
00185     for (counter = 0; counter < max_iterations && !converged; counter++) {
00186         converged = TRUE;
00187         lower_bound = -1e9;     /* no lower bound for first level */
00188         for (left = 0; left < n; left = right) {
00189             int best_i;
00190             double max_movement;
00191             double movement;
00192             float prefix_des_place, suffix_des_place;
00193             /* compute a block 'ordering[left]...ordering[right-1]' of 
00194              * nodes with the same coordinate:
00195              */
00196             cur_place = place[ordering[left]];
00197             for (right = left + 1; right < n; right++) {
00198                 if (place[ordering[right]] != cur_place) {
00199                     break;
00200                 }
00201             }
00202 
00203             /* compute desired place of nodes in block: */
00204             for (i = left; i < right; i++) {
00205                 node = ordering[i];
00206                 new_place_i = -b[node];
00207                 lap_node = lap[node];
00208                 for (j = 0; j < n; j++) {
00209                     if (j == node) {
00210                         continue;
00211                     }
00212                     new_place_i += lap_node[j] * place[j];
00213                 }
00214                 desired_place[node] = new_place_i / (-lap_node[node]);
00215             }
00216 
00217             /* reorder block by levels, and within levels by "relaxed" desired position */
00218             block_len = 0;
00219             first_next_level = 0;
00220             for (i = left; i < right; i = first_next_level) {
00221                 level = lev[ordering[i]];
00222                 if (level == num_levels) {
00223                     /* last_level */
00224                     first_next_level = right;
00225                 } else {
00226                     first_next_level = MIN(right, levels[level]);
00227                 }
00228 
00229                 /* First, collect all nodes with desired places smaller than current place */
00230                 for (j = i; j < first_next_level; j++) {
00231                     node = ordering[j];
00232                     if (desired_place[node] < cur_place) {
00233                         block[block_len++] = node;
00234                     }
00235                 }
00236                 /* Second, collect all nodes with desired places equal to current place */
00237                 for (j = i; j < first_next_level; j++) {
00238                     node = ordering[j];
00239                     if (desired_place[node] == cur_place) {
00240                         block[block_len++] = node;
00241                     }
00242                 }
00243                 /* Third, collect all nodes with desired places greater than current place */
00244                 for (j = i; j < first_next_level; j++) {
00245                     node = ordering[j];
00246                     if (desired_place[node] > cur_place) {
00247                         block[block_len++] = node;
00248                     }
00249                 }
00250             }
00251 
00252             /* loop through block and compute desired places of its prefixes */
00253             des_place_block = 0;
00254             block_deg = 0;
00255             for (i = 0; i < block_len; i++) {
00256                 node = block[i];
00257                 toBlockConnectivity = 0;
00258                 lap_node = lap[node];
00259                 for (j = 0; j < i; j++) {
00260                     toBlockConnectivity -= lap_node[block[j]];
00261                 }
00262                 toBlockConnectivity *= 2;
00263                 /* update block stats */
00264                 des_place_block =
00265                     (block_deg * des_place_block +
00266                      (-lap_node[node]) * desired_place[node] +
00267                      toBlockConnectivity * cur_place) / (block_deg -
00268                                                          lap_node[node] +
00269                                                          toBlockConnectivity);
00270                 prefix_desired_place[i] = des_place_block;
00271                 block_deg += toBlockConnectivity - lap_node[node];
00272             }
00273 
00274             /* loop through block and compute desired places of its suffixes */
00275             des_place_block = 0;
00276             block_deg = 0;
00277             for (i = block_len - 1; i >= 0; i--) {
00278                 node = block[i];
00279                 toBlockConnectivity = 0;
00280                 lap_node = lap[node];
00281                 for (j = i + 1; j < block_len; j++) {
00282                     toBlockConnectivity -= lap_node[block[j]];
00283                 }
00284                 toBlockConnectivity *= 2;
00285                 /* update block stats */
00286                 des_place_block =
00287                     (block_deg * des_place_block +
00288                      (-lap_node[node]) * desired_place[node] +
00289                      toBlockConnectivity * cur_place) / (block_deg -
00290                                                          lap_node[node] +
00291                                                          toBlockConnectivity);
00292                 suffix_desired_place[i] = des_place_block;
00293                 block_deg += toBlockConnectivity - lap_node[node];
00294             }
00295 
00296 
00297             /* now, find best place to split block */
00298             best_i = -1;
00299             max_movement = 0;
00300             for (i = 0; i < block_len; i++) {
00301                 suffix_des_place = suffix_desired_place[i];
00302                 prefix_des_place =
00303                     i > 0 ? prefix_desired_place[i - 1] : suffix_des_place;
00304                 /* limit moves to ensure that the prefix is placed before the suffix */
00305                 if (suffix_des_place < prefix_des_place) {
00306                     if (suffix_des_place < cur_place) {
00307                         if (prefix_des_place > cur_place) {
00308                             prefix_des_place = cur_place;
00309                         }
00310                         suffix_des_place = prefix_des_place;
00311                     } else if (prefix_des_place > cur_place) {
00312                         prefix_des_place = suffix_des_place;
00313                     }
00314                 }
00315                 movement =
00316                     (block_len - i) * fabs(suffix_des_place - cur_place) +
00317                     i * fabs(prefix_des_place - cur_place);
00318                 if (movement > max_movement) {
00319                     max_movement = movement;
00320                     best_i = i;
00321                 }
00322             }
00323             /* Actually move prefix and suffix */
00324             if (best_i >= 0) {
00325                 suffix_des_place = suffix_desired_place[best_i];
00326                 prefix_des_place =
00327                     best_i >
00328                     0 ? prefix_desired_place[best_i -
00329                                              1] : suffix_des_place;
00330 
00331                 /* compute right border of feasible move */
00332                 if (right >= n) {
00333                     /* no nodes after current block */
00334                     upper_bound = 1e9;
00335                 } else {
00336                     upper_bound = place[ordering[right]];
00337                 }
00338                 suffix_des_place = MIN(suffix_des_place, upper_bound);
00339                 prefix_des_place = MAX(prefix_des_place, lower_bound);
00340 
00341                 /* limit moves to ensure that the prefix is placed before the suffix */
00342                 if (suffix_des_place < prefix_des_place) {
00343                     if (suffix_des_place < cur_place) {
00344                         if (prefix_des_place > cur_place) {
00345                             prefix_des_place = cur_place;
00346                         }
00347                         suffix_des_place = prefix_des_place;
00348                     } else if (prefix_des_place > cur_place) {
00349                         prefix_des_place = suffix_des_place;
00350                     }
00351                 }
00352 
00353                 /* move prefix: */
00354                 for (i = 0; i < best_i; i++) {
00355                     place[block[i]] = prefix_des_place;
00356                 }
00357                 /* move suffix: */
00358                 for (i = best_i; i < block_len; i++) {
00359                     place[block[i]] = suffix_des_place;
00360                 }
00361 
00362                 lower_bound = suffix_des_place; /* lower bound for next block */
00363 
00364                 /* reorder 'ordering' to reflect change of places
00365                  * Note that it is enough to reorder the level where 
00366                  * the split was done
00367                  */
00368 #if 0
00369                 int max_in_level, min_in_level;
00370 
00371                 level = lev[best_i];
00372                 if (level == num_levels) {
00373                     /* last_level */
00374                     max_in_level = MIN(right, n);
00375                 } else {
00376                     max_in_level = MIN(right, levels[level]);
00377                 }
00378                 if (level == 0) {
00379                     /* first level */
00380                     min_in_level = MAX(left, 0);
00381                 } else {
00382                     min_in_level = MAX(left, levels[level - 1]);
00383                 }
00384 #endif
00385                 for (i = left; i < right; i++) {
00386                     ordering[i] = block[i - left];
00387                 }
00388                 converged = converged
00389                     && fabs(prefix_des_place - cur_place) < quad_prog_tol
00390                     && fabs(suffix_des_place - cur_place) < quad_prog_tol;
00391 
00392             } else {
00393                 /* no movement */
00394                 lower_bound = cur_place;        /* lower bound for next block */
00395             }
00396 
00397         }
00398     }
00399 
00400     computeHierarchyBoundaries(place, n, ordering, levels, num_levels,
00401                                hierarchy_boundaries);
00402 
00403     return counter;
00404 }
00405 
00406 #ifdef IPSEPCOLA
00407 static float *place;
00408 static int compare_incr(const void *a, const void *b)
00409 {
00410     if (place[*(int *) a] > place[*(int *) b]) {
00411         return 1;
00412     } else if (place[*(int *) a] < place[*(int *) b]) {
00413         return -1;
00414     }
00415     return 0;
00416 }
00417 
00418 /*
00419 While not converged: move everything towards the optimum, then satisfy constraints with as little displacement as possible.
00420 Returns number of iterations before convergence.
00421 */
00422 int constrained_majorization_gradient_projection(CMajEnv * e,
00423                                                  float *b, float **coords,
00424                                                  int ndims, int cur_axis,
00425                                                  int max_iterations,
00426                                                  float
00427                                                  *hierarchy_boundaries,
00428                                                  float levels_gap)
00429 {
00430 
00431     int i, j, counter;
00432     int *ordering = e->ordering;
00433     int *levels = e->levels;
00434     int num_levels = e->num_levels;
00435     boolean converged = FALSE;
00436     float *g = e->fArray1;
00437     float *old_place = e->fArray2;
00438     float *d = e->fArray4;
00439     float test = 0, tmptest = 0;
00440     float beta;
00441 
00442     if (max_iterations == 0)
00443         return 0;
00444 
00445     place = coords[cur_axis];
00446 #ifdef CONMAJ_LOGGING
00447     double prev_stress = 0;
00448     static int call_no = 0;
00449     for (i = 0; i < e->n; i++) {
00450         prev_stress += 2 * b[i] * place[i];
00451         for (j = 0; j < e->n; j++) {
00452             prev_stress -= e->A[i][j] * place[j] * place[i];
00453         }
00454     }
00455     FILE *logfile = fopen("constrained_majorization_log", "a");
00456 
00457     fprintf(logfile, "grad proj %d: stress=%f\n", call_no, prev_stress);
00458 #endif
00459     for (counter = 0; counter < max_iterations && !converged; counter++) {
00460         float alpha;
00461         float numerator = 0, denominator = 0, r;
00462         converged = TRUE;
00463         /* find steepest descent direction */
00464         for (i = 0; i < e->n; i++) {
00465             old_place[i] = place[i];
00466             g[i] = 2 * b[i];
00467             for (j = 0; j < e->n; j++) {
00468                 g[i] -= 2 * e->A[i][j] * place[j];
00469             }
00470         }
00471         for (i = 0; i < e->n; i++) {
00472             numerator += g[i] * g[i];
00473             r = 0;
00474             for (j = 0; j < e->n; j++) {
00475                 r += 2 * e->A[i][j] * g[j];
00476             }
00477             denominator -= r * g[i];
00478         }
00479         alpha = numerator / denominator;
00480         for (i = 0; i < e->n; i++) {
00481             if (alpha > 0 && alpha < 1000) {
00482                 place[i] -= alpha * g[i];
00483             }
00484         }
00485         if (num_levels)
00486             qsort((int *) ordering, (size_t) levels[0], sizeof(int),
00487                   compare_incr);
00488         /* project to constraint boundary */
00489         for (i = 0; i < num_levels; i++) {
00490             int endOfLevel = i == num_levels - 1 ? e->n : levels[i + 1];
00491             int ui, li, u, l;
00492 
00493             /* ensure monotic increase in position within levels */
00494             qsort((int *) ordering + levels[i],
00495                   (size_t) endOfLevel - levels[i], sizeof(int),
00496                   compare_incr);
00497             /* If there are overlapping levels find offending nodes and place at average position */
00498             ui = levels[i]; li = ui - 1;
00499             l = ordering[li--]; u = ordering[ui++];
00500             if (place[l] + levels_gap > place[u]) {
00501                 float sum =
00502                     place[l] + place[u] - levels_gap * (e->lev[l] +
00503                                                         e->lev[u]), w = 2;
00504                 float avgPos = sum / w;
00505                 float pos;
00506                 boolean finished;
00507                 do {
00508                     finished = TRUE;
00509                     if (ui < endOfLevel) {
00510                         u = ordering[ui];
00511                         pos = place[u] - levels_gap * e->lev[u];
00512                         if (pos < avgPos) {
00513                             ui++;
00514                             w++;
00515                             sum += pos;
00516                             avgPos = sum / w;
00517                             finished = FALSE;
00518                         }
00519                     }
00520 
00521                     if (li >= 0) {
00522                         l = ordering[li];
00523                         pos = place[l] - levels_gap * e->lev[l];
00524                         if (pos > avgPos) {
00525                             li--;
00526                             w++;
00527                             sum += pos;
00528                             avgPos = sum / w;
00529                             finished = FALSE;
00530                         }
00531                     }
00532                 } while (!finished);
00533                 for (j = li + 1; j < ui; j++) {
00534                     place[ordering[j]] =
00535                         avgPos + levels_gap * e->lev[ordering[j]];
00536                 }
00537             }
00538         }
00539         /* set place to the intersection of old_place-g and boundary and compute d, the vector from intersection pnt to projection pnt */
00540         for (i = 0; i < e->n; i++) {
00541             d[i] = place[i] - old_place[i];
00542         }
00543         /* now compute beta */
00544         numerator = 0, denominator = 0;
00545         for (i = 0; i < e->n; i++) {
00546             numerator += g[i] * d[i];
00547             r = 0;
00548             for (j = 0; j < e->n; j++) {
00549                 r += 2 * e->A[i][j] * d[j];
00550             }
00551             denominator += r * d[i];
00552         }
00553         beta = numerator / denominator;
00554 
00555         for (i = 0; i < e->n; i++) {
00556             if (beta > 0 && beta < 1.0) {
00557                 place[i] = old_place[i] + beta * d[i];
00558             }
00559             tmptest = fabs(place[i] - old_place[i]);
00560             if (test < tmptest)
00561                 test = tmptest;
00562         }
00563         computeHierarchyBoundaries(place, e->n, ordering, levels,
00564                                    num_levels, hierarchy_boundaries);
00565 #if 0
00566         if (num_levels)
00567             qsort((int *) ordering, (size_t) levels[0], sizeof(int),
00568                   compare_incr);
00569         for (i = 0; i < num_levels; i++) {
00570             int endOfLevel = i == num_levels - 1 ? e->n : levels[i + 1];
00571             /* ensure monotic increase in position within levels */
00572             qsort((int *) ordering + levels[i],
00573                   (size_t) endOfLevel - levels[i], sizeof(int),
00574                   compare_incr);
00575             /* If there are overlapping levels find offending nodes and place at average position */
00576             int l = ordering[levels[i] - 1], u = ordering[levels[i]];
00577             /* assert(place[l]+levels_gap<=place[u]+0.00001); */
00578         }
00579 #endif
00580 #ifdef CONMAJ_LOGGING
00581         double stress = 0;
00582         for (i = 0; i < e->n; i++) {
00583             stress += 2 * b[i] * place[i];
00584             for (j = 0; j < e->n; j++) {
00585                 stress -= e->A[i][j] * place[j] * place[i];
00586             }
00587         }
00588         fprintf(logfile, "%d: stress=%f, test=%f, %s\n", call_no, stress,
00589                 test, (stress >= prev_stress) ? "No Improvement" : "");
00590         prev_stress = stress;
00591 #endif
00592         if (test > quad_prog_tol) {
00593             converged = FALSE;
00594         }
00595     }
00596 #ifdef CONMAJ_LOGGING
00597     call_no++;
00598     fclose(logfile);
00599 #endif
00600     return counter;
00601 }
00602 #endif
00603 
00604 int
00605 constrained_majorization_new_with_gaps(CMajEnv * e, float *b,
00606                                        float **coords, int ndims,
00607                                        int cur_axis, int max_iterations,
00608                                        float *hierarchy_boundaries,
00609                                        float levels_gap)
00610 {
00611     float *place = coords[cur_axis];
00612     int i, j;
00613     int n = e->n;
00614     float **lap = e->A;
00615     int *ordering = e->ordering;
00616     int *levels = e->levels;
00617     int num_levels = e->num_levels;
00618     float new_place_i;
00619     boolean converged = FALSE;
00620     float upper_bound, lower_bound;
00621     int node;
00622     int left, right;
00623     float cur_place;
00624     float des_place_block;
00625     float block_deg;
00626     float toBlockConnectivity;
00627     float *lap_node;
00628     float *desired_place;
00629     float *prefix_desired_place;
00630     float *suffix_desired_place;
00631     int *block;
00632     int block_len;
00633     int first_next_level;
00634     int *lev;
00635     int level = -1, max_in_level = 0;
00636     int counter;
00637     float *gap;
00638     float total_gap, target_place;
00639 
00640     if (max_iterations <= 0) {
00641         return 0;
00642     }
00643 
00644     ensureMonotonicOrderingWithGaps(place, n, ordering, levels, num_levels,
00645                                     levels_gap);
00646     /* it is important that in 'ordering' nodes are always sorted by layers, 
00647      * and within a layer by 'place'
00648      */
00649 
00650     /* the desired place of each individual node in the current block */
00651     desired_place = e->fArray1;
00652     /* the desired place of each prefix of current block */
00653     prefix_desired_place = e->fArray2;
00654     /* the desired place of each suffix of current block */
00655     suffix_desired_place = e->fArray3;
00656     /* current block (nodes connected by active constraints) */
00657     block = e->iArray1;
00658 
00659     lev = e->iArray2;           /* level of each node */
00660     for (i = 0; i < n; i++) {
00661         if (i >= max_in_level) {
00662             /* we are entering a new level */
00663             level++;
00664             if (level == num_levels) {
00665                 /* last_level */
00666                 max_in_level = n;
00667             } else {
00668                 max_in_level = levels[level];
00669             }
00670         }
00671         node = ordering[i];
00672         lev[node] = level;
00673     }
00674 
00675     /* displacement of block's nodes from block's reference point */
00676     gap = e->fArray4;
00677 
00678     for (counter = 0; counter < max_iterations && !converged; counter++) {
00679         converged = TRUE;
00680         lower_bound = -1e9;     /* no lower bound for first level */
00681         for (left = 0; left < n; left = right) {
00682             int best_i;
00683             double max_movement;
00684             double movement;
00685             float prefix_des_place, suffix_des_place;
00686             /* compute a block 'ordering[left]...ordering[right-1]' of 
00687              * nodes connected with active constraints
00688              */
00689             cur_place = place[ordering[left]];
00690             total_gap = 0;
00691             target_place = cur_place;
00692             gap[ordering[left]] = 0;
00693             for (right = left + 1; right < n; right++) {
00694                 if (lev[right] > lev[right - 1]) {
00695                     /* we are entering a new level */
00696                     target_place += levels_gap; /* note that 'levels_gap' may be negative */
00697                     total_gap += levels_gap;
00698                 }
00699                 node = ordering[right];
00700 #if 0
00701                 if (place[node] != target_place)
00702 #endif
00703                     /* not sure if this is better than 'place[node]!=target_place' */
00704                     if (fabs(place[node] - target_place) > 1e-9) {
00705                         break;
00706                     }
00707                 gap[node] = place[node] - cur_place;
00708             }
00709 
00710             /* compute desired place of block's reference point according 
00711              * to each node in the block:
00712              */
00713             for (i = left; i < right; i++) {
00714                 node = ordering[i];
00715                 new_place_i = -b[node];
00716                 lap_node = lap[node];
00717                 for (j = 0; j < n; j++) {
00718                     if (j == node) {
00719                         continue;
00720                     }
00721                     new_place_i += lap_node[j] * place[j];
00722                 }
00723                 desired_place[node] =
00724                     new_place_i / (-lap_node[node]) - gap[node];
00725             }
00726 
00727             /* reorder block by levels, and within levels 
00728              * by "relaxed" desired position
00729              */
00730             block_len = 0;
00731             first_next_level = 0;
00732             for (i = left; i < right; i = first_next_level) {
00733                 level = lev[ordering[i]];
00734                 if (level == num_levels) {
00735                     /* last_level */
00736                     first_next_level = right;
00737                 } else {
00738                     first_next_level = MIN(right, levels[level]);
00739                 }
00740 
00741                 /* First, collect all nodes with desired places smaller 
00742                  * than current place
00743                  */
00744                 for (j = i; j < first_next_level; j++) {
00745                     node = ordering[j];
00746                     if (desired_place[node] < cur_place) {
00747                         block[block_len++] = node;
00748                     }
00749                 }
00750                 /* Second, collect all nodes with desired places equal 
00751                  * to current place
00752                  */
00753                 for (j = i; j < first_next_level; j++) {
00754                     node = ordering[j];
00755                     if (desired_place[node] == cur_place) {
00756                         block[block_len++] = node;
00757                     }
00758                 }
00759                 /* Third, collect all nodes with desired places greater 
00760                  * than current place
00761                  */
00762                 for (j = i; j < first_next_level; j++) {
00763                     node = ordering[j];
00764                     if (desired_place[node] > cur_place) {
00765                         block[block_len++] = node;
00766                     }
00767                 }
00768             }
00769 
00770             /* loop through block and compute desired places of its prefixes */
00771             des_place_block = 0;
00772             block_deg = 0;
00773             for (i = 0; i < block_len; i++) {
00774                 node = block[i];
00775                 toBlockConnectivity = 0;
00776                 lap_node = lap[node];
00777                 for (j = 0; j < i; j++) {
00778                     toBlockConnectivity -= lap_node[block[j]];
00779                 }
00780                 toBlockConnectivity *= 2;
00781                 /* update block stats */
00782                 des_place_block =
00783                     (block_deg * des_place_block +
00784                      (-lap_node[node]) * desired_place[node] +
00785                      toBlockConnectivity * cur_place) / (block_deg -
00786                                                          lap_node[node] +
00787                                                          toBlockConnectivity);
00788                 prefix_desired_place[i] = des_place_block;
00789                 block_deg += toBlockConnectivity - lap_node[node];
00790             }
00791 
00792             if (block_len == n) {
00793                 /* fix is needed since denominator was 0 in this case */
00794                 prefix_desired_place[n - 1] = cur_place;        /* a "neutral" value */
00795             }
00796 
00797             /* loop through block and compute desired places of its suffixes */
00798             des_place_block = 0;
00799             block_deg = 0;
00800             for (i = block_len - 1; i >= 0; i--) {
00801                 node = block[i];
00802                 toBlockConnectivity = 0;
00803                 lap_node = lap[node];
00804                 for (j = i + 1; j < block_len; j++) {
00805                     toBlockConnectivity -= lap_node[block[j]];
00806                 }
00807                 toBlockConnectivity *= 2;
00808                 /* update block stats */
00809                 des_place_block =
00810                     (block_deg * des_place_block +
00811                      (-lap_node[node]) * desired_place[node] +
00812                      toBlockConnectivity * cur_place) / (block_deg -
00813                                                          lap_node[node] +
00814                                                          toBlockConnectivity);
00815                 suffix_desired_place[i] = des_place_block;
00816                 block_deg += toBlockConnectivity - lap_node[node];
00817             }
00818 
00819             if (block_len == n) {
00820                 /* fix is needed since denominator was 0 in this case */
00821                 suffix_desired_place[0] = cur_place;    /* a "neutral" value? */
00822             }
00823 
00824 
00825             /* now, find best place to split block */
00826             best_i = -1;
00827             max_movement = 0;
00828             for (i = 0; i < block_len; i++) {
00829                 suffix_des_place = suffix_desired_place[i];
00830                 prefix_des_place =
00831                     i > 0 ? prefix_desired_place[i - 1] : suffix_des_place;
00832                 /* limit moves to ensure that the prefix is placed before the suffix */
00833                 if (suffix_des_place < prefix_des_place) {
00834                     if (suffix_des_place < cur_place) {
00835                         if (prefix_des_place > cur_place) {
00836                             prefix_des_place = cur_place;
00837                         }
00838                         suffix_des_place = prefix_des_place;
00839                     } else if (prefix_des_place > cur_place) {
00840                         prefix_des_place = suffix_des_place;
00841                     }
00842                 }
00843                 movement =
00844                     (block_len - i) * fabs(suffix_des_place - cur_place) +
00845                     i * fabs(prefix_des_place - cur_place);
00846                 if (movement > max_movement) {
00847                     max_movement = movement;
00848                     best_i = i;
00849                 }
00850             }
00851             /* Actually move prefix and suffix */
00852             if (best_i >= 0) {
00853                 suffix_des_place = suffix_desired_place[best_i];
00854                 prefix_des_place =
00855                     best_i >
00856                     0 ? prefix_desired_place[best_i -
00857                                              1] : suffix_des_place;
00858 
00859                 /* compute right border of feasible move */
00860                 if (right >= n) {
00861                     /* no nodes after current block */
00862                     upper_bound = 1e9;
00863                 } else {
00864                     /* notice that we have to deduct 'gap[block[block_len-1]]'
00865                      * since all computations should be relative to 
00866                      * the block's reference point
00867                      */
00868                     if (lev[ordering[right]] > lev[ordering[right - 1]]) {
00869                         upper_bound =
00870                             place[ordering[right]] - levels_gap -
00871                             gap[block[block_len - 1]];
00872                     } else {
00873                         upper_bound =
00874                             place[ordering[right]] -
00875                             gap[block[block_len - 1]];
00876                     }
00877                 }
00878                 suffix_des_place = MIN(suffix_des_place, upper_bound);
00879                 prefix_des_place = MAX(prefix_des_place, lower_bound);
00880 
00881                 /* limit moves to ensure that the prefix is placed before the suffix */
00882                 if (suffix_des_place < prefix_des_place) {
00883                     if (suffix_des_place < cur_place) {
00884                         if (prefix_des_place > cur_place) {
00885                             prefix_des_place = cur_place;
00886                         }
00887                         suffix_des_place = prefix_des_place;
00888                     } else if (prefix_des_place > cur_place) {
00889                         prefix_des_place = suffix_des_place;
00890                     }
00891                 }
00892 
00893                 /* move prefix: */
00894                 for (i = 0; i < best_i; i++) {
00895                     place[block[i]] = prefix_des_place + gap[block[i]];
00896                 }
00897                 /* move suffix: */
00898                 for (i = best_i; i < block_len; i++) {
00899                     place[block[i]] = suffix_des_place + gap[block[i]];
00900                 }
00901 
00902 
00903                 /* compute lower bound for next block */
00904                 if (right < n
00905                     && lev[ordering[right]] > lev[ordering[right - 1]]) {
00906                     lower_bound = place[block[block_len - 1]] + levels_gap;
00907                 } else {
00908                     lower_bound = place[block[block_len - 1]];
00909                 }
00910 
00911 
00912                 /* reorder 'ordering' to reflect change of places
00913                  * Note that it is enough to reorder the level where 
00914                  * the split was done
00915                  */
00916 #if 0
00917                 int max_in_level, min_in_level;
00918 
00919                 level = lev[best_i];
00920                 if (level == num_levels) {
00921                     /* last_level */
00922                     max_in_level = MIN(right, n);
00923                 } else {
00924                     max_in_level = MIN(right, levels[level]);
00925                 }
00926                 if (level == 0) {
00927                     /* first level */
00928                     min_in_level = MAX(left, 0);
00929                 } else {
00930                     min_in_level = MAX(left, levels[level - 1]);
00931                 }
00932 #endif
00933                 for (i = left; i < right; i++) {
00934                     ordering[i] = block[i - left];
00935                 }
00936                 converged = converged
00937                     && fabs(prefix_des_place - cur_place) < quad_prog_tol
00938                     && fabs(suffix_des_place - cur_place) < quad_prog_tol;
00939 
00940 
00941             } else {
00942                 /* no movement */
00943                 /* compute lower bound for next block */
00944                 if (right < n
00945                     && lev[ordering[right]] > lev[ordering[right - 1]]) {
00946                     lower_bound = place[block[block_len - 1]] + levels_gap;
00947                 } else {
00948                     lower_bound = place[block[block_len - 1]];
00949                 }
00950             }
00951         }
00952         orthog1f(n, place);     /* for numerical stability, keep ||place|| small */
00953         computeHierarchyBoundaries(place, n, ordering, levels, num_levels,
00954                                    hierarchy_boundaries);
00955     }
00956 
00957     return counter;
00958 }
00959 
00960 void deleteCMajEnv(CMajEnv * e)
00961 {
00962     free(e->A[0]);
00963     free(e->A);
00964     free(e->lev);
00965     free(e->fArray1);
00966     free(e->fArray2);
00967     free(e->fArray3);
00968     free(e->fArray4);
00969     free(e->iArray1);
00970     free(e->iArray2);
00971     free(e->iArray3);
00972     free(e->iArray4);
00973     free(e);
00974 }
00975 
00976 CMajEnv *initConstrainedMajorization(float *packedMat, int n,
00977                                      int *ordering, int *levels,
00978                                      int num_levels)
00979 {
00980     int i, level = -1, start_of_level_above = 0;
00981     CMajEnv *e = GNEW(CMajEnv);
00982     e->A = NULL;
00983     e->n = n;
00984     e->ordering = ordering;
00985     e->levels = levels;
00986     e->num_levels = num_levels;
00987     e->A = unpackMatrix(packedMat, n);
00988     e->lev = N_GNEW(n, int);
00989     for (i = 0; i < e->n; i++) {
00990         if (i >= start_of_level_above) {
00991             level++;
00992             start_of_level_above =
00993                 (level == num_levels) ? e->n : levels[level];
00994         }
00995         e->lev[ordering[i]] = level;
00996     }
00997     e->fArray1 = N_GNEW(n, float);
00998     e->fArray2 = N_GNEW(n, float);
00999     e->fArray3 = N_GNEW(n, float);
01000     e->fArray4 = N_GNEW(n, float);
01001     e->iArray1 = N_GNEW(n, int);
01002     e->iArray2 = N_GNEW(n, int);
01003     e->iArray3 = N_GNEW(n, int);
01004     e->iArray4 = N_GNEW(n, int);
01005     return e;
01006 }
01007 #endif                          /* DIGCOLA */