linear-assignment.con commit Merge branch 'jk/save-getenv-result' (773e408)
   1/*
   2 * Based on: Jonker, R., & Volgenant, A. (1987). <i>A shortest augmenting path
   3 * algorithm for dense and sparse linear assignment problems</i>. Computing,
   4 * 38(4), 325-340.
   5 */
   6#include "cache.h"
   7#include "linear-assignment.h"
   8
   9#define COST(column, row) cost[(column) + column_count * (row)]
  10
  11/*
  12 * The parameter `cost` is the cost matrix: the cost to assign column j to row
  13 * i is `cost[j + column_count * i].
  14 */
  15void compute_assignment(int column_count, int row_count, int *cost,
  16                        int *column2row, int *row2column)
  17{
  18        int *v, *d;
  19        int *free_row, free_count = 0, saved_free_count, *pred, *col;
  20        int i, j, phase;
  21
  22        if (column_count < 2) {
  23                memset(column2row, 0, sizeof(int) * column_count);
  24                memset(row2column, 0, sizeof(int) * row_count);
  25                return;
  26        }
  27
  28        memset(column2row, -1, sizeof(int) * column_count);
  29        memset(row2column, -1, sizeof(int) * row_count);
  30        ALLOC_ARRAY(v, column_count);
  31
  32        /* column reduction */
  33        for (j = column_count - 1; j >= 0; j--) {
  34                int i1 = 0;
  35
  36                for (i = 1; i < row_count; i++)
  37                        if (COST(j, i1) > COST(j, i))
  38                                i1 = i;
  39                v[j] = COST(j, i1);
  40                if (row2column[i1] == -1) {
  41                        /* row i1 unassigned */
  42                        row2column[i1] = j;
  43                        column2row[j] = i1;
  44                } else {
  45                        if (row2column[i1] >= 0)
  46                                row2column[i1] = -2 - row2column[i1];
  47                        column2row[j] = -1;
  48                }
  49        }
  50
  51        /* reduction transfer */
  52        ALLOC_ARRAY(free_row, row_count);
  53        for (i = 0; i < row_count; i++) {
  54                int j1 = row2column[i];
  55                if (j1 == -1)
  56                        free_row[free_count++] = i;
  57                else if (j1 < -1)
  58                        row2column[i] = -2 - j1;
  59                else {
  60                        int min = COST(!j1, i) - v[!j1];
  61                        for (j = 1; j < column_count; j++)
  62                                if (j != j1 && min > COST(j, i) - v[j])
  63                                        min = COST(j, i) - v[j];
  64                        v[j1] -= min;
  65                }
  66        }
  67
  68        if (free_count ==
  69            (column_count < row_count ? row_count - column_count : 0)) {
  70                free(v);
  71                free(free_row);
  72                return;
  73        }
  74
  75        /* augmenting row reduction */
  76        for (phase = 0; phase < 2; phase++) {
  77                int k = 0;
  78
  79                saved_free_count = free_count;
  80                free_count = 0;
  81                while (k < saved_free_count) {
  82                        int u1, u2;
  83                        int j1 = 0, j2, i0;
  84
  85                        i = free_row[k++];
  86                        u1 = COST(j1, i) - v[j1];
  87                        j2 = -1;
  88                        u2 = INT_MAX;
  89                        for (j = 1; j < column_count; j++) {
  90                                int c = COST(j, i) - v[j];
  91                                if (u2 > c) {
  92                                        if (u1 < c) {
  93                                                u2 = c;
  94                                                j2 = j;
  95                                        } else {
  96                                                u2 = u1;
  97                                                u1 = c;
  98                                                j2 = j1;
  99                                                j1 = j;
 100                                        }
 101                                }
 102                        }
 103                        if (j2 < 0) {
 104                                j2 = j1;
 105                                u2 = u1;
 106                        }
 107
 108                        i0 = column2row[j1];
 109                        if (u1 < u2)
 110                                v[j1] -= u2 - u1;
 111                        else if (i0 >= 0) {
 112                                j1 = j2;
 113                                i0 = column2row[j1];
 114                        }
 115
 116                        if (i0 >= 0) {
 117                                if (u1 < u2)
 118                                        free_row[--k] = i0;
 119                                else
 120                                        free_row[free_count++] = i0;
 121                        }
 122                        row2column[i] = j1;
 123                        column2row[j1] = i;
 124                }
 125        }
 126
 127        /* augmentation */
 128        saved_free_count = free_count;
 129        ALLOC_ARRAY(d, column_count);
 130        ALLOC_ARRAY(pred, column_count);
 131        ALLOC_ARRAY(col, column_count);
 132        for (free_count = 0; free_count < saved_free_count; free_count++) {
 133                int i1 = free_row[free_count], low = 0, up = 0, last, k;
 134                int min, c, u1;
 135
 136                for (j = 0; j < column_count; j++) {
 137                        d[j] = COST(j, i1) - v[j];
 138                        pred[j] = i1;
 139                        col[j] = j;
 140                }
 141
 142                j = -1;
 143                do {
 144                        last = low;
 145                        min = d[col[up++]];
 146                        for (k = up; k < column_count; k++) {
 147                                j = col[k];
 148                                c = d[j];
 149                                if (c <= min) {
 150                                        if (c < min) {
 151                                                up = low;
 152                                                min = c;
 153                                        }
 154                                        col[k] = col[up];
 155                                        col[up++] = j;
 156                                }
 157                        }
 158                        for (k = low; k < up; k++)
 159                                if (column2row[col[k]] == -1)
 160                                        goto update;
 161
 162                        /* scan a row */
 163                        do {
 164                                int j1 = col[low++];
 165
 166                                i = column2row[j1];
 167                                u1 = COST(j1, i) - v[j1] - min;
 168                                for (k = up; k < column_count; k++) {
 169                                        j = col[k];
 170                                        c = COST(j, i) - v[j] - u1;
 171                                        if (c < d[j]) {
 172                                                d[j] = c;
 173                                                pred[j] = i;
 174                                                if (c == min) {
 175                                                        if (column2row[j] == -1)
 176                                                                goto update;
 177                                                        col[k] = col[up];
 178                                                        col[up++] = j;
 179                                                }
 180                                        }
 181                                }
 182                        } while (low != up);
 183                } while (low == up);
 184
 185update:
 186                /* updating of the column pieces */
 187                for (k = 0; k < last; k++) {
 188                        int j1 = col[k];
 189                        v[j1] += d[j1] - min;
 190                }
 191
 192                /* augmentation */
 193                do {
 194                        if (j < 0)
 195                                BUG("negative j: %d", j);
 196                        i = pred[j];
 197                        column2row[j] = i;
 198                        SWAP(j, row2column[i]);
 199                } while (i1 != i);
 200        }
 201
 202        free(col);
 203        free(pred);
 204        free(d);
 205        free(v);
 206        free(free_row);
 207}