Skip to content

Commit b0e13e8

Browse files
committed
make algorithm parametrized by matrix type
Try to go deeper and be more generic... Now the algorithm does not depend on the base matrix class. Issue: saebyn#25 Signed-off-by: Gluttton <gluttton@ukr.net>
1 parent a610d58 commit b0e13e8

17 files changed

+385
-307
lines changed

benchmarks/test.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ class MunkresFixture : public celero::TestFixture
3232

3333
BASELINE_F (Munkres, Solve, MunkresFixture, 5000, 1)
3434
{
35-
munkres_cpp::Munkres<MUNKRES_CPP_VALUE_TYPE> munkres (matrix);
35+
munkres_cpp::Munkres<MUNKRES_CPP_VALUE_TYPE, munkres_cpp::MUNKRES_CPP_MATRIX_TYPE> munkres (matrix);
3636
}
3737

3838

examples/example_01.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
// The easiest way to start with munkres-cpp.
2222
#include <munkres-cpp/munkres.h>
23+
#include <munkres-cpp/matrix.h>
2324
#include <cstdlib>
2425

2526
int main (int /*argc*/, char * /*argv*/[])
@@ -35,7 +36,7 @@ int main (int /*argc*/, char * /*argv*/[])
3536
// Input data must be positive and well defined (no NaN or infinity).
3637

3738
// Next you need create the problem solver and pass data to it.
38-
munkres_cpp::Munkres<int> solver (data);
39+
munkres_cpp::Munkres<int, munkres_cpp::Matrix> solver (data);
3940

4041
// Now the matrix contains the solution of the problem.
4142
// Zero value represents selected values.

examples/example_02.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
// Easy way to start with munkres-cpp.
2222
#include <munkres-cpp/munkres.h>
23+
#include <munkres-cpp/matrix.h>
2324
#include <munkres-cpp/utils.h>
2425
#include <cstdlib>
2526

@@ -39,7 +40,7 @@ int main (int /*argc*/, char * /*argv*/[])
3940
// of the input data you should use it.
4041
if (munkres_cpp::is_data_valid (data) ) {
4142
// Next you need to create the problem solver and pass data to it.
42-
munkres_cpp::Munkres<int> solver (data);
43+
munkres_cpp::Munkres<int, munkres_cpp::Matrix> solver (data);
4344

4445
// Now the matrix contains the solution.
4546
// Zero value represents selected values.

examples/example_03.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ int main (int /*argc*/, char * /*argv*/[])
3838
// Don't forget! You are responsible for correctness of the input data.
3939

4040
// Create the solver and pass data to it.
41-
munkres_cpp::Munkres<double> solver (data);
41+
munkres_cpp::Munkres<double, munkres_cpp::matrix_boost> solver (data);
4242

4343
// Now the matrix contains the solution.
4444

examples/example_04.cpp

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -37,37 +37,56 @@ template<class T>
3737
class matrix_boost_adapter : public munkres_cpp::matrix_base<T>
3838
{
3939
public:
40-
matrix_boost_adapter (boost::numeric::ublas::matrix<T> & data)
41-
: data {data}
40+
matrix_boost_adapter (boost::numeric::ublas::matrix<T> * data = nullptr)
41+
: data {data}
42+
, is_own_data {false}
4243
{
44+
if (!data) {
45+
data = new boost::numeric::ublas::matrix<T>;
46+
is_own_data = true;
47+
}
48+
}
49+
50+
matrix_boost_adapter (size_t rows, size_t columns)
51+
: data {new boost::numeric::ublas::matrix<T> (rows, columns, 0)}
52+
, is_own_data {true}
53+
{
54+
}
55+
56+
~matrix_boost_adapter () override
57+
{
58+
if (is_own_data) {
59+
delete data;
60+
}
4361
}
4462

4563
const T & operator () (const size_t row, const size_t column) const override
4664
{
47-
return data (row, column);
65+
return data->operator () (row, column);
4866
};
4967

5068
T & operator () (const size_t row, const size_t column) override
5169
{
52-
return data (row, column);
70+
return data->operator () (row, column);
5371
}
5472

5573
size_t columns () const override
5674
{
57-
return data.size2 ();
75+
return data->size2 ();
5876
}
5977

6078
size_t rows () const override
6179
{
62-
return data.size1 ();
80+
return data->size1 ();
6381
}
6482

65-
void resize (size_t, size_t, T) override
83+
void resize (size_t, size_t, T/* value = T (0) */) override
6684
{
6785
}
6886

6987
private:
70-
boost::numeric::ublas::matrix<T> & data;
88+
boost::numeric::ublas::matrix<T> * data;
89+
bool is_own_data;
7190
};
7291

7392
int main (int /*argc*/, char * /*argv*/[])
@@ -80,10 +99,10 @@ int main (int /*argc*/, char * /*argv*/[])
8099
// Don't forget! You are responsible for correctness of the input data.
81100

82101
// Create data adapter and pass your container to it.
83-
matrix_boost_adapter<double> adapter (data);
102+
matrix_boost_adapter<double> adapter (& data);
84103

85104
// Create the solver and pass data to it.
86-
munkres_cpp::Munkres<double> solver (adapter);
105+
munkres_cpp::Munkres<double, matrix_boost_adapter> solver (adapter);
87106

88107
// Now the matrix contains the solution.
89108

examples/example_05.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ class matrix_boost_adapter : public munkres_cpp::matrix_base<T>, boost::numeric:
4040
{
4141
public:
4242
matrix_boost_adapter (const size_t rows, const size_t columns)
43-
: boost::numeric::ublas::matrix<T>::matrix (rows, columns)
43+
: boost::numeric::ublas::matrix<T>::matrix (rows, columns, 0)
4444
{
4545
}
4646

@@ -114,7 +114,7 @@ int main (int /*argc*/, char * /*argv*/[])
114114
// of the input data you should use it.
115115
if (munkres_cpp::is_data_valid (data) ) {
116116
// Next you need create the problem solver and pass data to it.
117-
munkres_cpp::Munkres<float> solver (data);
117+
munkres_cpp::Munkres<float, matrix_boost_adapter> solver (data);
118118

119119
// Now the matrix contains the solution.
120120
// Zero value represents selected values.

examples/example_06.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,18 +26,19 @@
2626
#include <ctime>
2727

2828
#include <munkres-cpp/munkres.h>
29+
#include <munkres-cpp/adapters/matrix_boost.h>
2930

3031
int main (int argc, char * argv[])
3132
{
32-
int nrows = 101;
33-
int ncols = 101;
33+
int nrows = 10;
34+
int ncols = 10;
3435

3536
if (argc == 3) {
3637
nrows = atoi (argv[1]);
3738
ncols = atoi (argv[2]);
3839
}
3940

40-
munkres_cpp::Matrix<double> matrix (nrows, ncols);
41+
munkres_cpp::matrix_boost<double> matrix (nrows, ncols);
4142

4243
srandom ( time (nullptr) ); // Seed random number generator.
4344

@@ -59,7 +60,7 @@ int main (int argc, char * argv[])
5960
std::cout << std::endl;
6061

6162
// Apply Munkres algorithm to matrix.
62-
munkres_cpp::Munkres<double> m (matrix);
63+
munkres_cpp::Munkres<double, munkres_cpp::matrix_boost> m (matrix);
6364

6465
// Display solved matrix.
6566
for (int row = 0; row < nrows; row++) {

src/munkres-cpp/adapters/matrix_armadillo.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ class matrix_armadillo : public matrix_base<T>, public arma::Mat<T>
3535
matrix_armadillo (size_t rows, size_t columns)
3636
: arma::Mat<T>::Mat (rows, columns)
3737
{
38+
std::fill (matrix_base<T>::begin (), matrix_base<T>::end (), T (0) );
3839
}
3940

4041
matrix_armadillo (const arma::Mat<T> & other)
@@ -94,6 +95,11 @@ class matrix_armadillo : public matrix_base<T>, public arma::Mat<T>
9495
}
9596
}
9697
}
98+
99+
bool is_zero (size_t row, size_t column) const
100+
{
101+
return matrix_base<T>::is_zero (row, column);
102+
}
97103
};
98104

99105
}// namespace munkres_cpp

src/munkres-cpp/adapters/matrix_boost.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ class matrix_boost : public matrix_base<T>, public boost::numeric::ublas::matrix
3232
matrix_boost (size_t rows, size_t columns)
3333
: boost::numeric::ublas::matrix<T>::matrix (rows, columns)
3434
{
35+
std::fill (matrix_base<T>::begin (), matrix_base<T>::end (), T (0) );
3536
}
3637

3738
matrix_boost (const boost::numeric::ublas::matrix<T> & other)

src/munkres-cpp/adapters/matrix_eigen.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ class matrix_eigen : public matrix_base<T>, public Eigen::Matrix<T, Eigen::Dynam
3232
matrix_eigen (size_t rows, size_t columns)
3333
: Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>::Matrix (rows, columns)
3434
{
35+
std::fill (matrix_base<T>::begin (), matrix_base<T>::end (), T (0) );
3536
}
3637

3738
matrix_eigen (const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> & other)

src/munkres-cpp/adapters/matrix_opencv.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ class matrix_opencv : public matrix_base<T>, public cv::Mat_<T>
3636
matrix_opencv (size_t rows, size_t columns)
3737
: cv::Mat_<T>::Mat_ (rows, columns, cv::DataType<T>::type)
3838
{
39+
std::fill (matrix_base<T>::begin (), matrix_base<T>::end (), T (0) );
3940
}
4041

4142
matrix_opencv (const matrix_opencv<T> & other)

src/munkres-cpp/munkres.h

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
#if !defined(_MUNKRES_H_)
2020
#define _MUNKRES_H_
2121

22-
#include "munkres-cpp/matrix.h"
2322
#include <forward_list>
2423
#include <algorithm>
2524

@@ -28,11 +27,11 @@
2827
namespace munkres_cpp
2928
{
3029

31-
template<typename T>
30+
template<typename T, template <typename> class M>
3231
class Munkres
3332
{
3433
public:
35-
Munkres (matrix_base<T> &);
34+
Munkres (M<T> &);
3635

3736
private:
3837
Munkres (const Munkres &) = delete;
@@ -46,8 +45,8 @@ class Munkres
4645
int step6 ();
4746

4847
const size_t size;
49-
matrix_base<T> & matrix;
50-
Matrix<char> mask_matrix;
48+
M<T> & matrix;
49+
M<char> mask_matrix;
5150
bool * const row_mask;
5251
bool * const col_mask;
5352
size_t saverow;
@@ -62,8 +61,8 @@ class Munkres
6261

6362

6463

65-
template<typename T>
66-
void minimize_along_direction (matrix_base<T> & matrix, bool over_columns)
64+
template<typename T, template <typename> class M>
65+
void minimize_along_direction (M<T> & matrix, bool over_columns)
6766
{
6867
// Look for a minimum value to subtract from all values along the "outer" direction.
6968
size_t i, j = 0, size = matrix.rows ();
@@ -85,8 +84,8 @@ void minimize_along_direction (matrix_base<T> & matrix, bool over_columns)
8584

8685

8786

88-
template<typename T>
89-
bool Munkres<T>::find_uncovered_in_matrix (size_t & row, size_t & col) const
87+
template<typename T, template <typename> class M>
88+
bool Munkres<T, M>::find_uncovered_in_matrix (size_t & row, size_t & col) const
9089
{
9190
for (col = 0; col < size; col++)
9291
if (!col_mask[col])
@@ -100,8 +99,8 @@ bool Munkres<T>::find_uncovered_in_matrix (size_t & row, size_t & col) const
10099

101100

102101

103-
template<typename T>
104-
int Munkres<T>::step1 ()
102+
template<typename T, template <typename> class M>
103+
int Munkres<T, M>::step1 ()
105104
{
106105
for (size_t row = 0; row < size; row++) {
107106
for (size_t col = 0; col < size; col++) {
@@ -123,8 +122,8 @@ int Munkres<T>::step1 ()
123122

124123

125124

126-
template<typename T>
127-
int Munkres<T>::step2 ()
125+
template<typename T, template <typename> class M>
126+
int Munkres<T, M>::step2 ()
128127
{
129128
size_t covercount = 0;
130129

@@ -140,8 +139,8 @@ int Munkres<T>::step2 ()
140139

141140

142141

143-
template<typename T>
144-
int Munkres<T>::step3 ()
142+
template<typename T, template <typename> class M>
143+
int Munkres<T, M>::step3 ()
145144
{
146145
// Main Zero Search
147146
// 1. Find an uncovered Z in the distance matrix and prime it. If no such zero exists, go to Step 5
@@ -164,8 +163,8 @@ int Munkres<T>::step3 ()
164163

165164

166165

167-
template<typename T>
168-
int Munkres<T>::step4 ()
166+
template<typename T, template <typename> class M>
167+
int Munkres<T, M>::step4 ()
169168
{
170169
// Seq contains pairs of row/column values where we have found
171170
// either a star or a prime that is part of the ``alternating sequence``.
@@ -212,8 +211,8 @@ int Munkres<T>::step4 ()
212211

213212

214213

215-
template<typename T>
216-
int Munkres<T>::step5 ()
214+
template<typename T, template <typename> class M>
215+
int Munkres<T, M>::step5 ()
217216
{
218217
// New Zero Manufactures
219218
// 1. Let h be the smallest uncovered entry in the (modified) distance matrix.
@@ -249,8 +248,8 @@ int Munkres<T>::step5 ()
249248
//
250249
// Assignments are remaining 0 values
251250
// (extra 0 values are replaced with 1)
252-
template<typename T>
253-
Munkres<T>::Munkres (matrix_base<T> & matrix)
251+
template<typename T, template <typename> class M>
252+
Munkres<T, M>::Munkres (M<T> & matrix)
254253
: size {std::max (matrix.rows (), matrix.columns () )}
255254
, matrix {matrix}
256255
, mask_matrix {size, size}

src/munkres-cpp/utils.h

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
#if !defined(__MUNKRES_CPP_UTILS_H__)
22
#define __MUNKRES_CPP_UTILS_H__
33

4-
#include "munkres-cpp/matrix_base.h"
54
#include <algorithm>
5+
#include <cmath>
66

77

88

99
namespace munkres_cpp
1010
{
1111

12-
template<typename T>
12+
template<typename T, template <typename> class M>
1313
typename std::enable_if<std::is_floating_point<T>::value>::type
14-
replace_infinites (matrix_base<T> & matrix)
14+
replace_infinites (M<T> & matrix)
1515
{
1616
std::replace_if (matrix.begin (), matrix.end (), [](const T & v){return std::isinf (v);}, std::numeric_limits<T>::max () );
1717
}
@@ -41,14 +41,14 @@ is_data_invalid (const T & value)
4141

4242

4343

44-
template<typename T>
45-
typename std::enable_if<std::is_unsigned<T>::value, bool>::type is_data_valid (const matrix_base<T> &)
44+
template<typename T, template <typename> class M>
45+
typename std::enable_if<std::is_unsigned<T>::value, bool>::type is_data_valid (const M<T> &)
4646
{
4747
return true;
4848
}
4949

50-
template<typename T>
51-
typename std::enable_if<std::is_signed<T>::value, bool>::type is_data_valid (const matrix_base<T> & matrix)
50+
template<typename T, template <typename> class M>
51+
typename std::enable_if<std::is_signed<T>::value, bool>::type is_data_valid (const M<T> & matrix)
5252
{
5353
return !std::any_of (matrix.begin (), matrix.end (), [](const T & v){return is_data_invalid<T> (v);});
5454
}

0 commit comments

Comments
 (0)