hashptr.h: use inline functions instead of #define
[libfirm] / ir / lpp / lpp_gurobi.c
index ce20157..a87e6e1 100644 (file)
@@ -1,16 +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
+#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;
 
@@ -51,16 +60,33 @@ static gurobi_t *new_gurobi(lpp_t *lpp)
 
        gurobi_t *grb = XMALLOCZ(gurobi_t);
        grb->lpp = lpp;
-       error = GRBloadenv(&grb->env, NULL);
+       /* /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 0
        error = GRBsetlogfile(grb->env, lpp->log);
        check_gurobi_error(grb, error);
+#else
+       if (lpp->log != stdout && lpp->log != stderr) {
+               error = GRBsetintparam(grb->env, GRB_INT_PAR_OUTPUTFLAG, 0);
+               check_gurobi_error(grb, error);
+       }
+#endif
 
        return grb;
 }
 
 static void free_gurobi(gurobi_t *grb)
 {
+       GRBfreemodel(grb->model);
        GRBfreeenv(grb->env);
        free(grb);
 }
@@ -150,9 +176,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)
@@ -165,39 +192,21 @@ static void gurobi_solve(gurobi_t *grb)
        double *values;
        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);
-
        /* 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 0
        /*
         * 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");
        }
+#endif
 
        /* solve */
        error = GRBoptimize(grb->model);
@@ -216,20 +225,26 @@ 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 */
        error = GRBgetdblattr(grb->model, GRB_DBL_ATTR_ITERCOUNT, &iterations);