• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

paulmthompson / WhiskerToolbox / 18389801194

09 Oct 2025 09:35PM UTC coverage: 71.943% (+0.1%) from 71.826%
18389801194

push

github

paulmthompson
add correlation matrix to filtering interface

207 of 337 new or added lines in 5 files covered. (61.42%)

867 existing lines in 31 files now uncovered.

49964 of 69449 relevant lines covered (71.94%)

1103.53 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

67.59
/src/StateEstimation/Assignment/hungarian.cpp
1
/* This is an implementation of the Hungarian algorithm in C++
2
 * The Hungarian algorithm, also know as Munkres or Kuhn-Munkres
3
 * algorithm is usefull for solving the assignment problem.
4
 *
5
 * Assignment problem: Let C be an n x n matrix 
6
 * representing the costs of each of n workers to perform any of n jobs.
7
 * The assignment problem is to assign jobs to workers so as to 
8
 * minimize the total cost. Since each worker can perform only one job and 
9
 * each job can be assigned to only one worker the assignments constitute 
10
 * an independent set of the matrix C.
11
 * 
12
 * It is a port heavily based on http://csclab.murraystate.edu/~bob.pilgrim/445/munkres.html
13
 * 
14
 * This version is written by Fernando B. Giannasi */
15

16
#include <algorithm>
17
#include <cmath>
18
#include <iostream>
19
#include <iterator>
20
#include <limits>
21
#include <list>
22
#include <stdexcept>
23
#include <string>
24
#include <type_traits>
25
#include <vector>
26

27

28
namespace Munkres {
29

30
/* Utility function to print Matrix */
31
template<template<typename, typename...> class Container,
32
         typename T,
33
         typename... Args>
34
//disable for string, which is std::basic_string<char>, a container itself
35
typename std::enable_if<!std::is_convertible<Container<T, Args...>, std::string>::value &&
36
                                !std::is_constructible<Container<T, Args...>, std::string>::value,
37
                        std::ostream &>::type
38
operator<<(std::ostream & os, Container<T, Args...> const & con) {
39
    os << " ";
40
    for (auto & elem: con)
41
        os << elem << " ";
42

43
    os << "\n";
44
    return os;
45
}
46

47
/* Handle negative elements if present. If allowed = true, add abs(minval) to 
48
  * every element to create one zero. Else throw an exception */
49
template<typename T>
50
void handle_negatives(std::vector<std::vector<T>> & matrix,
×
51
                      bool allowed = true) {
52
    T minval = std::numeric_limits<T>::max();
×
53

54
    for (auto & elem: matrix)
×
55
        for (auto & num: elem)
×
56
            minval = std::min(minval, num);
×
57

58
    if (minval < 0) {
×
59
        if (!allowed) {//throw
×
60
            throw std::runtime_error("Only non-negative values allowed");
×
61
        } else {// add abs(minval) to every element to create one zero
62
            minval = abs(minval);
×
63

64
            for (auto & elem: matrix)
×
65
                for (auto & num: elem)
×
66
                    num += minval;
×
67
        }
68
    }
69
}
×
70

71
/* Ensure that the matrix is square by the addition of dummy rows/columns if necessary */
72
template<typename T>
73
void pad_matrix(std::vector<std::vector<T>> & matrix) {
7✔
74
    std::size_t i_size = matrix.size();
7✔
75
    std::size_t j_size = matrix[0].size();
7✔
76

77
    if (i_size > j_size) {
7✔
UNCOV
78
        for (auto & vec: matrix)
×
UNCOV
79
            vec.resize(i_size, std::numeric_limits<T>::max());
×
80
    } else if (i_size < j_size) {
7✔
81
        while (matrix.size() < j_size)
×
82
            matrix.push_back(std::vector<T>(j_size, std::numeric_limits<T>::max()));
×
83
    }
84
}
7✔
85

86
/* For each row of the matrix, find the smallest element and subtract it from every 
87
  * element in its row.  
88
  * For each col of the matrix, find the smallest element and subtract it from every 
89
  * element in its col. Go to Step 2. */
90
template<typename T>
91
void step1(std::vector<std::vector<T>> & matrix,
7✔
92
           int & step) {
93
    // process rows
94
    for (auto & row: matrix) {
22✔
95
        auto smallest = *std::min_element(begin(row), end(row));
30✔
96
        if (smallest > 0)
15✔
97
            for (auto & n: row)
50✔
98
                n -= smallest;
35✔
99
    }
100

101
    // process cols
102
    int sz = matrix.size();// square matrix is granted
7✔
103
    for (int j = 0; j < sz; ++j) {
22✔
104
        T minval = std::numeric_limits<T>::max();
15✔
105
        for (int i = 0; i < sz; ++i) {
50✔
106
            minval = std::min(minval, matrix[i][j]);
35✔
107
        }
108

109
        if (minval > 0) {
15✔
110
            for (int i = 0; i < sz; ++i) {
4✔
111
                matrix[i][j] -= minval;
3✔
112
            }
113
        }
114
    }
115

116
    step = 2;
7✔
117
}
7✔
118

119
/* helper to clear the temporary vectors */
120
inline void clear_covers(std::vector<int> & cover) {
16✔
121
    for (auto & n: cover) n = 0;
50✔
122
}
16✔
123

124
/* Find a zero (Z) in the resulting matrix.  If there is no starred zero in its row or 
125
  * column, star Z. Repeat for each element in the matrix. Go to Step 3.  In this step, 
126
  * we introduce the mask matrix M, which in the same dimensions as the cost matrix and 
127
  * is used to star and prime zeros of the cost matrix.  If M(i,j)=1 then C(i,j) is a 
128
  * starred zero,  If M(i,j)=2 then C(i,j) is a primed zero.  We also define two vectors 
129
  * RowCover and ColCover that are used to "cover" the rows and columns of the cost matrix.
130
  * In the nested loop (over indices i and j) we check to see if C(i,j) is a zero value 
131
  * and if its column or row is not already covered.  If not then we star this zero 
132
  * (i.e. set M(i,j)=1) and cover its row and column (i.e. set R_cov(i)=1 and C_cov(j)=1).
133
  * Before we go on to Step 3, we uncover all rows and columns so that we can use the 
134
  * cover vectors to help us count the number of starred zeros. */
135
template<typename T>
136
void step2(std::vector<std::vector<T>> const & matrix,
7✔
137
           std::vector<std::vector<int>> & M,
138
           std::vector<int> & RowCover,
139
           std::vector<int> & ColCover,
140
           int & step) {
141
    int sz = matrix.size();
7✔
142

143
    for (int r = 0; r < sz; ++r)
22✔
144
        for (int c = 0; c < sz; ++c)
50✔
145
            if (matrix[r][c] == 0)
35✔
146
                if (RowCover[r] == 0 && ColCover[c] == 0) {
17✔
147
                    M[r][c] = 1;
14✔
148
                    RowCover[r] = 1;
14✔
149
                    ColCover[c] = 1;
14✔
150
                }
151

152
    clear_covers(RowCover);// reset vectors for posterior using
7✔
153
    clear_covers(ColCover);
7✔
154

155
    step = 3;
7✔
156
}
7✔
157

158

159
/* Cover each column containing a starred zero.  If K columns are covered, the starred 
160
  * zeros describe a complete set of unique assignments.  In this case, Go to DONE, 
161
  * otherwise, Go to Step 4. Once we have searched the entire cost matrix, we count the 
162
  * number of independent zeros found.  If we have found (and starred) K independent zeros 
163
  * then we are done.  If not we procede to Step 4.*/
164
void step3(std::vector<std::vector<int>> const & M,
8✔
165
           std::vector<int> & ColCover,
166
           int & step) {
167
    int sz = M.size();
8✔
168
    int colcount = 0;
8✔
169

170
    for (int r = 0; r < sz; ++r)
25✔
171
        for (int c = 0; c < sz; ++c)
56✔
172
            if (M[r][c] == 1)
39✔
173
                ColCover[c] = 1;
16✔
174

175
    for (auto & n: ColCover)
25✔
176
        if (n == 1)
17✔
177
            colcount++;
16✔
178

179
    if (colcount >= sz) {
8✔
180
        step = 7;// solution found
7✔
181
    } else {
182
        step = 4;
1✔
183
    }
184
}
8✔
185

186
// Following functions to support step 4
187
template<typename T>
188
void find_a_zero(int & row,
2✔
189
                 int & col,
190
                 std::vector<std::vector<T>> const & matrix,
191
                 std::vector<int> const & RowCover,
192
                 std::vector<int> const & ColCover) {
193
    int r = 0;
2✔
194
    int c = 0;
2✔
195
    int sz = matrix.size();
2✔
196
    bool done = false;
2✔
197
    row = -1;
2✔
198
    col = -1;
2✔
199

200
    while (!done) {
5✔
201
        c = 0;
3✔
202
        while (true) {
203
            if (matrix[r][c] == 0 && RowCover[r] == 0 && ColCover[c] == 0) {
5✔
204
                row = r;
2✔
205
                col = c;
2✔
206
                done = true;
2✔
207
            }
208
            c += 1;
5✔
209
            if (c >= sz || done)
5✔
210
                break;
211
        }
212
        r += 1;
3✔
213
        if (r >= sz)
3✔
214
            done = true;
1✔
215
    }
216
}
2✔
217

218
bool star_in_row(int row,
2✔
219
                 std::vector<std::vector<int>> const & M) {
220
    bool tmp = false;
2✔
221
    for (unsigned c = 0; c < M.size(); c++)
6✔
222
        if (M[row][c] == 1)
4✔
223
            tmp = true;
1✔
224

225
    return tmp;
2✔
226
}
227

228

229
void find_star_in_row(int row,
1✔
230
                      int & col,
231
                      std::vector<std::vector<int>> const & M) {
232
    col = -1;
1✔
233
    for (unsigned c = 0; c < M.size(); c++)
3✔
234
        if (M[row][c] == 1)
2✔
235
            col = c;
1✔
236
}
1✔
237

238

239
/* Find a noncovered zero and prime it.  If there is no starred zero in the row containing
240
  * this primed zero, Go to Step 5.  Otherwise, cover this row and uncover the column 
241
  * containing the starred zero. Continue in this manner until there are no uncovered zeros
242
  * left. Save the smallest uncovered value and Go to Step 6. */
243
template<typename T>
244
void step4(std::vector<std::vector<T>> const & matrix,
1✔
245
           std::vector<std::vector<int>> & M,
246
           std::vector<int> & RowCover,
247
           std::vector<int> & ColCover,
248
           int & path_row_0,
249
           int & path_col_0,
250
           int & step) {
251
    int row = -1;
1✔
252
    int col = -1;
1✔
253
    bool done = false;
1✔
254

255
    while (!done) {
3✔
256
        find_a_zero(row, col, matrix, RowCover, ColCover);
2✔
257

258
        if (row == -1) {
2✔
UNCOV
259
            done = true;
×
UNCOV
260
            step = 6;
×
261
        } else {
262
            M[row][col] = 2;
2✔
263
            if (star_in_row(row, M)) {
2✔
264
                find_star_in_row(row, col, M);
1✔
265
                RowCover[row] = 1;
1✔
266
                ColCover[col] = 0;
1✔
267
            } else {
268
                done = true;
1✔
269
                step = 5;
1✔
270
                path_row_0 = row;
1✔
271
                path_col_0 = col;
1✔
272
            }
273
        }
274
    }
275
}
1✔
276

277
// Following functions to support step 5
278
void find_star_in_col(int c,
2✔
279
                      int & r,
280
                      std::vector<std::vector<int>> const & M) {
281
    r = -1;
2✔
282
    for (unsigned i = 0; i < M.size(); i++)
6✔
283
        if (M[i][c] == 1)
4✔
284
            r = i;
1✔
285
}
2✔
286

287
void find_prime_in_row(int r,
1✔
288
                       int & c,
289
                       std::vector<std::vector<int>> const & M) {
290
    for (unsigned j = 0; j < M.size(); j++)
3✔
291
        if (M[r][j] == 2)
2✔
292
            c = j;
1✔
293
}
1✔
294

295
void augment_path(std::vector<std::vector<int>> & path,
1✔
296
                  int path_count,
297
                  std::vector<std::vector<int>> & M) {
298
    for (int p = 0; p < path_count; p++)
4✔
299
        if (M[path[p][0]][path[p][1]] == 1)
3✔
300
            M[path[p][0]][path[p][1]] = 0;
1✔
301
        else
302
            M[path[p][0]][path[p][1]] = 1;
2✔
303
}
1✔
304

305
void erase_primes(std::vector<std::vector<int>> & M) {
1✔
306
    for (auto & row: M)
3✔
307
        for (auto & val: row)
6✔
308
            if (val == 2)
4✔
UNCOV
309
                val = 0;
×
310
}
1✔
311

312

313
/* Construct a series of alternating primed and starred zeros as follows.  
314
  * Let Z0 represent the uncovered primed zero found in Step 4.  Let Z1 denote the 
315
  * starred zero in the column of Z0 (if any). Let Z2 denote the primed zero in the 
316
  * row of Z1 (there will always be one).  Continue until the series terminates at a 
317
  * primed zero that has no starred zero in its column.  Unstar each starred zero of 
318
  * the series, star each primed zero of the series, erase all primes and uncover every 
319
  * line in the matrix.  Return to Step 3.  You may notice that Step 5 seems vaguely 
320
  * familiar.  It is a verbal description of the augmenting path algorithm (for solving
321
  * the maximal matching problem). */
322
void step5(std::vector<std::vector<int>> & path,
1✔
323
           int path_row_0,
324
           int path_col_0,
325
           std::vector<std::vector<int>> & M,
326
           std::vector<int> & RowCover,
327
           std::vector<int> & ColCover,
328
           int & step) {
329
    int r = -1;
1✔
330
    int c = -1;
1✔
331
    int path_count = 1;
1✔
332

333
    path[path_count - 1][0] = path_row_0;
1✔
334
    path[path_count - 1][1] = path_col_0;
1✔
335

336
    bool done = false;
1✔
337
    while (!done) {
3✔
338
        find_star_in_col(path[path_count - 1][1], r, M);
2✔
339
        if (r > -1) {
2✔
340
            path_count += 1;
1✔
341
            // Bounds check to prevent buffer overflow
342
            if (path_count > static_cast<int>(path.size())) {
1✔
343
                throw std::runtime_error("Hungarian algorithm: path length exceeded maximum size");
×
344
            }
345
            path[path_count - 1][0] = r;
1✔
346
            path[path_count - 1][1] = path[path_count - 2][1];
1✔
347
        } else {
348
            done = true;
1✔
349
        }
350

351
        if (!done) {
2✔
352
            find_prime_in_row(path[path_count - 1][0], c, M);
1✔
353
            path_count += 1;
1✔
354
            // Bounds check to prevent buffer overflow
355
            if (path_count > static_cast<int>(path.size())) {
1✔
356
                throw std::runtime_error("Hungarian algorithm: path length exceeded maximum size");
×
357
            }
358
            path[path_count - 1][0] = path[path_count - 2][0];
1✔
359
            path[path_count - 1][1] = c;
1✔
360
        }
361
    }
362

363
    augment_path(path, path_count, M);
1✔
364
    clear_covers(RowCover);
1✔
365
    clear_covers(ColCover);
1✔
366
    erase_primes(M);
1✔
367

368
    step = 3;
1✔
369
}
1✔
370

371
// methods to support step 6
372
template<typename T>
UNCOV
373
void find_smallest(T & minval,
×
374
                   std::vector<std::vector<T>> const & matrix,
375
                   std::vector<int> const & RowCover,
376
                   std::vector<int> const & ColCover) {
UNCOV
377
    for (unsigned r = 0; r < matrix.size(); r++)
×
UNCOV
378
        for (unsigned c = 0; c < matrix.size(); c++)
×
UNCOV
379
            if (RowCover[r] == 0 && ColCover[c] == 0)
×
UNCOV
380
                if (minval > matrix[r][c])
×
UNCOV
381
                    minval = matrix[r][c];
×
UNCOV
382
}
×
383

384
/* Add the value found in Step 4 to every element of each covered row, and subtract it 
385
  * from every element of each uncovered column.  Return to Step 4 without altering any
386
  * stars, primes, or covered lines. Notice that this step uses the smallest uncovered 
387
  * value in the cost matrix to modify the matrix.  Even though this step refers to the
388
  * value being found in Step 4 it is more convenient to wait until you reach Step 6 
389
  * before searching for this value.  It may seem that since the values in the cost 
390
  * matrix are being altered, we would lose sight of the original problem.  
391
  * However, we are only changing certain values that have already been tested and 
392
  * found not to be elements of the minimal assignment.  Also we are only changing the 
393
  * values by an amount equal to the smallest value in the cost matrix, so we will not
394
  * jump over the optimal (i.e. minimal assignment) with this change. */
395
template<typename T>
UNCOV
396
void step6(std::vector<std::vector<T>> & matrix,
×
397
           std::vector<int> const & RowCover,
398
           std::vector<int> const & ColCover,
399
           int & step) {
UNCOV
400
    T minval = std::numeric_limits<T>::max();
×
UNCOV
401
    find_smallest(minval, matrix, RowCover, ColCover);
×
402

UNCOV
403
    int sz = matrix.size();
×
UNCOV
404
    for (int r = 0; r < sz; r++)
×
UNCOV
405
        for (int c = 0; c < sz; c++) {
×
UNCOV
406
            if (RowCover[r] == 1)
×
407
                matrix[r][c] += minval;
×
UNCOV
408
            if (ColCover[c] == 0)
×
UNCOV
409
                matrix[r][c] -= minval;
×
410
        }
411

UNCOV
412
    step = 4;
×
UNCOV
413
}
×
414

415
/* Calculates the optimal cost from mask matrix */
416
template<template<typename, typename...> class Container,
417
         typename T,
418
         typename... Args>
419
T output_solution(Container<Container<T, Args...>> const & original,
7✔
420
                  std::vector<std::vector<int>> const & M) {
421
    T res = 0;
7✔
422

423
    for (unsigned j = 0; j < original.begin()->size(); ++j)
22✔
424
        for (unsigned i = 0; i < original.size(); ++i)
50✔
425
            if (M[i][j]) {
35✔
426
                auto it1 = original.begin();
15✔
427
                std::advance(it1, i);
428
                auto it2 = it1->begin();
15✔
429
                std::advance(it2, j);
430
                res += *it2;
15✔
431
                continue;
15✔
432
            }
15✔
433

434
    return res;
7✔
435
}
436

437

438
/* Main function of the algorithm */
439
template<template<typename, typename...> class Container,
440
         typename T,
441
         typename... Args>
442
typename std::enable_if<std::is_integral<T>::value, T>::type// Work only on integral types
443
hungarian(Container<Container<T, Args...>> const & original,
×
444
          bool allow_negatives = true) {
445
    /* Initialize data structures */
446

447
    // Work on a vector copy to preserve original matrix
448
    // Didn't passed by value cause needed to access both
449
    std::vector<std::vector<T>> matrix(original.size(),
×
450
                                       std::vector<T>(original.begin()->size()));
×
451

452
    auto it = original.begin();
×
453
    for (auto & vec: matrix) {
×
454
        std::copy(it->begin(), it->end(), vec.begin());
×
455
        it = std::next(it);
×
456
    }
457

458
    // handle negative values -> pass true if allowed or false otherwise
459
    // if it is an unsigned type just skip this step
460
    if (!std::is_unsigned<T>::value) {
461
        handle_negatives(matrix, allow_negatives);
×
462
    }
463

464

465
    // make square matrix
466
    pad_matrix(matrix);
×
467
    std::size_t sz = matrix.size();
×
468

469
    /* The masked matrix M.  If M(i,j)=1 then C(i,j) is a starred zero,  
470
      * If M(i,j)=2 then C(i,j) is a primed zero. */
471
    std::vector<std::vector<int>> M(sz, std::vector<int>(sz, 0));
×
472

473
    /* We also define two vectors RowCover and ColCover that are used to "cover" 
474
      *the rows and columns of the cost matrix C*/
475
    std::vector<int> RowCover(sz, 0);
×
476
    std::vector<int> ColCover(sz, 0);
×
477

478
    int path_row_0, path_col_0;//temporary to hold the smallest uncovered value
×
479

480
    // Array for the augmenting path algorithm
481
    // Path can potentially alternate between starred and primed zeros up to 2*sz length
482
    std::vector<std::vector<int>> path(2 * sz, std::vector<int>(2, 0));
×
483

484
    /* Now Work The Steps */
485
    bool done = false;
×
486
    int step = 1;
×
487
    while (!done) {
×
488
        switch (step) {
×
489
            case 1:
×
490
                step1(matrix, step);
×
491
                break;
×
492
            case 2:
×
493
                step2(matrix, M, RowCover, ColCover, step);
×
494
                break;
×
495
            case 3:
×
496
                step3(M, ColCover, step);
×
497
                break;
×
498
            case 4:
×
499
                step4(matrix, M, RowCover, ColCover, path_row_0, path_col_0, step);
×
500
                break;
×
501
            case 5:
×
502
                step5(path, path_row_0, path_col_0, M, RowCover, ColCover, step);
×
503
                break;
×
504
            case 6:
×
505
                step6(matrix, RowCover, ColCover, step);
×
506
                break;
×
507
            case 7:
×
508
                for (auto & vec: M) { vec.resize(original.begin()->size()); }
×
509
                M.resize(original.size());
×
510
                done = true;
×
511
                break;
×
512
            default:
×
513
                done = true;
×
514
                break;
×
515
        }
516
    }
517

518
    //Printing part (optional)
519
    //std::cout << "Cost Matrix: \n" << original << std::endl
520
    //          << "Optimal assignment: \n" << M;
521

522
    return output_solution<Container, T, Args...>(original, M);
×
523
}
×
524

525
template<template<typename, typename...> class Container,
526
         typename T,
527
         typename... Args>
528
typename std::enable_if<std::is_integral<T>::value, T>::type
529
hungarian_with_assignment(Container<Container<T, Args...>> const & original,
7✔
530
                          std::vector<std::vector<int>> & assignment_matrix,
531
                          bool allow_negatives) {
532
    Container<Container<T, Args...>> matrix(original);
7✔
533

534
    /* If the problem is an odd sized matrix then we adjust to an even size by padding with zeroes  */
535
    pad_matrix(matrix);
7✔
536
    std::size_t sz = matrix.size();
7✔
537

538
    /* The masked matrix M.  If M(i,j)=1 then C(i,j) is a starred zero,  
539
      * If M(i,j)=2 then C(i,j) is a primed zero. */
540
    std::vector<std::vector<int>> M(sz, std::vector<int>(sz, 0));
35✔
541

542
    /* We also define two vectors RowCover and ColCover that are used to "cover" 
543
      *the rows and columns of the cost matrix C*/
544
    std::vector<int> RowCover(sz, 0);
21✔
545
    std::vector<int> ColCover(sz, 0);
21✔
546

547
    int path_row_0, path_col_0;//temporary to hold the smallest uncovered value
7✔
548

549
    // Array for the augmenting path algorithm
550
    // Path can potentially alternate between starred and primed zeros up to 2*sz length
551
    std::vector<std::vector<int>> path(2 * sz, std::vector<int>(2, 0));
35✔
552

553
    /* Now Work The Steps */
554
    bool done = false;
7✔
555
    int step = 1;
7✔
556
    while (!done) {
38✔
557
        switch (step) {
31✔
558
            case 1:
7✔
559
                step1(matrix, step);
7✔
560
                break;
7✔
561
            case 2:
7✔
562
                step2(matrix, M, RowCover, ColCover, step);
7✔
563
                break;
7✔
564
            case 3:
8✔
565
                step3(M, ColCover, step);
8✔
566
                break;
8✔
567
            case 4:
1✔
568
                step4(matrix, M, RowCover, ColCover, path_row_0, path_col_0, step);
1✔
569
                break;
1✔
570
            case 5:
1✔
571
                step5(path, path_row_0, path_col_0, M, RowCover, ColCover, step);
1✔
572
                break;
1✔
UNCOV
573
            case 6:
×
UNCOV
574
                step6(matrix, RowCover, ColCover, step);
×
UNCOV
575
                break;
×
576
            case 7:
7✔
577
                for (auto & vec: M) { vec.resize(original.begin()->size()); }
22✔
578
                M.resize(original.size());
7✔
579
                done = true;
7✔
580
                break;
7✔
581
            default:
×
582
                done = true;
×
583
                break;
×
584
        }
585
    }
586

587
    // Copy the assignment matrix to output
588
    assignment_matrix = M;
7✔
589

590
    return output_solution<Container, T, Args...>(original, M);
14✔
591
}
7✔
592

593

594
}// namespace Munkres
595

596
// Explicit instantiation for the types we need
597
template int Munkres::hungarian<std::vector, int>(
598
        std::vector<std::vector<int>> const & original, bool allow_negatives);
599

600
template int Munkres::hungarian_with_assignment<std::vector, int>(
601
        std::vector<std::vector<int>> const & original,
602
        std::vector<std::vector<int>> & assignment_matrix,
603
        bool allow_negatives);
604
/*
605
 int main() //example of usage
606
 {
607
     using namespace Munkres;
608
     using namespace std;
609
     
610
     // work on multiple containers of the STL
611
     list<list<int>> matrix {{85,  12,  36,  83,  50,  96,  12,  1 },
612
                             {84,  35,  16,  17,  40,  94,  16,  52},
613
                             {14,  16,  8 ,  53,  14,  12,  70,  50},
614
                             {73,  83,  19,  44,  83,  66,  71,  18},
615
                             {36,  45,  29,  4 ,  61,  15,  70,  47},
616
                             {7 ,  14,  11,  69,  57,  32,  37,  81},
617
                             {9 ,  65,  38,  74,  87,  51,  86,  52},
618
                             {52,  40,  56,  10,  42,  2 ,  26,  36},
619
                             {85,  86,  36,  90,  49,  89,  41,  74},
620
                             {40,  67,  2 ,  70,  18,  5 ,  94,  43},
621
                             {85,  12,  36,  83,  50,  96,  12,  1 },
622
                             {84,  35,  16,  17,  40,  94,  16,  52},
623
                             {14,  16,  8 ,  53,  14,  12,  70,  50},
624
                             {73,  83,  19,  44,  83,  66,  71,  18},
625
                             {36,  45,  29,  4 ,  61,  15,  70,  47},
626
                             {7 ,  14,  11,  69,  57,  32,  37,  81},
627
                             {9 ,  65,  38,  74,  87,  51,  86,  52},
628
                             {52,  40,  56,  10,  42,  2 ,  26,  36},
629
                             {85,  86,  36,  90,  49,  89,  41,  74},
630
                             {40,  67,  2 ,  70,  18,  5 ,  94,  43}};
631
                                      
632
     auto res = hungarian(matrix);
633
     std::cout << "Optimal cost: " << res << std::endl;
634
     std::cout << "----------------- \n\n";
635
     
636
     vector<vector<vector<int>>> tests;
637
     
638
     tests.push_back({{25,40,35},
639
                      {40,60,35},
640
                      {20,40,25}});
641
     
642
     tests.push_back({{64,18,75},
643
                      {97,60,24},
644
                      {87,63,15}});
645
     
646
     tests.push_back({{80,40,50,46}, 
647
                      {40,70,20,25},
648
                      {30,10,20,30},
649
                      {35,20,25,30}});
650
     
651
     tests.push_back({{10,19,8,15},
652
                      {10,18,7,17},
653
                      {13,16,9,14},
654
                      {12,19,8,18},
655
                      {14,17,10,19}});
656
     
657
     for (auto& m: tests) {
658
         auto r = hungarian(m);
659
         std::cout << "Optimal cost: " << r << std::endl;
660
         std::cout << "----------------- \n\n";
661
     }
662
     
663
     return 0;
664
 }
665
     */
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc