valueset: Remove the unused link field.
[libfirm] / ir / lpp / lpp_gurobi.c
index d7c942c..6b043e4 100644 (file)
@@ -1,25 +1,34 @@
+/*
+ * Copyright (C) 2005-2011 University of Karlsruhe.  All right reserved.
+ *
+ * This file is part of libFirm.
+ *
+ * This file may be distributed and/or modified under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * Licensees holding valid libFirm Professional Edition licenses may use
+ * this file in accordance with the libFirm Commercial License.
+ * Agreement provided with the Software.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
 /**
- * Author:      Matthias Braun
- * Copyright:   (c) Universitaet Karlsruhe
- * Licence:     This file protected by GPL -  GNU GENERAL PUBLIC LICENSE.
+ * @file
+ * @author  Matthias Braun
  */
 #include "config.h"
 
+#ifdef WITH_GUROBI
 #include "lpp_gurobi.h"
 
 #include <stdio.h>
 #include <stdlib.h>
-
-#ifdef WITH_GUROBI
-
-
-#ifdef _WIN32
-#include <malloc.h>
-#else
-#include <sys/time.h>
-#include <alloca.h>
-#endif
-#include <assert.h>
+#include <math.h>
 
 #include "obst.h"
 
 static char gurobi_cst_encoding[4] = { 0, GRB_EQUAL, GRB_LESS_EQUAL, GRB_GREATER_EQUAL };
 static char gurobi_var_encoding[4] = { 0, 0, GRB_CONTINUOUS, GRB_BINARY };
 
-#define my_timersub(tvp, uvp, vvp)                     \
-    do {                                \
-        (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec;      \
-        (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec;   \
-        if ((vvp)->tv_usec < 0) {               \
-            (vvp)->tv_sec--;                \
-            (vvp)->tv_usec += 1000000;          \
-        }                           \
-    } while (0)
-
 typedef struct _gurobi_t {
        lpp_t *lpp;
        GRBenv *env;
+       GRBenv *modelenv;
        GRBmodel *model;
 } gurobi_t;
 
@@ -60,16 +60,28 @@ static gurobi_t *new_gurobi(lpp_t *lpp)
 
        gurobi_t *grb = XMALLOCZ(gurobi_t);
        grb->lpp = lpp;
-       error = GRBloadenv(&grb->env, NULL);
-       check_gurobi_error(grb, error);
-       error = GRBsetlogfile(grb->env, lpp->log);
+       /* /tmp/firm_gurobi.log is a hack (see below) */
+       error = GRBloadenv(&grb->env, "/tmp/firm_gurobi.log");
        check_gurobi_error(grb, error);
+       /* Matze: do not set the FILE* for logging output. Because:
+        *  a) the function is deprecated
+        *  b) gurobi closes the FILE handle when it is done, which leads to
+        *     very unexpected effects when you pass stdout or stderr as logging
+        *     output.
+        * The only thing gurobi sanely supports is giving a string with a filename
+        * :-( ...so we use /tmp/firm_gurobi.log as a temporary measure...
+        */
+       if (lpp->log != stdout && lpp->log != stderr) {
+               error = GRBsetintparam(grb->env, GRB_INT_PAR_OUTPUTFLAG, 0);
+               check_gurobi_error(grb, error);
+       }
 
        return grb;
 }
 
 static void free_gurobi(gurobi_t *grb)
 {
+       GRBfreemodel(grb->model);
        GRBfreeenv(grb->env);
        free(grb);
 }
@@ -80,16 +92,18 @@ static void free_gurobi(gurobi_t *grb)
  */
 static void gurobi_construct(gurobi_t *grb)
 {
-       const matrix_elem_t *elem;
-       int                  i, o, sv_cnt;
-       int                  numcols, numrows, numentries;
-       int                  objsen, *matbeg, *matcnt, *matind, *indices;
-       double               *obj, *rhs, *matval, *lb, *startv;
-       char                 *sense, *vartype;
-       char                 **colname, **rowname;
-       struct obstack       obst;
-       lpp_t                *lpp = grb->lpp;
-       int                  error;
+       int            i, o;
+       //int            sv_cnt;
+       //int           *indices;
+       //double        *startv;
+       int            numcols, numrows, numentries;
+       int            objsen, *matbeg, *matcnt, *matind;
+       double        *obj, *rhs, *matval, *lb;
+       char          *sense, *vartype;
+       char         **colname, **rowname;
+       struct obstack obst;
+       lpp_t         *lpp = grb->lpp;
+       int            error;
 
        numcols    = lpp->var_next-1;
        numrows    = lpp->cst_next-1;
@@ -102,8 +116,8 @@ static void gurobi_construct(gurobi_t *grb)
        colname = obstack_alloc(&obst, numcols * sizeof(*colname));
        rowname = obstack_alloc(&obst, numrows * sizeof(*rowname));
        vartype = obstack_alloc(&obst, numcols * sizeof(*vartype));
-       indices = obstack_alloc(&obst, numcols * sizeof(*indices));
-       startv  = obstack_alloc(&obst, numcols * sizeof(*startv));
+       //indices = obstack_alloc(&obst, numcols * sizeof(*indices));
+       //startv  = obstack_alloc(&obst, numcols * sizeof(*startv));
        matbeg  = obstack_alloc(&obst, numcols * sizeof(*matbeg));
        matcnt  = obstack_alloc(&obst, numcols * sizeof(*matcnt));
        matind  = obstack_alloc(&obst, numentries * sizeof(*matind));
@@ -112,7 +126,7 @@ static void gurobi_construct(gurobi_t *grb)
        sense   = obstack_alloc(&obst, numrows * sizeof(*sense));
 
        o      = 0;
-       sv_cnt = 0;
+       //sv_cnt = 0;
        /* fill the CPLEX matrix*/
        for (i = 0; i < numcols; ++i) {
                lpp_name_t *curr_var = lpp->vars[1+i];
@@ -123,14 +137,6 @@ static void gurobi_construct(gurobi_t *grb)
                colname[i] = (char*) curr_var->name;
                vartype[i] = gurobi_var_encoding[curr_var->type.var_type];
 
-#if 0
-               if (curr_var->value_kind == lpp_value_start) {
-                       panic("start values not supported in gurobi yet");
-                       indices[sv_cnt]  = i;
-                       startv[sv_cnt++] = curr_var->value;
-               }
-#endif
-
                matbeg[i] = o;
                matcnt[i] = 0;
                matrix_foreach_in_col(lpp->m, 1 + i, elem) {
@@ -156,9 +162,10 @@ static void gurobi_construct(gurobi_t *grb)
                             objsen, 0, obj, sense, rhs, matbeg, matcnt, matind,
                             matval, lb, NULL, vartype, colname, rowname);
        check_gurobi_error(grb, error);
+       grb->modelenv = GRBgetenv(grb->model);
 
        obstack_free(&obst, NULL);
-       free_lpp_matrix(lpp);
+       lpp_free_matrix(lpp);
 }
 
 static void gurobi_solve(gurobi_t *grb)
@@ -169,48 +176,17 @@ static void gurobi_solve(gurobi_t *grb)
        int error;
        int numcols = lpp->var_next-1;
        double *values;
-       struct timeval tvb, tva, tvdiff;
-       double iterations;
-
-       /* set performance parameters */
-       // CPXsetintparam(grb->env, CPX_PARAM_MIPSTART, CPX_ON);
-       //CPXsetintparam(grb->env, CPX_PARAM_MIPORDTYPE, CPX_MIPORDER_COST);
-       /* output every search tree node */
-       // CPXsetintparam(grb->env, CPX_PARAM_MIPINTERVAL, 1);
-
-       /* experimental switches */
-       // CPXsetintparam(grb->env, CPX_PARAM_VARSEL, CPX_VARSEL_STRONG);
-       // CPXsetdblparam(grb->env, CPX_PARAM_BTTOL, 1.0);
-       // CPXsetintparam(grb->env, CPX_PARAM_BRDIR, CPX_BRDIR_UP);
+       double  iterations;
 
        /* Set the time limit appropriately */
        if(lpp->time_limit_secs > 0.0) {
-               error = GRBsetdblparam(grb->env, GRB_DBL_PAR_TIMELIMIT, lpp->time_limit_secs);
+               error = GRBsetdblparam(grb->modelenv, GRB_DBL_PAR_TIMELIMIT, lpp->time_limit_secs);
                check_gurobi_error(grb, error);
        }
 
-       /*
-        * If we have enough time, we instruct cplex to imply some
-        * of its higher order magic to pursue the best solution
-        */
-       if(lpp->emphasis) {
-               /* not implemented */
-       }
-
-       /*
-        * If a bound of the objective function is supplied,
-        * set it accordingly, dependign on minimization or maximization.
-        */
-       if(lpp->set_bound) {
-               //panic("bound not implemented yet");
-               fprintf(stderr, "Warning: gurobi bound not implemented yet\n");
-       }
-
        /* solve */
-       gettimeofday(&tvb, NULL);
        error = GRBoptimize(grb->model);
        check_gurobi_error(grb, error);
-       gettimeofday(&tva, NULL);
 
        /* get solution status */
        error = GRBgetintattr(grb->model, GRB_INT_ATTR_STATUS, &optimstatus);
@@ -225,27 +201,34 @@ static void gurobi_solve(gurobi_t *grb)
        default:                    lpp->sol_state = lpp_feasible; break;
        }
 
-       /* get variable solution values */
-       values = alloca(numcols * sizeof(*values));
-       error = GRBgetdblattrarray(grb->model, GRB_DBL_ATTR_X, 0, numcols, values);
-       check_gurobi_error(grb, error);
-       for(i=0; i<numcols; ++i) {
-               lpp->vars[1+i]->value      = values[i];
-               lpp->vars[1+i]->value_kind = lpp_value_solution;
-       }
+       if (lpp->sol_state >= lpp_feasible) {
+               /* get variable solution values */
+               values = alloca(numcols * sizeof(*values));
+               error = GRBgetdblattrarray(grb->model, GRB_DBL_ATTR_X, 0, numcols,
+                                          values);
+               check_gurobi_error(grb, error);
+               for(i=0; i<numcols; ++i) {
+                       lpp->vars[1+i]->value      = values[i];
+                       lpp->vars[1+i]->value_kind = lpp_value_solution;
+               }
 
-       /* Get the value of the objective function. */
-       error = GRBgetdblattr(grb->model, GRB_DBL_ATTR_OBJVAL, &lpp->objval);
-       check_gurobi_error(grb, error);
-       error = GRBgetdblattr(grb->model , GRB_DBL_ATTR_OBJBOUND, &lpp->best_bound);
-       check_gurobi_error(grb, error);
+               /* Get the value of the objective function. */
+               error = GRBgetdblattr(grb->model, GRB_DBL_ATTR_OBJVAL, &lpp->objval);
+               check_gurobi_error(grb, error);
+               error = GRBgetdblattr(grb->model , GRB_DBL_ATTR_OBJBOUND,
+                                     &lpp->best_bound);
+               if (error != 0) {
+                       lpp->best_bound = FP_NAN;
+               }
+       }
 
        /* get some statistics */
-       my_timersub(&tva, &tvb, &tvdiff);
-       lpp->sol_time = tvdiff.tv_sec + tvdiff.tv_usec / 1e6;
        error = GRBgetdblattr(grb->model, GRB_DBL_ATTR_ITERCOUNT, &iterations);
        check_gurobi_error(grb, error);
        lpp->iterations = (unsigned) iterations;
+
+       error = GRBgetdblattr(grb->model, GRB_DBL_ATTR_RUNTIME, &lpp->sol_time);
+       check_gurobi_error(grb, error);
 }
 
 void lpp_solve_gurobi(lpp_t *lpp)