Skip to content

Commit 2f85b13

Browse files
committed
Added the missing verbose_solver header
1 parent 42f9c7e commit 2f85b13

File tree

1 file changed

+115
-0
lines changed

1 file changed

+115
-0
lines changed
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
/*
2+
* superviseddescent: A C++11 implementation of the supervised descent
3+
* optimisation method
4+
* File: superviseddescent/verbose_solver.hpp
5+
*
6+
* Copyright 2014, 2015 Patrik Huber
7+
*
8+
* Licensed under the Apache License, Version 2.0 (the "License");
9+
* you may not use this file except in compliance with the License.
10+
* You may obtain a copy of the License at
11+
*
12+
* http://www.apache.org/licenses/LICENSE-2.0
13+
*
14+
* Unless required by applicable law or agreed to in writing, software
15+
* distributed under the License is distributed on an "AS IS" BASIS,
16+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17+
* See the License for the specific language governing permissions and
18+
* limitations under the License.
19+
*/
20+
#pragma once
21+
22+
#ifndef VERBOSE_SOLVER_HPP_
23+
#define VERBOSE_SOLVER_HPP_
24+
25+
#include "superviseddescent/regressors.hpp"
26+
27+
#include "Eigen/LU"
28+
29+
#include "opencv2/core/core.hpp"
30+
31+
#include <iostream>
32+
#include <chrono>
33+
34+
namespace superviseddescent {
35+
36+
/**
37+
* A solver that the LinearRegressor uses to solve its system of linear
38+
* equations. This class is exactly the same as \c PartialPivLUSolver, with
39+
* the difference that this solver prints out information about timing and
40+
* the exact regularisation parameter. It is helpful for debugging purposes.
41+
* It has no runtime overhead, but it prints quite some information to
42+
* the standard output.
43+
*/
44+
class VerbosePartialPivLUSolver
45+
{
46+
public:
47+
/**
48+
* The same as \c PartialPivLUSolver, with the difference that this solver
49+
* prints out information about timing and the exact regularisation parameter.
50+
*
51+
* @copydoc PartialPivLUSolver::solve(cv::Mat data, cv::Mat labels, superviseddescent::Regulariser regulariser).
52+
*/
53+
cv::Mat solve(cv::Mat data, cv::Mat labels, superviseddescent::Regulariser regulariser)
54+
{
55+
using cv::Mat;
56+
using std::cout;
57+
using std::endl;
58+
using RowMajorMatrixXf = Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>;
59+
using namespace std::chrono;
60+
time_point<system_clock> start, end;
61+
62+
// Map the cv::Mat data and labels to Eigen matrices:
63+
Eigen::Map<RowMajorMatrixXf> A_Eigen(data.ptr<float>(), data.rows, data.cols);
64+
Eigen::Map<RowMajorMatrixXf> labels_Eigen(labels.ptr<float>(), labels.rows, labels.cols);
65+
66+
start = system_clock::now();
67+
RowMajorMatrixXf AtA_Eigen = A_Eigen.transpose() * A_Eigen;
68+
end = system_clock::now();
69+
cout << "At * A (ms): " << duration_cast<milliseconds>(end - start).count() << endl;
70+
71+
// Note: This is a bit of unnecessary back-and-forth mapping, just for the regularisation:
72+
Mat AtA_Map(static_cast<int>(AtA_Eigen.rows()), static_cast<int>(AtA_Eigen.cols()), CV_32FC1, AtA_Eigen.data());
73+
Mat regularisationMatrix = regulariser.get_matrix(AtA_Map, data.rows);
74+
Eigen::Map<RowMajorMatrixXf> reg_Eigen(regularisationMatrix.ptr<float>(), regularisationMatrix.rows, regularisationMatrix.cols);
75+
76+
Eigen::DiagonalMatrix<float, Eigen::Dynamic> reg_Eigen_diag(regularisationMatrix.rows);
77+
Eigen::VectorXf diagVec(regularisationMatrix.rows);
78+
for (int i = 0; i < diagVec.size(); ++i) {
79+
diagVec(i) = regularisationMatrix.at<float>(i, i);
80+
}
81+
reg_Eigen_diag.diagonal() = diagVec;
82+
start = system_clock::now();
83+
AtA_Eigen = AtA_Eigen + reg_Eigen_diag.toDenseMatrix();
84+
end = system_clock::now();
85+
cout << "AtA + Reg (ms): " << duration_cast<milliseconds>(end - start).count() << endl;
86+
87+
// Perform a PartialPivLU:
88+
start = system_clock::now();
89+
Eigen::PartialPivLU<RowMajorMatrixXf> qrOfAtA(AtA_Eigen);
90+
end = system_clock::now();
91+
cout << "Decomposition (ms): " << duration_cast<milliseconds>(end - start).count() << endl;
92+
start = system_clock::now();
93+
//RowMajorMatrixXf AtAInv_Eigen = qrOfAtA.inverse();
94+
RowMajorMatrixXf x_Eigen = qrOfAtA.solve(A_Eigen.transpose() * labels_Eigen);
95+
//RowMajorMatrixXf x_Eigen = AtA_Eigen.partialPivLu.solve(A_Eigen.transpose() * labels_Eigen);
96+
end = system_clock::now();
97+
cout << "solve() (ms): " << duration_cast<milliseconds>(end - start).count() << endl;
98+
99+
// x = (AtAReg)^-1 * At * b:
100+
start = system_clock::now();
101+
//RowMajorMatrixXf x_Eigen = AtAInv_Eigen * A_Eigen.transpose() * labels_Eigen;
102+
end = system_clock::now();
103+
cout << "AtAInv * At * b (ms): " << duration_cast<milliseconds>(end - start).count() << endl;
104+
105+
// Map the resulting x back to a cv::Mat by creating a Mat header:
106+
Mat x(static_cast<int>(x_Eigen.rows()), static_cast<int>(x_Eigen.cols()), CV_32FC1, x_Eigen.data());
107+
108+
// We have to copy the data because the underlying data is managed by Eigen::Matrix x_Eigen, which will go out of scope after we leave this function:
109+
return x.clone();
110+
//return qrOfAtA.isInvertible();
111+
};
112+
};
113+
114+
} /* namespace superviseddescent */
115+
#endif /* VERBOSE_SOLVER_HPP_ */

0 commit comments

Comments
 (0)