Mercurial > octave
diff 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 diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/DLD-FUNCTIONS/__glpk__.cc Tue Mar 22 16:18:26 2005 +0000 @@ -0,0 +1,653 @@ +/*- -------------------------------------------------------------------- + -- + -- 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; +} +