1 /*M///////////////////////////////////////////////////////////////////////////////////////
2 //
3 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4 //
5 // By downloading, copying, installing or using the software you agree to this license.
6 // If you do not agree to this license, do not download, install,
7 // copy or use the software.
8 //
9 //
10 // License Agreement
11 // For Open Source Computer Vision Library
12 //
13 // Copyright (C) 2013, OpenCV Foundation, all rights reserved.
14 // Third party copyrights are property of their respective owners.
15 //
16 // Redistribution and use in source and binary forms, with or without modification,
17 // are permitted provided that the following conditions are met:
18 //
19 // * Redistribution's of source code must retain the above copyright notice,
20 // this list of conditions and the following disclaimer.
21 //
22 // * Redistribution's in binary form must reproduce the above copyright notice,
23 // this list of conditions and the following disclaimer in the documentation
24 // and/or other materials provided with the distribution.
25 //
26 // * The name of the copyright holders may not be used to endorse or promote products
27 // derived from this software without specific prior written permission.
28 //
29 // This software is provided by the copyright holders and contributors "as is" and
30 // any express or implied warranties, including, but not limited to, the implied
31 // warranties of merchantability and fitness for a particular purpose are disclaimed.
32 // In no event shall the OpenCV Foundation or contributors be liable for any direct,
33 // indirect, incidental, special, exemplary, or consequential damages
34 // (including, but not limited to, procurement of substitute goods or services;
35 // loss of use, data, or profits; or business interruption) however caused
36 // and on any theory of liability, whether in contract, strict liability,
37 // or tort (including negligence or otherwise) arising in any way out of
38 // the use of this software, even if advised of the possibility of such damage.
39 //
40 //M*/
41 #include "precomp.hpp"
42 #include <climits>
43 #include <algorithm>
44 #include <cstdarg>
45
46 #define dprintf(x)
47 #define print_matrix(x)
48
49 namespace cv
50 {
51
52 using std::vector;
53
54 #ifdef ALEX_DEBUG
print_simplex_state(const Mat & c,const Mat & b,double v,const std::vector<int> N,const std::vector<int> B)55 static void print_simplex_state(const Mat& c,const Mat& b,double v,const std::vector<int> N,const std::vector<int> B){
56 printf("\tprint simplex state\n");
57
58 printf("v=%g\n",v);
59
60 printf("here c goes\n");
61 print_matrix(c);
62
63 printf("non-basic: ");
64 print(Mat(N));
65 printf("\n");
66
67 printf("here b goes\n");
68 print_matrix(b);
69 printf("basic: ");
70
71 print(Mat(B));
72 printf("\n");
73 }
74 #else
75 #define print_simplex_state(c,b,v,N,B)
76 #endif
77
78 /**Due to technical considerations, the format of input b and c is somewhat special:
79 *both b and c should be one column bigger than corresponding b and c of linear problem and the leftmost column will be used internally
80 by this procedure - it should not be cleaned before the call to procedure and may contain mess after
81 it also initializes N and B and does not make any assumptions about their init values
82 * @return SOLVELP_UNFEASIBLE if problem is unfeasible, 0 if feasible.
83 */
84 static int initialize_simplex(Mat_<double>& c, Mat_<double>& b,double& v,vector<int>& N,vector<int>& B,vector<unsigned int>& indexToRow);
85 static inline void pivot(Mat_<double>& c,Mat_<double>& b,double& v,vector<int>& N,vector<int>& B,int leaving_index,
86 int entering_index,vector<unsigned int>& indexToRow);
87 /**@return SOLVELP_UNBOUNDED means the problem is unbdd, SOLVELP_MULTI means multiple solutions, SOLVELP_SINGLE means one solution.
88 */
89 static int inner_simplex(Mat_<double>& c, Mat_<double>& b,double& v,vector<int>& N,vector<int>& B,vector<unsigned int>& indexToRow);
90 static void swap_columns(Mat_<double>& A,int col1,int col2);
91 #define SWAP(type,a,b) {type tmp=(a);(a)=(b);(b)=tmp;}
92
93 //return codes:-2 (no_sol - unbdd),-1(no_sol - unfsbl), 0(single_sol), 1(multiple_sol=>least_l2_norm)
solveLP(const Mat & Func,const Mat & Constr,Mat & z)94 int solveLP(const Mat& Func, const Mat& Constr, Mat& z){
95 dprintf(("call to solveLP\n"));
96
97 //sanity check (size, type, no. of channels)
98 CV_Assert(Func.type()==CV_64FC1 || Func.type()==CV_32FC1);
99 CV_Assert(Constr.type()==CV_64FC1 || Constr.type()==CV_32FC1);
100 CV_Assert((Func.rows==1 && (Constr.cols-Func.cols==1))||
101 (Func.cols==1 && (Constr.cols-Func.rows==1)));
102
103 //copy arguments for we will shall modify them
104 Mat_<double> bigC=Mat_<double>(1,(Func.rows==1?Func.cols:Func.rows)+1),
105 bigB=Mat_<double>(Constr.rows,Constr.cols+1);
106 if(Func.rows==1){
107 Func.convertTo(bigC.colRange(1,bigC.cols),CV_64FC1);
108 }else{
109 Mat FuncT=Func.t();
110 FuncT.convertTo(bigC.colRange(1,bigC.cols),CV_64FC1);
111 }
112 Constr.convertTo(bigB.colRange(1,bigB.cols),CV_64FC1);
113 double v=0;
114 vector<int> N,B;
115 vector<unsigned int> indexToRow;
116
117 if(initialize_simplex(bigC,bigB,v,N,B,indexToRow)==SOLVELP_UNFEASIBLE){
118 return SOLVELP_UNFEASIBLE;
119 }
120 Mat_<double> c=bigC.colRange(1,bigC.cols),
121 b=bigB.colRange(1,bigB.cols);
122
123 int res=0;
124 if((res=inner_simplex(c,b,v,N,B,indexToRow))==SOLVELP_UNBOUNDED){
125 return SOLVELP_UNBOUNDED;
126 }
127
128 //return the optimal solution
129 z.create(c.cols,1,CV_64FC1);
130 MatIterator_<double> it=z.begin<double>();
131 unsigned int nsize = (unsigned int)N.size();
132 for(int i=1;i<=c.cols;i++,it++){
133 if(indexToRow[i]<nsize){
134 *it=0;
135 }else{
136 *it=b.at<double>(indexToRow[i]-nsize,b.cols-1);
137 }
138 }
139
140 return res;
141 }
142
initialize_simplex(Mat_<double> & c,Mat_<double> & b,double & v,vector<int> & N,vector<int> & B,vector<unsigned int> & indexToRow)143 static int initialize_simplex(Mat_<double>& c, Mat_<double>& b,double& v,vector<int>& N,vector<int>& B,vector<unsigned int>& indexToRow){
144 N.resize(c.cols);
145 N[0]=0;
146 for (std::vector<int>::iterator it = N.begin()+1 ; it != N.end(); ++it){
147 *it=it[-1]+1;
148 }
149 B.resize(b.rows);
150 B[0]=(int)N.size();
151 for (std::vector<int>::iterator it = B.begin()+1 ; it != B.end(); ++it){
152 *it=it[-1]+1;
153 }
154 indexToRow.resize(c.cols+b.rows);
155 indexToRow[0]=0;
156 for (std::vector<unsigned int>::iterator it = indexToRow.begin()+1 ; it != indexToRow.end(); ++it){
157 *it=it[-1]+1;
158 }
159 v=0;
160
161 int k=0;
162 {
163 double min=DBL_MAX;
164 for(int i=0;i<b.rows;i++){
165 if(b(i,b.cols-1)<min){
166 min=b(i,b.cols-1);
167 k=i;
168 }
169 }
170 }
171
172 if(b(k,b.cols-1)>=0){
173 N.erase(N.begin());
174 for (std::vector<unsigned int>::iterator it = indexToRow.begin()+1 ; it != indexToRow.end(); ++it){
175 --(*it);
176 }
177 return 0;
178 }
179
180 Mat_<double> old_c=c.clone();
181 c=0;
182 c(0,0)=-1;
183 for(int i=0;i<b.rows;i++){
184 b(i,0)=-1;
185 }
186
187 print_simplex_state(c,b,v,N,B);
188
189 dprintf(("\tWE MAKE PIVOT\n"));
190 pivot(c,b,v,N,B,k,0,indexToRow);
191
192 print_simplex_state(c,b,v,N,B);
193
194 inner_simplex(c,b,v,N,B,indexToRow);
195
196 dprintf(("\tAFTER INNER_SIMPLEX\n"));
197 print_simplex_state(c,b,v,N,B);
198
199 unsigned int nsize = (unsigned int)N.size();
200 if(indexToRow[0]>=nsize){
201 int iterator_offset=indexToRow[0]-nsize;
202 if(b(iterator_offset,b.cols-1)>0){
203 return SOLVELP_UNFEASIBLE;
204 }
205 pivot(c,b,v,N,B,iterator_offset,0,indexToRow);
206 }
207
208 vector<int>::iterator iterator;
209 {
210 int iterator_offset=indexToRow[0];
211 iterator=N.begin()+iterator_offset;
212 std::iter_swap(iterator,N.begin());
213 SWAP(int,indexToRow[*iterator],indexToRow[0]);
214 swap_columns(c,iterator_offset,0);
215 swap_columns(b,iterator_offset,0);
216 }
217
218 dprintf(("after swaps\n"));
219 print_simplex_state(c,b,v,N,B);
220
221 //start from 1, because we ignore x_0
222 c=0;
223 v=0;
224 for(int I=1;I<old_c.cols;I++){
225 if(indexToRow[I]<nsize){
226 dprintf(("I=%d from nonbasic\n",I));
227 int iterator_offset=indexToRow[I];
228 c(0,iterator_offset)+=old_c(0,I);
229 print_matrix(c);
230 }else{
231 dprintf(("I=%d from basic\n",I));
232 int iterator_offset=indexToRow[I]-nsize;
233 c-=old_c(0,I)*b.row(iterator_offset).colRange(0,b.cols-1);
234 v+=old_c(0,I)*b(iterator_offset,b.cols-1);
235 print_matrix(c);
236 }
237 }
238
239 dprintf(("after restore\n"));
240 print_simplex_state(c,b,v,N,B);
241
242 N.erase(N.begin());
243 for (std::vector<unsigned int>::iterator it = indexToRow.begin()+1 ; it != indexToRow.end(); ++it){
244 --(*it);
245 }
246 return 0;
247 }
248
inner_simplex(Mat_<double> & c,Mat_<double> & b,double & v,vector<int> & N,vector<int> & B,vector<unsigned int> & indexToRow)249 static int inner_simplex(Mat_<double>& c, Mat_<double>& b,double& v,vector<int>& N,vector<int>& B,vector<unsigned int>& indexToRow){
250 int count=0;
251 for(;;){
252 dprintf(("iteration #%d\n",count));
253 count++;
254
255 static MatIterator_<double> pos_ptr;
256 int e=-1,pos_ctr=0,min_var=INT_MAX;
257 bool all_nonzero=true;
258 for(pos_ptr=c.begin();pos_ptr!=c.end();pos_ptr++,pos_ctr++){
259 if(*pos_ptr==0){
260 all_nonzero=false;
261 }
262 if(*pos_ptr>0){
263 if(N[pos_ctr]<min_var){
264 e=pos_ctr;
265 min_var=N[pos_ctr];
266 }
267 }
268 }
269 if(e==-1){
270 dprintf(("hello from e==-1\n"));
271 print_matrix(c);
272 if(all_nonzero==true){
273 return SOLVELP_SINGLE;
274 }else{
275 return SOLVELP_MULTI;
276 }
277 }
278
279 int l=-1;
280 min_var=INT_MAX;
281 double min=DBL_MAX;
282 int row_it=0;
283 MatIterator_<double> min_row_ptr=b.begin();
284 for(MatIterator_<double> it=b.begin();it!=b.end();it+=b.cols,row_it++){
285 double myite=0;
286 //check constraints, select the tightest one, reinforcing Bland's rule
287 if((myite=it[e])>0){
288 double val=it[b.cols-1]/myite;
289 if(val<min || (val==min && B[row_it]<min_var)){
290 min_var=B[row_it];
291 min_row_ptr=it;
292 min=val;
293 l=row_it;
294 }
295 }
296 }
297 if(l==-1){
298 return SOLVELP_UNBOUNDED;
299 }
300 dprintf(("the tightest constraint is in row %d with %g\n",l,min));
301
302 pivot(c,b,v,N,B,l,e,indexToRow);
303
304 dprintf(("objective, v=%g\n",v));
305 print_matrix(c);
306 dprintf(("constraints\n"));
307 print_matrix(b);
308 dprintf(("non-basic: "));
309 print_matrix(Mat(N));
310 dprintf(("basic: "));
311 print_matrix(Mat(B));
312 }
313 }
314
pivot(Mat_<double> & c,Mat_<double> & b,double & v,vector<int> & N,vector<int> & B,int leaving_index,int entering_index,vector<unsigned int> & indexToRow)315 static inline void pivot(Mat_<double>& c,Mat_<double>& b,double& v,vector<int>& N,vector<int>& B,
316 int leaving_index,int entering_index,vector<unsigned int>& indexToRow){
317 double Coef=b(leaving_index,entering_index);
318 for(int i=0;i<b.cols;i++){
319 if(i==entering_index){
320 b(leaving_index,i)=1/Coef;
321 }else{
322 b(leaving_index,i)/=Coef;
323 }
324 }
325
326 for(int i=0;i<b.rows;i++){
327 if(i!=leaving_index){
328 double coef=b(i,entering_index);
329 for(int j=0;j<b.cols;j++){
330 if(j==entering_index){
331 b(i,j)=-coef*b(leaving_index,j);
332 }else{
333 b(i,j)-=(coef*b(leaving_index,j));
334 }
335 }
336 }
337 }
338
339 //objective function
340 Coef=c(0,entering_index);
341 for(int i=0;i<(b.cols-1);i++){
342 if(i==entering_index){
343 c(0,i)=-Coef*b(leaving_index,i);
344 }else{
345 c(0,i)-=Coef*b(leaving_index,i);
346 }
347 }
348 dprintf(("v was %g\n",v));
349 v+=Coef*b(leaving_index,b.cols-1);
350
351 SWAP(int,N[entering_index],B[leaving_index]);
352 SWAP(int,indexToRow[N[entering_index]],indexToRow[B[leaving_index]]);
353 }
354
swap_columns(Mat_<double> & A,int col1,int col2)355 static inline void swap_columns(Mat_<double>& A,int col1,int col2){
356 for(int i=0;i<A.rows;i++){
357 double tmp=A(i,col1);
358 A(i,col1)=A(i,col2);
359 A(i,col2)=tmp;
360 }
361 }
362 }
363