From 6db2596ca921de0e39faa2c1b535a0faf6dd710b Mon Sep 17 00:00:00 2001 From: Alex Leontiev Date: Thu, 11 Jul 2013 22:05:14 +0300 Subject: [PATCH] Convenience fixes Attempting to fix issues pointed out by Vadim Pisarevsky during the pull request review. In particular, the following things are done: *) The mechanism of debug info printing is changed and made more procedure-style than the previous macro-style *) z in solveLP() is now returned as a column-vector *) Func parameter of solveLP() is now allowed to be column-vector, in which case it is understood to be the transpose of what we need *) Func and Constr now can contain floats, not only doubles (in the former case the conversion is done via convertTo()) *)different constructor to allocate space for z in solveLP() is used, making the size of z more explicit (this is just a notation change, not functional, both constructors are achieving the same goal) *) (big) mat.hpp and iostream headers are moved to precomp-headers from optim.hpp --- modules/optim/doc/linear_programming.rst | 6 +- modules/optim/include/opencv2/optim.hpp | 4 -- modules/optim/src/lpsolver.cpp | 103 ++++++++++++++++++------------- modules/optim/src/precomp.hpp | 2 + modules/optim/test/test_lpsolver.cpp | 18 +++--- modules/optim/test/test_precomp.hpp | 2 + 6 files changed, 77 insertions(+), 58 deletions(-) diff --git a/modules/optim/doc/linear_programming.rst b/modules/optim/doc/linear_programming.rst index fbc1d04..946df9e 100644 --- a/modules/optim/doc/linear_programming.rst +++ b/modules/optim/doc/linear_programming.rst @@ -28,11 +28,11 @@ by T. H. Cormen, C. E. Leiserson, R. L. Rivest and Clifford Stein. In particular .. ocv:function:: int optim::solveLP(const Mat& Func, const Mat& Constr, Mat& z) - :param Func: This row-vector corresponds to :math:`c` in the LP problem formulation (see above). + :param Func: This row-vector corresponds to :math:`c` in the LP problem formulation (see above). It should contain 32- or 64-bit floating point numbers. As a convenience, column-vector may be also submitted, in the latter case it is understood to correspond to :math:`c^T`. - :param Constr: *m*-by-*n\+1* matrix, whose rightmost column corresponds to :math:`b` in formulation above and the remaining to :math:`A`. + :param Constr: *m*-by-*n\+1* matrix, whose rightmost column corresponds to :math:`b` in formulation above and the remaining to :math:`A`. It should containt 32- or 64-bit floating point numbers. - :param z: The solution will be returned here as a row-vector - it corresponds to (transposed) :math:`c` in the formulation above. + :param z: The solution will be returned here as a column-vector - it corresponds to :math:`c` in the formulation above. It will contain 64-bit floating point numbers. :return: One of the return codes: diff --git a/modules/optim/include/opencv2/optim.hpp b/modules/optim/include/opencv2/optim.hpp index a50af74..2e225e8 100644 --- a/modules/optim/include/opencv2/optim.hpp +++ b/modules/optim/include/opencv2/optim.hpp @@ -43,10 +43,6 @@ #ifndef __OPENCV_OPTIM_HPP__ #define __OPENCV_OPTIM_HPP__ -#include -#include "opencv2/core.hpp" -#include "opencv2/core/mat.hpp" - //uncomment the next line to print the debug info //#define ALEX_DEBUG diff --git a/modules/optim/src/lpsolver.cpp b/modules/optim/src/lpsolver.cpp index 28b7b46..8377e5c 100644 --- a/modules/optim/src/lpsolver.cpp +++ b/modules/optim/src/lpsolver.cpp @@ -9,39 +9,39 @@ using std::vector; #ifdef ALEX_DEBUG #define dprintf(x) printf x -#define print_matrix(x) do{\ - printf("\ttype:%d vs %d,\tsize: %d-on-%d\n",(x).type(),CV_64FC1,(x).rows,(x).cols);\ - for(int i=0;i<(x).rows;i++){\ - printf("\t[");\ - for(int j=0;j<(x).cols;j++){\ - printf("%g, ",(x).at(i,j));\ - }\ - printf("]\n");\ - }\ -}while(0) -#define print_simplex_state(c,b,v,N,B) do{\ - printf("\tprint simplex state\n");\ - \ - printf("v=%g\n",(v));\ - \ - printf("here c goes\n");\ - print_matrix((c));\ - \ - printf("non-basic: ");\ - for (std::vector::const_iterator it = (N).begin() ; it != (N).end(); ++it){\ - printf("%d, ",*it);\ - }\ - printf("\n");\ - \ - printf("here b goes\n");\ - print_matrix((b));\ - printf("basic: ");\ - \ - for (std::vector::const_iterator it = (B).begin() ; it != (B).end(); ++it){\ - printf("%d, ",*it);\ - }\ - printf("\n");\ -}while(0) +static void print_matrix(const Mat& x){ + printf("\ttype:%d vs %d,\tsize: %d-on-%d\n",(x).type(),CV_64FC1,(x).rows,(x).cols); + for(int i=0;i<(x).rows;i++){ + printf("\t["); + for(int j=0;j<(x).cols;j++){ + printf("%g, ",(x).at(i,j)); + } + printf("]\n"); + } +} +static void print_simplex_state(const Mat& c,const Mat& b,double v,const std::vector N,const std::vector B){ + printf("\tprint simplex state\n"); + + printf("v=%g\n",(v)); + + printf("here c goes\n"); + print_matrix((c)); + + printf("non-basic: "); + for (std::vector::const_iterator it = (N).begin() ; it != (N).end(); ++it){ + printf("%d, ",*it); + } + printf("\n"); + + printf("here b goes\n"); + print_matrix((b)); + printf("basic: "); + + for (std::vector::const_iterator it = (B).begin() ; it != (B).end(); ++it){ + printf("%d, ",*it); + } + printf("\n"); +} #else #define dprintf(x) do {} while (0) #define print_matrix(x) do {} while (0) @@ -66,16 +66,36 @@ int solveLP(const Mat& Func, const Mat& Constr, Mat& z){ dprintf(("call to solveLP\n")); //sanity check (size, type, no. of channels) - CV_Assert(Func.type()==CV_64FC1); - CV_Assert(Constr.type()==CV_64FC1); - CV_Assert(Func.rows==1); - CV_Assert(Constr.cols-Func.cols==1); + CV_Assert(Func.type()==CV_64FC1 || Func.type()==CV_32FC1); + CV_Assert(Constr.type()==CV_64FC1 || Constr.type()==CV_32FC1); + CV_Assert((Func.rows==1 && (Constr.cols-Func.cols==1))|| + (Func.cols==1 && (Constr.cols-Func.rows==1))); //copy arguments for we will shall modify them - Mat_ bigC=Mat_(1,Func.cols+1), + Mat_ bigC=Mat_(1,(Func.rows==1?Func.cols:Func.rows)+1), bigB=Mat_(Constr.rows,Constr.cols+1); - Func.copyTo(bigC.colRange(1,bigC.cols)); - Constr.copyTo(bigB.colRange(1,bigB.cols)); + if(Func.rows==1){ + Func.convertTo(bigC.colRange(1,bigC.cols),CV_64FC1); + }else{ + dprintf(("hi from other branch\n")); + Mat_ slice=bigC.colRange(1,bigC.cols); + MatIterator_ slice_iterator=slice.begin(); + switch(Func.type()){ + case CV_64FC1: + for(MatConstIterator_ it=Func.begin();it!=Func.end();it++,slice_iterator++){ + * slice_iterator= *it; + } + break; + case CV_32FC1: + for(MatConstIterator_ it=Func.begin();it!=Func.end();it++,slice_iterator++){ + * slice_iterator= *it; + } + break; + } + print_matrix(Func); + print_matrix(bigC); + } + Constr.convertTo(bigB.colRange(1,bigB.cols),CV_64FC1); double v=0; vector N,B; @@ -91,8 +111,7 @@ int solveLP(const Mat& Func, const Mat& Constr, Mat& z){ } //return the optimal solution - const int z_size[]={1,c.cols}; - z.create(2,z_size,CV_64FC1); + z.create(c.cols,1,CV_64FC1); MatIterator_ it=z.begin(); for(int i=1;i<=c.cols;i++,it++){ std::vector::iterator pos=B.begin(); diff --git a/modules/optim/src/precomp.hpp b/modules/optim/src/precomp.hpp index 7aab572..60d2b5b 100644 --- a/modules/optim/src/precomp.hpp +++ b/modules/optim/src/precomp.hpp @@ -43,6 +43,8 @@ #ifndef __OPENCV_PRECOMP_H__ #define __OPENCV_PRECOMP_H__ +#include "opencv2/core.hpp" +#include "opencv2/core/mat.hpp" #include "opencv2/optim.hpp" #endif diff --git a/modules/optim/test/test_lpsolver.cpp b/modules/optim/test/test_lpsolver.cpp index bcab3fa..68bc693 100644 --- a/modules/optim/test/test_lpsolver.cpp +++ b/modules/optim/test/test_lpsolver.cpp @@ -1,17 +1,17 @@ #include "test_precomp.hpp" -#include "opencv2/optim.hpp" +#include TEST(Optim_LpSolver, regression_basic){ cv::Mat A,B,z,etalon_z; if(true){ //cormen's example #1 - A=(cv::Mat_(1,3)<<3,1,2); + A=(cv::Mat_(3,1)<<3,1,2); B=(cv::Mat_(3,4)<<1,1,3,30,2,2,5,24,4,1,2,36); std::cout<<"here A goes\n"<(1,3)<<8,4,0); + etalon_z=(cv::Mat_(3,1)<<8,4,0); ASSERT_EQ(cv::countNonZero(z!=etalon_z),0); } @@ -22,7 +22,7 @@ TEST(Optim_LpSolver, regression_basic){ std::cout<<"here A goes\n"<(1,2)<<20,0); + etalon_z=(cv::Mat_(2,1)<<20,0); ASSERT_EQ(cv::countNonZero(z!=etalon_z),0); } @@ -33,7 +33,7 @@ TEST(Optim_LpSolver, regression_basic){ std::cout<<"here A goes\n"<(1,2)<<1,0); + etalon_z=(cv::Mat_(2,1)<<1,0); ASSERT_EQ(cv::countNonZero(z!=etalon_z),0); } } @@ -48,7 +48,7 @@ TEST(Optim_LpSolver, regression_init_unfeasible){ std::cout<<"here A goes\n"<(1,3)<<1250,1000,0); + etalon_z=(cv::Mat_(3,1)<<1250,1000,0); ASSERT_EQ(cv::countNonZero(z!=etalon_z),0); } } @@ -71,7 +71,7 @@ TEST(Optim_LpSolver, regression_multiple_solutions){ if(true){ //trivial example with multiple solutions - A=(cv::Mat_(1,2)<<1,1); + A=(cv::Mat_(2,1)<<1,1); B=(cv::Mat_(1,3)<<1,1,1); std::cout<<"here A goes\n"<(1,2)<<2,-1); + A=(cv::Mat_(2,1)<<2,-1); B=(cv::Mat_(2,3)<<2,-1,2,1,-5,-4); std::cout<<"here A goes\n"<(1,4)<<10,-57,-9,-24); + A=(cv::Mat_(4,1)<<10,-57,-9,-24); B=(cv::Mat_(3,5)<<0.5,-5.5,-2.5,9,0,0.5,-1.5,-0.5,1,0,1,0,0,0,1); std::cout<<"here A goes\n"<