lpsolver.cpp 10.3 KB
Newer Older
1
#include "opencv2/ts.hpp"
2
#include "precomp.hpp"
3 4
#include <climits>
#include <algorithm>
5
#include <cstdarg>
6 7

namespace cv{namespace optim{
8
using std::vector;
9

10
#ifdef ALEX_DEBUG
A
Alex Leontiev 已提交
11
#define dprintf(x) printf x
A
Alex Leontiev 已提交
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
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<double>(i,j));
        }
        printf("]\n");
    }
}
static void print_simplex_state(const Mat& c,const Mat& b,double v,const std::vector<int> N,const std::vector<int> 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<int>::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<int>::const_iterator it = (B).begin() ; it != (B).end(); ++it){
        printf("%d, ",*it);
    }
    printf("\n");
}
A
Alex Leontiev 已提交
45 46 47 48
#else
#define dprintf(x) do {} while (0)
#define print_matrix(x) do {} while (0)
#define print_simplex_state(c,b,v,N,B) do {} while (0)
49
#endif
A
Alex Leontiev 已提交
50

51 52 53 54 55 56
/**Due to technical considerations, the format of input b and c is somewhat special:
 *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
 by this procedure - it should not be cleaned before the call to procedure and may contain mess after
 it also initializes N and B and does not make any assumptions about their init values
 * @return SOLVELP_UNFEASIBLE if problem is unfeasible, 0 if feasible.
*/
57 58
static int initialize_simplex(Mat_<double>& c, Mat_<double>& b,double& v,vector<int>& N,vector<int>& B);
static inline void pivot(Mat_<double>& c,Mat_<double>& b,double& v,vector<int>& N,vector<int>& B, int leaving_index,int entering_index);
59 60
/**@return SOLVELP_UNBOUNDED means the problem is unbdd, SOLVELP_MULTI means multiple solutions, SOLVELP_SINGLE means one solution.
 */
61 62
static int inner_simplex(Mat_<double>& c, Mat_<double>& b,double& v,vector<int>& N,vector<int>& B);
static void swap_columns(Mat_<double>& A,int col1,int col2);
A
Alex Leontiev 已提交
63 64

//return codes:-2 (no_sol - unbdd),-1(no_sol - unfsbl), 0(single_sol), 1(multiple_sol=>least_l2_norm)
65
int solveLP(const Mat& Func, const Mat& Constr, Mat& z){
A
Alex Leontiev 已提交
66
    dprintf(("call to solveLP\n"));
67

68
    //sanity check (size, type, no. of channels)
A
Alex Leontiev 已提交
69 70 71 72
    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)));
A
Alex Leontiev 已提交
73 74

    //copy arguments for we will shall modify them
A
Alex Leontiev 已提交
75
    Mat_<double> bigC=Mat_<double>(1,(Func.rows==1?Func.cols:Func.rows)+1),
A
Alex Leontiev 已提交
76
        bigB=Mat_<double>(Constr.rows,Constr.cols+1);
A
Alex Leontiev 已提交
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
    if(Func.rows==1){
        Func.convertTo(bigC.colRange(1,bigC.cols),CV_64FC1);
    }else{
        dprintf(("hi from other branch\n"));
        Mat_<double> slice=bigC.colRange(1,bigC.cols);
        MatIterator_<double> slice_iterator=slice.begin();
        switch(Func.type()){
            case CV_64FC1:
                for(MatConstIterator_<double> it=Func.begin<double>();it!=Func.end<double>();it++,slice_iterator++){
                    * slice_iterator= *it;
                }
                break;
            case CV_32FC1:
                for(MatConstIterator_<float> it=Func.begin<float>();it!=Func.end<double>();it++,slice_iterator++){
                    * slice_iterator= *it;
                }
                break;
        }
        print_matrix(Func);
        print_matrix(bigC);
    }
    Constr.convertTo(bigB.colRange(1,bigB.cols),CV_64FC1);
A
Alex Leontiev 已提交
99 100 101
    double v=0;
    vector<int> N,B;

102 103
    if(initialize_simplex(bigC,bigB,v,N,B)==SOLVELP_UNFEASIBLE){
        return SOLVELP_UNFEASIBLE;
104
    }
A
Alex Leontiev 已提交
105 106 107 108
    Mat_<double> c=bigC.colRange(1,bigC.cols),
        b=bigB.colRange(1,bigB.cols);

    int res=0;
109 110
    if((res=inner_simplex(c,b,v,N,B))==SOLVELP_UNBOUNDED){
        return SOLVELP_UNBOUNDED;
111
    }
A
Alex Leontiev 已提交
112 113

    //return the optimal solution
A
Alex Leontiev 已提交
114
    z.create(c.cols,1,CV_64FC1);
A
Alex Leontiev 已提交
115 116 117 118 119 120 121 122 123 124 125 126 127
    MatIterator_<double> it=z.begin<double>();
    for(int i=1;i<=c.cols;i++,it++){
        std::vector<int>::iterator pos=B.begin();
        if((pos=std::find(B.begin(),B.end(),i))==B.end()){
            *it=0;
        }else{
            *it=b.at<double>(pos-B.begin(),b.cols-1);
        }
    }

    return res;
}

128
static int initialize_simplex(Mat_<double>& c, Mat_<double>& b,double& v,vector<int>& N,vector<int>& B){
A
Alex Leontiev 已提交
129 130
    N.resize(c.cols);
    N[0]=0;
131 132 133
    for (std::vector<int>::iterator it = N.begin()+1 ; it != N.end(); ++it){
        *it=it[-1]+1;
    }
A
Alex Leontiev 已提交
134 135
    B.resize(b.rows);
    B[0]=N.size();
136 137 138
    for (std::vector<int>::iterator it = B.begin()+1 ; it != B.end(); ++it){
        *it=it[-1]+1;
    }
A
Alex Leontiev 已提交
139
    v=0;
140

A
Alex Leontiev 已提交
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
    int k=0;
    {
        double min=DBL_MAX;
        for(int i=0;i<b.rows;i++){
            if(b(i,b.cols-1)<min){
                min=b(i,b.cols-1);
                k=i;
            }
        }
    }

    if(b(k,b.cols-1)>=0){
        N.erase(N.begin());
        return 0;
    }

    Mat_<double> old_c=c.clone();
    c=0;
    c(0,0)=-1;
    for(int i=0;i<b.rows;i++){
        b(i,0)=-1;
    }

    print_simplex_state(c,b,v,N,B);

A
Alex Leontiev 已提交
166
    dprintf(("\tWE MAKE PIVOT\n"));
A
Alex Leontiev 已提交
167 168 169 170 171 172
    pivot(c,b,v,N,B,k,0);

    print_simplex_state(c,b,v,N,B);

    inner_simplex(c,b,v,N,B);

A
Alex Leontiev 已提交
173
    dprintf(("\tAFTER INNER_SIMPLEX\n"));
A
Alex Leontiev 已提交
174 175
    print_simplex_state(c,b,v,N,B);

A
Alex Leontiev 已提交
176 177 178 179
    vector<int>::iterator iterator=std::find(B.begin(),B.end(),0);
    if(iterator!=B.end()){
        int iterator_offset=iterator-B.begin();
        if(b(iterator_offset,b.cols-1)>0){
180
            return SOLVELP_UNFEASIBLE;
A
Alex Leontiev 已提交
181
        }
A
Alex Leontiev 已提交
182
        pivot(c,b,v,N,B,iterator_offset,0);
A
Alex Leontiev 已提交
183 184
    }

A
Alex Leontiev 已提交
185 186 187 188 189 190 191
    {
        iterator=std::find(N.begin(),N.end(),0);
        int iterator_offset=iterator-N.begin();
        std::iter_swap(iterator,N.begin());
        swap_columns(c,iterator_offset,0);
        swap_columns(b,iterator_offset,0);
    }
A
Alex Leontiev 已提交
192

A
Alex Leontiev 已提交
193
    dprintf(("after swaps\n"));
A
Alex Leontiev 已提交
194 195 196 197 198
    print_simplex_state(c,b,v,N,B);

    //start from 1, because we ignore x_0
    c=0;
    v=0;
A
Alex Leontiev 已提交
199 200 201
    for(int I=1;I<old_c.cols;I++){
        if((iterator=std::find(N.begin(),N.end(),I))!=N.end()){
            dprintf(("I=%d from nonbasic\n",I));
A
Alex Leontiev 已提交
202
            fflush(stdout);
A
Alex Leontiev 已提交
203 204
            int iterator_offset=iterator-N.begin();
            c(0,iterator_offset)+=old_c(0,I);     
A
Alex Leontiev 已提交
205 206
            print_matrix(c);
        }else{
A
Alex Leontiev 已提交
207
            dprintf(("I=%d from basic\n",I));
A
Alex Leontiev 已提交
208
            fflush(stdout);
A
Alex Leontiev 已提交
209 210 211
            int iterator_offset=std::find(B.begin(),B.end(),I)-B.begin();
            c-=old_c(0,I)*b.row(iterator_offset).colRange(0,b.cols-1);
            v+=old_c(0,I)*b(iterator_offset,b.cols-1);
A
Alex Leontiev 已提交
212 213 214
            print_matrix(c);
        }
    }
215

A
Alex Leontiev 已提交
216
    dprintf(("after restore\n"));
A
Alex Leontiev 已提交
217 218 219 220 221
    print_simplex_state(c,b,v,N,B);

    N.erase(N.begin());
    return 0;
}
222

223
static int inner_simplex(Mat_<double>& c, Mat_<double>& b,double& v,vector<int>& N,vector<int>& B){
224 225
    int count=0;
    while(1){
A
Alex Leontiev 已提交
226 227
        dprintf(("iteration #%d\n",count));
        count++;
228

229
        static MatIterator_<double> pos_ptr;
A
Alex Leontiev 已提交
230 231 232 233 234 235 236 237 238 239 240 241 242 243
        int e=-1,pos_ctr=0,min_var=INT_MAX;
        bool all_nonzero=true;
        for(pos_ptr=c.begin();pos_ptr!=c.end();pos_ptr++,pos_ctr++){
            if(*pos_ptr==0){
                all_nonzero=false;
            }
            if(*pos_ptr>0){
                if(N[pos_ctr]<min_var){
                    e=pos_ctr;
                    min_var=N[pos_ctr];
                }
            }
        }
        if(e==-1){
A
Alex Leontiev 已提交
244
            dprintf(("hello from e==-1\n"));
A
Alex Leontiev 已提交
245 246
            print_matrix(c);
            if(all_nonzero==true){
247
                return SOLVELP_SINGLE;
A
Alex Leontiev 已提交
248
            }else{
249
                return SOLVELP_MULTI;
A
Alex Leontiev 已提交
250
            }
251
        }
A
Alex Leontiev 已提交
252

253
        int l=-1;
A
Alex Leontiev 已提交
254
        min_var=INT_MAX;
255 256
        double min=DBL_MAX;
        int row_it=0;
A
Alex Leontiev 已提交
257 258
        MatIterator_<double> min_row_ptr=b.begin();
        for(MatIterator_<double> it=b.begin();it!=b.end();it+=b.cols,row_it++){
259
            double myite=0;
A
Alex Leontiev 已提交
260
            //check constraints, select the tightest one, reinforcing Bland's rule
261 262
            if((myite=it[e])>0){
                double val=it[b.cols-1]/myite;
A
Alex Leontiev 已提交
263 264
                if(val<min || (val==min && B[row_it]<min_var)){
                    min_var=B[row_it];
265 266 267 268 269 270 271
                    min_row_ptr=it;
                    min=val;
                    l=row_it;
                }
            }
        }
        if(l==-1){
272
            return SOLVELP_UNBOUNDED;
273
        }
A
Alex Leontiev 已提交
274
        dprintf(("the tightest constraint is in row %d with %g\n",l,min));
275

276
        pivot(c,b,v,N,B,l,e);
277

A
Alex Leontiev 已提交
278
        dprintf(("objective, v=%g\n",v));
279
        print_matrix(c);
A
Alex Leontiev 已提交
280
        dprintf(("constraints\n"));
281
        print_matrix(b);
A
Alex Leontiev 已提交
282
        dprintf(("non-basic: "));
283
        for (std::vector<int>::iterator it = N.begin() ; it != N.end(); ++it){
A
Alex Leontiev 已提交
284
            dprintf(("%d, ",*it));
285
        }
A
Alex Leontiev 已提交
286
        dprintf(("\nbasic: "));
287
        for (std::vector<int>::iterator it = B.begin() ; it != B.end(); ++it){
A
Alex Leontiev 已提交
288
            dprintf(("%d, ",*it));
289
        }
A
Alex Leontiev 已提交
290
        dprintf(("\n"));
291
    }
A
Alex Leontiev 已提交
292
}
293

294
static inline void pivot(Mat_<double>& c,Mat_<double>& b,double& v,vector<int>& N,vector<int>& B, int leaving_index,int entering_index){
A
Alex Leontiev 已提交
295
    double Coef=b(leaving_index,entering_index);
A
Alex Leontiev 已提交
296 297
    for(int i=0;i<b.cols;i++){
        if(i==entering_index){
A
Alex Leontiev 已提交
298
            b(leaving_index,i)=1/Coef;
299
        }else{
A
Alex Leontiev 已提交
300
            b(leaving_index,i)/=Coef;
301 302 303
        }
    }

A
Alex Leontiev 已提交
304 305 306 307 308 309 310 311 312
    for(int i=0;i<b.rows;i++){
        if(i!=leaving_index){
            double coef=b(i,entering_index);
            for(int j=0;j<b.cols;j++){
                if(j==entering_index){
                    b(i,j)=-coef*b(leaving_index,j);
                }else{
                    b(i,j)-=(coef*b(leaving_index,j));
                }
313 314
            }
        }
A
Alex Leontiev 已提交
315 316 317
    }

    //objective function
A
Alex Leontiev 已提交
318
    Coef=c(0,entering_index);
A
Alex Leontiev 已提交
319 320
    for(int i=0;i<(b.cols-1);i++){
        if(i==entering_index){
A
Alex Leontiev 已提交
321
            c(0,i)=-Coef*b(leaving_index,i);
322
        }else{
A
Alex Leontiev 已提交
323
            c(0,i)-=Coef*b(leaving_index,i);
324 325
        }
    }
A
Alex Leontiev 已提交
326 327
    dprintf(("v was %g\n",v));
    v+=Coef*b(leaving_index,b.cols-1);
328
    
A
Alex Leontiev 已提交
329 330 331
    int tmp=N[entering_index];
    N[entering_index]=B[leaving_index];
    B[leaving_index]=tmp;
332
}
333

334
static inline void swap_columns(Mat_<double>& A,int col1,int col2){
A
Alex Leontiev 已提交
335 336 337 338 339 340
    for(int i=0;i<A.rows;i++){
        double tmp=A(i,col1);
        A(i,col1)=A(i,col2);
        A(i,col2)=tmp;
    }
}
341
}}