aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjoern Brandenburg <bbb@mpi-sws.org>2012-08-07 14:19:14 -0400
committerBjoern Brandenburg <bbb@mpi-sws.org>2013-02-12 06:49:39 -0500
commita4ff45bfbaef292ee1106b759c7ae80213b03cd4 (patch)
treea13c4046ce6be77257bdd028fbc2896a6af161e3
parent673f367fc5835ebce3357dfebee9c0e414e5c09b (diff)
Add CPLEX integration
This patch introduces a concrete subclass of Solution that implements the actual solving of linear programs by means of invoking the CPLEX Concert Technology API. The project can still be compiled on systems that do not have CPLEX installed.
-rw-r--r--native/Makefile30
-rw-r--r--native/include/linprog/cplex.h8
-rw-r--r--native/src/linprog/cplex.cpp168
3 files changed, 203 insertions, 3 deletions
diff --git a/native/Makefile b/native/Makefile
index aa8f75c..71a6835 100644
--- a/native/Makefile
+++ b/native/Makefile
@@ -45,6 +45,24 @@ ifeq ($(OS),Linux)
45LIBS += -lrt 45LIBS += -lrt
46endif 46endif
47 47
48# #### CPLEX Support ####
49
50# See if we can find a CPLEX installation.
51CPLEX := ${realpath ${shell which cplex}}
52ifneq ($(CPLEX),)
53# Yes, we seem to have something that looks like cplex.
54
55# The CPLEX variable now contains the canonicalized path to the cplex
56# binary. From this, we can extract the include and library paths.
57CPLEX_DIR := ${realpath ${dir $(CPLEX)}/../..}
58
59${info Found CPLEX installation in $(CPLEX_DIR).}
60
61# Add headers, libraries, and definitions.
62INCLUDES += -I$(CPLEX_DIR)/include/
63LIBS += -lilocplex -lcplex -lconcert
64DEFS += -DCONFIG_HAVE_CPLEX
65endif
48 66
49# #### Debug support #### 67# #### Debug support ####
50ifeq ($(DEBUG),y) 68ifeq ($(DEBUG),y)
@@ -61,8 +79,9 @@ endif
61CXXFLAGS = -Wall -Wextra -Werror $(DISABLED_WARNINGS) -fPIC $(INCLUDES) $(DEFS) 79CXXFLAGS = -Wall -Wextra -Werror $(DISABLED_WARNINGS) -fPIC $(INCLUDES) $(DEFS)
62LDFLAGS = $(LIBS) 80LDFLAGS = $(LIBS)
63SWIGFLAGS = -python -c++ -outdir . -includeall -Iinclude 81SWIGFLAGS = -python -c++ -outdir . -includeall -Iinclude
82
64vpath %.cc interface 83vpath %.cc interface
65vpath %.cpp src src/edf src/blocking 84vpath %.cpp src src/edf src/blocking src/linprog
66 85
67# #### Common C++ source files #### 86# #### Common C++ source files ####
68 87
@@ -79,6 +98,11 @@ SYNC_OBJ += rw-phase-fair.o rw-task-fair.o
79 98
80ALL = testmain _sched.so _locking.so _sim.so 99ALL = testmain _sched.so _locking.so _sim.so
81 100
101# Compile LP-based code only if we have a solver.
102ifneq ($(CPLEX),)
103LP_OBJ = cplex.o io.o
104endif
105
82.PHONY: all clean 106.PHONY: all clean
83 107
84all: ${ALL} 108all: ${ALL}
@@ -87,8 +111,8 @@ clean:
87 rm -f interface/*.cc interface/*.o *.py 111 rm -f interface/*.cc interface/*.o *.py
88 rm -f *.o ${ALL} 112 rm -f *.o ${ALL}
89 113
90testmain: testmain.o ${CORE_OBJ} ${SYNC_OBJ} ${EDF_OBJ} ${SCHED_OBJ} 114testmain: testmain.o ${CORE_OBJ} ${SYNC_OBJ} ${EDF_OBJ} ${SCHED_OBJ} ${LP_OBJ}
91 $(CXX) -o $@ $+ $(LDFLAGS) 115 $(CXX) -o $@ $+ $(LDFLAGS)
92 116
93# #### Python libraries #### 117# #### Python libraries ####
94 118
diff --git a/native/include/linprog/cplex.h b/native/include/linprog/cplex.h
new file mode 100644
index 0000000..c68bd24
--- /dev/null
+++ b/native/include/linprog/cplex.h
@@ -0,0 +1,8 @@
1#ifndef LINPROG_CPLEX_H
2#define LINPROG_CPLEX_H
3
4#include "linprog/solver.h"
5
6Solution *cplex_solve(const LinearProgram& lp, unsigned int max_num_vars);
7
8#endif
diff --git a/native/src/linprog/cplex.cpp b/native/src/linprog/cplex.cpp
new file mode 100644
index 0000000..b5565d4
--- /dev/null
+++ b/native/src/linprog/cplex.cpp
@@ -0,0 +1,168 @@
1#define IL_STD // required by CPLEX when using STL classes.
2
3#include <ilcplex/ilocplex.h>
4
5#include "cpu_time.h"
6
7#include "linprog/cplex.h"
8
9class CPLEXSolution : public Solution
10{
11private:
12 IloEnv ilo_env;
13 IloEnv& get_env()
14 {
15 return ilo_env;
16 }
17
18 IloNumArray cplex_values;
19
20 const LinearProgram &linprog;
21
22 bool solved;
23
24 void solve_model(unsigned int max_num_vars,
25 double var_lb, double var_ub);
26
27 IloObjective make_objective(const IloNumVarArray& vars);
28 IloRangeArray make_constraints(const IloNumVarArray& vars);
29
30 IloRange make_constraint(const IloNumVarArray &vars,
31 const LinearExpression *exp, double bound,
32 bool is_exact_bound);
33
34public:
35 CPLEXSolution(const LinearProgram &lp, unsigned int max_num_vars,
36 double var_lb = 0.0, double var_ub = 1.0);
37 ~CPLEXSolution();
38
39 double get_value(unsigned int var) const
40 {
41 return cplex_values[var];
42 }
43
44 bool is_solved() const
45 {
46 return solved;
47 }
48};
49
50CPLEXSolution::CPLEXSolution(const LinearProgram& lp, unsigned int max_num_vars,
51 double var_lb, double var_ub)
52 : ilo_env(),
53 cplex_values(get_env(), max_num_vars),
54 linprog(lp),
55 solved(false)
56{
57 get_env().setNormalizer(IloFalse);
58 get_env().setOut(get_env().getNullStream());
59
60 if (max_num_vars > 0)
61 solve_model(max_num_vars, var_lb, var_ub);
62 else
63 // Trivial case: no variables.
64 solved = true;
65}
66
67
68void CPLEXSolution::solve_model(unsigned int max_num_vars,
69 double var_lb, double var_ub)
70{
71 try
72 {
73 IloNumVarArray cplex_vars = IloNumVarArray(get_env(), max_num_vars,
74 var_lb, var_ub);
75
76 IloObjective objective = make_objective(cplex_vars);
77 IloRangeArray constraints = make_constraints(cplex_vars);
78
79 IloModel model = IloModel(get_env());
80
81 model.add(objective);
82 model.add(constraints);
83
84
85 IloCplex cplex = IloCplex(model);
86
87 cplex.solve();
88
89 cplex.getValues(cplex_vars, cplex_values);
90 solved = true;
91
92 } catch (IloException &ex)
93 {
94 // Improve me: we should export some kind of error info.
95 std::cerr << "CPLEX failed: " << ex << std::endl;
96 solved = false;
97 }
98}
99
100IloObjective CPLEXSolution::make_objective(const IloNumVarArray &vars)
101{
102 const LinearExpression *obj = linprog.get_objective();
103
104 IloObjective goal = IloObjective(get_env(), 0, IloObjective::Maximize);
105 IloNumArray coeffs = IloNumArray(get_env(), vars.getSize());
106
107 assert((int) obj->get_terms().size() <= coeffs.getSize());
108
109 coeffs.add(vars.getSize(), 0);
110
111 // Set coefficient for each variable in the objective function.
112 foreach(obj->get_terms(), term)
113 {
114 double coefficient = term->first;
115 unsigned int var_idx = term->second;
116 coeffs[var_idx] = coefficient;
117 }
118
119 goal.setLinearCoefs(vars, coeffs);
120
121 return goal;
122}
123
124IloRangeArray CPLEXSolution::make_constraints(const IloNumVarArray &vars)
125{
126 IloRangeArray constraints(get_env());
127
128 foreach (linprog.get_equalities(), exp)
129 constraints.add(make_constraint(vars, exp->first, exp->second, true));
130
131 foreach (linprog.get_inequalities(), exp)
132 constraints.add(make_constraint(vars, exp->first, exp->second, false));
133
134 return constraints;
135}
136
137IloRange CPLEXSolution::make_constraint(const IloNumVarArray &vars,
138 const LinearExpression *exp, double bound,
139 bool is_exact_bound)
140{
141 IloRange r = IloRange(get_env(), -IloInfinity, bound);
142
143 if (is_exact_bound)
144 r.setLB(bound);
145
146 foreach (exp->get_terms(), term)
147 r.setLinearCoef(vars[term->second], term->first);
148
149 return r;
150}
151
152CPLEXSolution::~CPLEXSolution()
153{
154 get_env().end();
155}
156
157
158Solution *cplex_solve(const LinearProgram& lp, unsigned int max_num_vars)
159{
160 CPLEXSolution *sol = new CPLEXSolution(lp, max_num_vars);
161 if (sol->is_solved())
162 return sol;
163 else
164 {
165 delete sol;
166 return NULL;
167 }
168}