view src/DLD-FUNCTIONS/__glpk__.cc @ 5232:9b776f5a33eb

[project @ 2005-03-22 16:16:30 by jwe]
author jwe
date Tue, 22 Mar 2005 16:18:26 +0000
parents
children a791b8b777e4
line wrap: on
line source

/*- --------------------------------------------------------------------
 --
 -- Copyright (C) 2005, Nicolo' Giorgetti, All rights reserved.
 -- E-mail: <giorgetti@dii.unisi.it>.
 --
 -- This file is part of GLPKOCT an Octave interface to GLPK.
 --
 -- GLPK 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.
 --
 -- GLPK 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.
 --
 -- You should have received a copy of the GNU General Public License
 -- along with GLPK; see the file COPYING. If not, write to the Free
 -- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 -- 02111-1307, USA.
 --
 -- ---------------------------------------------------------------------*/

#include <cfloat>
#include <csetjmp>
#include <ctime>

//-- Octave headers
#include <oct.h>
#include <octave/ov-struct.h>
#include <octave/config.h>
#include <octave/error.h>

//-- GLPK C header
extern "C"{
#include "glpk.h"
}

#define OCTOUT octave_stdout
#define OCTERR octave_stdout
#define NIntP 17
#define NRealP 10

int lpxIntParam[NIntP]= {
   1,
   1,
   0,
   1,
   0,
   -1,
   0,
   200,
   1,
   2,
   0,
   1,
   0,
   0,
   2, 
   2,
   1
};

int IParam[NIntP]={
   LPX_K_MSGLEV,
   LPX_K_SCALE,
   LPX_K_DUAL,
   LPX_K_PRICE,
   LPX_K_ROUND,
   LPX_K_ITLIM,
   LPX_K_ITCNT,
   LPX_K_OUTFRQ,
   LPX_K_MPSINFO,
   LPX_K_MPSOBJ,
   LPX_K_MPSORIG,
   LPX_K_MPSWIDE,
   LPX_K_MPSFREE,
   LPX_K_MPSSKIP,
   LPX_K_BRANCH,
   LPX_K_BTRACK,
   LPX_K_PRESOL
};


double lpxRealParam[NRealP]={
   0.07,
   1e-7,
   1e-7,
   1e-9,
   -DBL_MAX,
   DBL_MAX,
   -1.0,
   0.0,
   1e-6,
   1e-7
};

int RParam[NRealP]={
   LPX_K_RELAX,
   LPX_K_TOLBND,
   LPX_K_TOLDJ,
   LPX_K_TOLPIV,
   LPX_K_OBJLL,
   LPX_K_OBJUL,
   LPX_K_TMLIM,
   LPX_K_OUTDLY,
   LPX_K_TOLINT,
   LPX_K_TOLOBJ
};

jmp_buf mark;  //-- Address for long jump to jump to
int     fperr; //-- Global error number


int glpkmex_fault_hook(void *info,  char *msg)
{    
    OCTERR<<"*** SEVERE CRITICAL ERROR *** from GLPK !\n\n"<<msg<<" %s\n";
    longjmp( mark, -1 );
}

int glpkmex_print_hook(void *info,  char *msg)
{
    OCTERR<<msg<<"\n";
    return 1;
}


int glpk(int sense,int n, int m, double *c,int nz,int *rn,int *cn, 
         double *a,double *b, char *ctype,int *freeLB, double *lb, 
	 int *freeUB, double *ub, int *vartype, int isMIP, int lpsolver,
	 int save_pb, double *xmin, double *fmin, double *status,
         double *lambda, double *redcosts, double *time, double *mem)
{
   
   LPX *lp;
   int i,j;
   int error;
   clock_t  t_start;
   int typx=0;
   int method;

   t_start = clock();
   
   lib_set_fault_hook(NULL,glpkmex_fault_hook);
   

   if (lpxIntParam[0] > 1){
         lib_set_print_hook(NULL,glpkmex_print_hook);
   }
      
   lp=lpx_create_prob();
     
   
   //-- Set the sense of optimization
   if (sense==1) lpx_set_obj_dir(lp,LPX_MIN);
   else lpx_set_obj_dir(lp,LPX_MAX);

   //-- If the problem has integer structural variables switch to MIP
   if(isMIP) lpx_set_class(lp,LPX_MIP);

   lpx_add_cols(lp,n);   
   for(i=0;i<n;i++){
	
      //-- Define type of the structural variables
      if (!freeLB[i] && !freeUB[i]){
        lpx_set_col_bnds(lp,i+1,LPX_DB,lb[i],ub[i]);
      }else{
         if (!freeLB[i] && freeUB[i]){
            lpx_set_col_bnds(lp,i+1,LPX_LO,lb[i],ub[i]);
         }else{
            if (freeLB[i] && !freeUB[i]){
               lpx_set_col_bnds(lp,i+1,LPX_UP,lb[i],ub[i]);
            }else{
               lpx_set_col_bnds(lp,i+1,LPX_FR,lb[i],ub[i]);
            }
         }
      }
      // -- Set the objective coefficient of the corresponding 
      // -- structural variable. No constant term is assumed.
	  lpx_set_obj_coef(lp,i+1,c[i]);

      if(isMIP){
        lpx_set_col_kind(lp,i+1,vartype[i]);
      }
   }
   
   lpx_add_rows(lp,m);   
   for(i=0;i<m;i++){
   
      /* If the i-th row has no lower bound (types F,U), the
         corrispondent parameter will be ignored.
         If the i-th row has no upper bound (types F,L), the corrispondent
         parameter will be ignored.
         If the i-th row is of S type, the i-th LB is used, but
         the i-th UB is ignored.
      */
      switch(ctype[i]){
         case 'F': typx=LPX_FR; break;
         case 'U': typx=LPX_UP; break;
         case 'L': typx=LPX_LO; break;
         case 'S': typx=LPX_FX; break;
         case 'D': typx=LPX_DB; 
      }
      lpx_set_row_bnds(lp,i+1,typx,b[i],b[i]);

   }
   lpx_load_matrix(lp,nz,rn,cn,a);

   if (save_pb){
      if(lpx_write_cpxlp(lp, "outpb.lp") != 0){
        OCTERR<<"Unable to write problem\n";
        longjmp( mark, -1 );
      }
   }

   //-- scale the problem data (if required)
   //-- if (scale && (!presol || method == 1)) lpx_scale_prob(lp);
   //-- LPX_K_SCALE=IParam[1]  LPX_K_PRESOL=IParam[16]
   if (lpxIntParam[1] && (!lpxIntParam[16] || lpsolver!=1)){
      lpx_scale_prob(lp);
   }
   //-- build advanced initial basis (if required)
   if (lpsolver == 1 && !lpxIntParam[16]){
      lpx_adv_basis(lp);
   }
 
   for(i=0;i<NIntP;i++){
     lpx_set_int_parm(lp,IParam[i],lpxIntParam[i]);
   }
   for(i=0;i<NRealP;i++){
     lpx_set_real_parm(lp,RParam[i],lpxRealParam[i]);
   } 

   if(lpsolver==1) method='S';
   else method='T';

   switch(method){
   case 'S':
     if(isMIP){
       method='I';
       error=lpx_simplex(lp);
       error=lpx_integer(lp);
     }else{
       error=lpx_simplex(lp);
     }
     break;
   case 'T':
     error=lpx_interior(lp);
     break;
   default:
     insist(method != method);
   }

   /*
       error assumes the following results:
       error=0 <=> No errors
       error=1 <=> Iteration limit exceeded.
       error=2 <=> Numerical problems with basis matrix.
   */
   if(error==LPX_E_OK){
     if(isMIP){
       *status=(double)lpx_mip_status(lp);
       *fmin=lpx_mip_obj_val(lp);
     }else{
       if(lpsolver==1){
         *status=(double)lpx_get_status(lp);
         *fmin=lpx_get_obj_val(lp);
       }else{
         *status=(double)lpx_ipt_status(lp);
         *fmin=lpx_ipt_obj_val(lp);
       }
     }
     if(isMIP){
         for(i=0;i<n;i++)  xmin[i]=lpx_mip_col_val(lp,i+1);
     }else{
      /* Primal values */
      for(i=0;i<n;i++){
         if(lpsolver==1) xmin[i]=lpx_get_col_prim(lp,i+1);
         else xmin[i]=lpx_ipt_col_prim(lp,i+1);
      }
      /* Dual values */
      for(i=0; i<m; i++){
         if(lpsolver==1) lambda[i]=lpx_get_row_dual(lp,i+1);
         else lambda[i]=lpx_ipt_row_dual(lp,i+1);
      }
      /* Reduced costs */
      for(i=0; i<lpx_get_num_cols(lp); i++){
         if(lpsolver==1) redcosts[i]=lpx_get_col_dual(lp,i+1);
         else redcosts[i]=lpx_ipt_col_dual(lp,i+1);
      }
     }
     *time=((double)(clock() - t_start))/CLOCKS_PER_SEC;
     *mem=(double)lib_env_ptr()->mem_tpeak;      

     lpx_delete_prob(lp);
     return(0);
   }
   lpx_delete_prob(lp);
   *status=(double)error;
   return(error);
}





DEFUN_DLD(glpkoct, args, nlhs, "glpkoct: OCT interface for the GLPK library. Don't use glpkoct, use glpk.m instead")
{
   // The list of values to return.  See the declaration in oct-obj.h
   octave_value_list retval;

   int nrhs=args.length();
	
   if(nrhs<1){
      OCTERR<<"Use the script glpk for the optimization\n";
      return retval;
   }	
   
   //-- 1st Input. Sense of optimization.
   int sense;
   double SENSE = args(0).scalar_value ();
   if (SENSE>=0) sense=1;
   else sense =-1;
   
   //-- 2nd Input. A column array containing the objective function
   //--            coefficients.
   int mrowsc=args(1).rows();
   
   Matrix C(args(1).matrix_value());
   double *c=C.fortran_vec();
   	
   //-- 3rd Input. A matrix containing the constraints coefficients.
   // If matrix A is NOT a sparse matrix
   // if(!mxIsSparse(A_IN)){
   int mrowsA=args(2).rows();	
   Matrix A(args(2).matrix_value()); // get the matrix
   Array<int> rn (mrowsA*mrowsc+1);
   Array<int> cn (mrowsA*mrowsc+1);
   ColumnVector a (mrowsA*mrowsc+1, 0.0);

   int nz=0;
   for(int i=0;i<mrowsA;i++){
      for(int j=0;j<mrowsc;j++){
        if(A(i,j) != 0){
           nz++;
	   rn(nz)=i+1;
	   cn(nz)=j+1;
	   a(nz)=A(i,j);
        }
      }
   }
// DON'T DELETE THIS PART... REPRESENTS THE SPARSE MATRICES MANIPULATION
//	  }else{
//	    int i,j;
//	    int *jc,*ir;
//	    double *pr;
//	    int nelc,count,row;
//
//	    /* NOTE: nnz is the actual number of nonzeros and is stored as the
//       last element of the jc array where the size of the jc array is the
//       number of columns + 1 */
//	    nz = *(mxGetJc(A_IN) + mrowsc);
//	    jc = mxGetJc(A_IN);
//	    ir = mxGetIr(A_IN);
//	    pr = mxGetPr(A_IN);
//
//       rn=(int *)calloc(nz+1,sizeof(int));
//	    cn=(int *)calloc(nz+1,sizeof(int));
//	    a=(double *)calloc(nz+1,sizeof(double));
//
//       count=0; row=0;
//	    for(i=1;i<=mrowsc;i++){
//	      nelc=jc[i]-jc[i-1];
//	      for(j=0;j<nelc;j++){
//		      count++;
//		      rn[count]=ir[row]+1;
//		      cn[count]=i;
//		      a[count]=pr[row];
//		      row++;
//	      }
//	    }
//	  }

   //-- 4th Input. A column array containing the right-hand side value
   //	           for each constraint in the constraint matrix.
   Matrix B(args(3).matrix_value());
   double *b=B.fortran_vec();
   	
   for(int i=0; i< mrowsA; i++){
   	if (isinf(b[i]) && b[i]<0) b[i]=-octave_Inf;
   	if (isinf(b[i]) && b[i]>0) b[i]=octave_Inf;
   }	

      	
   //-- 5th Input. A column array containing the sense of each constraint
   //--            in the constraint matrix.
   charMatrix CTYPE(args(4).char_matrix_value());	
	
   char *ctype=CTYPE.fortran_vec();
	
   //-- 6th Input. An array of length mrowsc containing the lower
   //--            bound on each of the variables.
   Matrix LB(args(5).matrix_value());
   		 		
   double *lb=LB.fortran_vec();
   
   //-- LB argument, default: Free
   Array<int> freeLB (mrowsc);
   for(int i=0;i<mrowsc;i++){
      if(isinf(lb[i])){
         freeLB(i)=1;
         lb[i]=-octave_Inf;
      }else freeLB(i)=0;
   }
   
   //-- 7th Input. An array of at least length numcols containing the upper
   //--            bound on each of the variables.
   Matrix UB(args(6).matrix_value());
   		
   double *ub=UB.fortran_vec();
 			
   Array<int> freeUB (mrowsc);
   for(int i=0;i<mrowsc;i++){
      if(isinf(ub[i])){
         freeUB(i)=1;
	 ub[i]=octave_Inf;
      }else freeUB(i)=0;
   }
		
   //-- 8th Input. A column array containing the types of the variables.
   charMatrix VTYPE(args(7).char_matrix_value());

   Array<int> vartype (mrowsc);
   int isMIP;
   for (int i = 0; i < mrowsc ; i++){
      if(VTYPE(i,0)=='I'){
         isMIP=1;
	 vartype(i)=LPX_IV;
      }else{
         vartype(i)=LPX_CV;
      }
   }

   //-- 9th Input. A structure containing the control parameters.
   Octave_map PARAM = args(8).map_value();
   
   //-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
   //-- Integer parameters                                             
   //-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

   //-- Level of messages output by the solver
   if(PARAM.contains("msglev")){
      octave_value tmp=PARAM.contents(PARAM.seek("msglev"))(0);

      double numtmp=tmp.scalar_value();
      if((numtmp != 0) && (numtmp != 1) && (numtmp != 2) && (numtmp != 3)){
         OCTOUT<<"'msglev' parameter must be only:\n\t0 - no output,\n\t1 - error messages only),\n\t2 - normal output,\n\t3 - full output [default]\n";
         return retval;
      }
         lpxIntParam[0]=(int) numtmp;
   }	

   //-- scaling option
   if(PARAM.contains("scale")){
      octave_value tmp=PARAM.contents(PARAM.seek("scale"))(0);
      double numtmp=tmp.scalar_value(); 
      if((numtmp != 0) && (numtmp != 1) && (numtmp != 2)){
         OCTOUT<<"'scale' parameter must be only:\n\t0 - no scaling,\n\t1 - equilibration scaling,\n\t2 - geometric mean scaling\n";
         return retval;
   }
      lpxIntParam[1]=(int) numtmp;
   }

   //-- Dual dimplex option
   if(PARAM.contains("dual")){
      octave_value tmp=PARAM.contents(PARAM.seek("dual"))(0);
      double numtmp=tmp.scalar_value();
      if((numtmp != 0) && (numtmp != 1)){
         OCTOUT<<"'dual' parameter must be only:\n\t0 - do not use the dual simplex [default],\n\t1 - use dual simplex\n";
         return retval;
      }
      lpxIntParam[2]=(int) numtmp;
   }

   //-- Pricing option
   if(PARAM.contains("price")){
      octave_value tmp=PARAM.contents(PARAM.seek("price"))(0);
      double numtmp=tmp.scalar_value();
      if((numtmp != 0) && (numtmp != 1)){
         OCTOUT<<"'price' parameter must be only:\n\t0 - textbook pricing,\n\t1 - steepest edge pricing [default]\n";
	 return retval;
      }
      lpxIntParam[3]=(int) numtmp;
   }

   //-- Solution rounding option 
   if(PARAM.contains("round")){
      octave_value tmp=PARAM.contents(PARAM.seek("round"))(0);
      double numtmp=tmp.scalar_value();
      if((numtmp != 0) && (numtmp != 1)){
         OCTOUT<<"'round' parameter must be only:\n\t0 - report all primal and dual values [default],\n\t1 - replace tiny primal and dual values by exact zero\n";
	return retval;
      }
      lpxIntParam[4]=(int) numtmp;
   }

   //-- Simplex iterations limit
   if(PARAM.contains("itlim")){
      octave_value tmp=PARAM.contents(PARAM.seek("itlim"))(0);
      lpxIntParam[5]=(int) tmp.scalar_value(); }

   //-- Simplex iterations count
   if(PARAM.contains("itcnt")){
      octave_value tmp=PARAM.contents(PARAM.seek("itcnt"))(0);
      lpxIntParam[6]=(int) tmp.scalar_value(); }
 
   //-- Output frequency, in iterations
   if(PARAM.contains("outfrq")){
      octave_value tmp=PARAM.contents(PARAM.seek("outfrq"))(0);
      lpxIntParam[7]=(int) tmp.scalar_value(); }
 
   //-- Branching heuristic option
   if(PARAM.contains("branch")){
      octave_value tmp=PARAM.contents(PARAM.seek("branch"))(0);
      double numtmp=tmp.scalar_value();			
      if((numtmp != 0) && (numtmp != 1) && (numtmp != 2)){
         OCTOUT<<"'branch' parameter must be only (for MIP only):\n\t0 - branch on the first variable,\n\t1 - branch on the last variable,\n\t2 - branch using a heuristic by Driebeck and Tomlin [default]\n";
         return retval;
      }
      lpxIntParam[14]=(int) numtmp;
   }

   //-- Backtracking heuristic option
   if(PARAM.contains("btrack")){
      octave_value tmp=PARAM.contents(PARAM.seek("btrack"))(0);
      double numtmp=tmp.scalar_value();	
      if((numtmp != 0) && (numtmp != 1) && (numtmp != 2)){
         OCTOUT<<"'btrack' parameter must be only (for MIP only):\n\t0 - depth first search,\n\t1 - breadth first search,\n\t2 - backtrack using the best projection heuristic\n";
	 return retval;
      }
      lpxIntParam[15]=(int) numtmp;
   }

   //-- Presolver option
   if(PARAM.contains("presol")){
      octave_value tmp=PARAM.contents(PARAM.seek("presol"))(0);
      double numtmp=tmp.scalar_value();
      if((numtmp != 0) && (numtmp != 1)){
         OCTOUT<<"'presol' parameter must be only:\n\t0 - LP presolver is ***NOT*** used,\n\t1 - LP presol is used\n";
	 return retval;
      }
      lpxIntParam[16]=(int) numtmp;
   }

   //-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
   //-- Real parameters                                                
   //-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

   //-- Ratio test option
   if(PARAM.contains("relax")){
      octave_value tmp=PARAM.contents(PARAM.seek("relax"))(0);
      lpxRealParam[0]=tmp.scalar_value(); }

   //-- Relative tolerance used to check if the current basic solution
   //-- is primal feasible
   if(PARAM.contains("tolbnd")){
      octave_value tmp=PARAM.contents(PARAM.seek("tolbn"))(0);
      lpxRealParam[1]=tmp.scalar_value(); }

   //-- Absolute tolerance used to check if the current basic solution
   //-- is dual feasible
   if(PARAM.contains("toldj")){
      octave_value tmp=PARAM.contents(PARAM.seek("toldj"))(0);
      lpxRealParam[2]=tmp.scalar_value(); }
		
   //-- Relative tolerance used to choose eligible pivotal elements of
   //--	the simplex table in the ratio test
   if(PARAM.contains("tolpiv")){
      octave_value tmp=PARAM.contents(PARAM.seek("tolpiv"))(0);
      lpxRealParam[3]=tmp.scalar_value(); }
		
   if(PARAM.contains("objll")){
      octave_value tmp=PARAM.contents(PARAM.seek("objll"))(0);
      lpxRealParam[4]=tmp.scalar_value(); }
		
   if(PARAM.contains("objul")){
      octave_value tmp=PARAM.contents(PARAM.seek("objul"))(0);
      lpxRealParam[5]=tmp.scalar_value(); }
		
   if(PARAM.contains("tmlim")){
      octave_value tmp=PARAM.contents(PARAM.seek("tmlim"))(0);
      lpxRealParam[6]=tmp.scalar_value(); }
		
   if(PARAM.contains("outdly")){
      octave_value tmp=PARAM.contents(PARAM.seek("outdly"))(0);
      lpxRealParam[7]=tmp.scalar_value(); }
		
   if(PARAM.contains("tolint")){
      octave_value tmp=PARAM.contents(PARAM.seek("tolint"))(0);
      lpxRealParam[8]=tmp.scalar_value(); }
		
   if(PARAM.contains("tolobj")){
      octave_value tmp=PARAM.contents(PARAM.seek("tolobj"))(0);
      lpxRealParam[9]=tmp.scalar_value(); }
	

   //-- 10th Input. If the problem is a LP problem you may select which solver
   //--      use: RSM (Revised Simplex Method) or IPM (Interior Point Method).
   //--      If the problem is a MIP problem this field will be ignored.
   octave_value tmp=args(9).scalar_value();
   int lpsolver = (int) tmp.scalar_value();

   //-- 11th Input. Saves a copy of the problem if SAVE<>0.
   tmp=args(10).scalar_value();
   int save_pb = (tmp.scalar_value() != 0);

   //-- Assign pointers to the output parameters
   ColumnVector xmin (mrowsc);
   ColumnVector fmin (1);
   ColumnVector status (1);
   ColumnVector lambda (mrowsA);
   ColumnVector redcosts (mrowsc);
   ColumnVector time (1);
   ColumnVector mem (1);
	
   int jmpret = setjmp( mark );
   if (jmpret==0){
      int error=glpk(sense,mrowsc,mrowsA,c,nz,
		     rn.fortran_vec(),cn.fortran_vec(),a.fortran_vec(),b,ctype,
		     freeLB.fortran_vec(),lb,freeUB.fortran_vec(),ub,
		     vartype.fortran_vec(),isMIP,lpsolver,save_pb,
		     xmin.fortran_vec(),fmin.fortran_vec(),status.fortran_vec(),
		     lambda.fortran_vec(),redcosts.fortran_vec(), 
		     time.fortran_vec(),mem.fortran_vec());
   }

   // Set the output parameters
   retval(0)=octave_value(xmin);  // returns xmin
   retval(1)=octave_value(fmin);   // returns fmin
   retval(2)=octave_value(status); // returns status
	
   // Extra informations
   Octave_map extra("lambda",octave_value(lambda)); //returns lambda
   extra.assign("redcosts",octave_value(redcosts)); //returns the reduced costs
   extra.assign("time",octave_value(time)); //time to solve the optimization pb
   extra.assign("mem",octave_value(mem));   //memory used

   retval(3)=extra;
	
   return retval;
}