// XXX FIXME XXX leave this in until problems with incorrectly specified // number of equality constraints is resolved. #define BOUNDS_CHECKING #include #include #include #include #ifdef USE_OCTAVE_NAN #define lo_ieee_nan_value() octave_NaN #define lo_ieee_inf_value() octave_Inf #endif using namespace std; // Copyright (C) 2000 Ben Sapp. All rights reserved. // // This is free software; you can redistribute it and/or modify it // under the terms of the GNU General Public License as published by the // Free Software Foundation; either version 2, or (at your option) any // later version. // // This is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License // for more details. // 2001-09-20 Paul Kienzle // * Use x((int)rint(m(i,j))) instead of x(m(i,j)) #define TRUE 1 #define FALSE 0 // 2.1.51 and later have identity matrix defined in utils.h, but can't use // it to ensure that the code works with older octave versions static inline Matrix lp_identity_matrix(int m,int n) { int min = (m > n) ? n : m; Matrix me(m,n,0.0); for(int i=0;i The upper bound is the smallest #define CASE_B 1 // min{y_i0/y_ij} for all y_ij > 0 is the smallest #define CASE_C 2 // min{(y_i0-h_j)/y_ij) for all y_ij < 0 is the smallest // This takes a tableau and reduces it to the solution tableau. static Matrix minimize(Matrix T, Matrix &basis,ColumnVector upper_bounds,RowVector &which_bound) { int nr = T.rows(); int nc = T.cols(); int i,j,k,min_case; double min_val; int min_row = 0; int found_one; while(TRUE){ found_one = FALSE; for(i=0;i<(nc-1);i++){ if(T(nr-1,i) < -10.0*DBL_EPSILON){ found_one = TRUE; break; } } if(!found_one){ break; } // Now i is the column we will pivot on. min_row = -1; min_case = CASE_A; min_val = upper_bounds(i); for(j=0;j<(nr-1);j++){ if(T(j,i) > 0){ if(min_val > (T(j,nc-1)/T(j,i))){ min_row = j; min_val = T(j,nc-1)/T(j,i); min_case = CASE_B; } }else if(T(j,i) < 0){ if(min_val > ((T(j,nc-1)-upper_bounds(i))/T(j,i))){ min_row = j; min_val = (T(j,nc-1)-upper_bounds(i))/T(j,i); min_case = CASE_C; } } } int interesting_column=0; for(j=0;j<(nr-1);j++){ if(basis(j,0) == min_row){ interesting_column = int(basis(j,1)); /*basis(j,0) = min_row; basis(j,1) = i; */ break; } } // Now min_row is the row and i is the column to pivot on. Matrix Id; switch(min_case) { case CASE_A: for(k = 0; k < nr; k++) { T(k,i) = -T(k,i); T(k,nc-1) += T(k,i); } which_bound(i) = -which_bound(i); break; case CASE_B: T = pivot(T,min_row,i); for(j=0;j 6) { print_usage("lp"); return retval; } else { c = RowVector(args(0).vector_value()); A = args(1).matrix_value(); b = ColumnVector(args(2).vector_value()); } switch(nargin) { case 6: if(args(5).is_real_scalar()) { ne = int(args(5).double_value()); } else { error("You must supply a scalar for the number of constraints that are equalities"); return retval; } case 5: if (!args(4).is_empty()) vub = ColumnVector(args(4).vector_value()); case 4: if (!args(3).is_empty()) vlb = ColumnVector(args(3).vector_value()); case 3: break; } if (error_state) return octave_value_list(); warning("lp is unreliable: the returned solution does not always lie within the bounds"); int nr = A.rows(); int nc = A.columns(); if(check_dimensions(c,A,b,vlb,vub) < 0){return retval;} ColumnVector orig_vub(vub); // Now take care of upper and lower bounds Matrix freeVars(0,2,0.0); int freeVarNum = 0; for (i=0; i {-Inf < x < x_max} // After we are done it will be {0 < x_new < Inf}, where {x_new = -x+x_max} b = b-A.column(i)*vub(i); T = lp_identity_matrix(A.rows()); T(i,i) = -1.0; A = A*T; vub(i) = inf; } else { // std::cout << i << " split variable\n"; // both bounds are infinity so make this into two variables; // Now we have the following constraint -Inf < x < Inf // After we are done we have {0 < x1_new < Inf} and // {0 < x2_new < Inf} where {x = x1_new-x2_new} A = A.append(-A.column(i)); c.resize(c.length()+1,-c(i)); vub.resize(vub.length()+1,inf); freeVars.resize(freeVarNum+1,2,0.0); freeVars(freeVarNum,0) = i; freeVars(freeVarNum,1) = A.cols()-1; freeVarNum++; } } // find a basis. Each row of basis holds where one element of the basis is. // For example if [1,2] is on row 1 of basis then row 1 , column 2 is an // element in the basis. Matrix basis(nr,2,-1.0); RowVector which_bound(nc+freeVarNum,1.0); int index = 0; int slacks = 0; if(ne <= nr) { A = A.append(lp_identity_matrix(nr,(nr-ne))); for(i=0;i<(nr-ne);i++) { basis(i,1) = i+nc; basis(i,0) = i; index++; slacks++; } which_bound = which_bound.append(RowVector(nr-ne,1.0)); vub = vub.stack(ColumnVector(nr-ne,inf)); c = c.append(RowVector(nr-ne,0)); } else { error("lp: it does not make sense to have more equalities than the rank of the system"); return(retval); } if(index < nr) { include_in_basis = FALSE; // Loop over all columns for(i = 0;i < nc;i++) { k=0; // Decide if this column can be included in a basis for(j = 0;j 1){break; /* If there are already too many non-zero entries ... move on! */ } } if(k == (nr-1)) { basis(index,1) = i; include_in_basis = TRUE; for(l = 0;l