diff options
author | Bjoern Brandenburg <bbb@mpi-sws.org> | 2012-08-07 14:19:14 -0400 |
---|---|---|
committer | Bjoern Brandenburg <bbb@mpi-sws.org> | 2013-02-12 06:49:39 -0500 |
commit | a4ff45bfbaef292ee1106b759c7ae80213b03cd4 (patch) | |
tree | a13c4046ce6be77257bdd028fbc2896a6af161e3 | |
parent | 673f367fc5835ebce3357dfebee9c0e414e5c09b (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/Makefile | 30 | ||||
-rw-r--r-- | native/include/linprog/cplex.h | 8 | ||||
-rw-r--r-- | native/src/linprog/cplex.cpp | 168 |
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) | |||
45 | LIBS += -lrt | 45 | LIBS += -lrt |
46 | endif | 46 | endif |
47 | 47 | ||
48 | # #### CPLEX Support #### | ||
49 | |||
50 | # See if we can find a CPLEX installation. | ||
51 | CPLEX := ${realpath ${shell which cplex}} | ||
52 | ifneq ($(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. | ||
57 | CPLEX_DIR := ${realpath ${dir $(CPLEX)}/../..} | ||
58 | |||
59 | ${info Found CPLEX installation in $(CPLEX_DIR).} | ||
60 | |||
61 | # Add headers, libraries, and definitions. | ||
62 | INCLUDES += -I$(CPLEX_DIR)/include/ | ||
63 | LIBS += -lilocplex -lcplex -lconcert | ||
64 | DEFS += -DCONFIG_HAVE_CPLEX | ||
65 | endif | ||
48 | 66 | ||
49 | # #### Debug support #### | 67 | # #### Debug support #### |
50 | ifeq ($(DEBUG),y) | 68 | ifeq ($(DEBUG),y) |
@@ -61,8 +79,9 @@ endif | |||
61 | CXXFLAGS = -Wall -Wextra -Werror $(DISABLED_WARNINGS) -fPIC $(INCLUDES) $(DEFS) | 79 | CXXFLAGS = -Wall -Wextra -Werror $(DISABLED_WARNINGS) -fPIC $(INCLUDES) $(DEFS) |
62 | LDFLAGS = $(LIBS) | 80 | LDFLAGS = $(LIBS) |
63 | SWIGFLAGS = -python -c++ -outdir . -includeall -Iinclude | 81 | SWIGFLAGS = -python -c++ -outdir . -includeall -Iinclude |
82 | |||
64 | vpath %.cc interface | 83 | vpath %.cc interface |
65 | vpath %.cpp src src/edf src/blocking | 84 | vpath %.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 | ||
80 | ALL = testmain _sched.so _locking.so _sim.so | 99 | ALL = testmain _sched.so _locking.so _sim.so |
81 | 100 | ||
101 | # Compile LP-based code only if we have a solver. | ||
102 | ifneq ($(CPLEX),) | ||
103 | LP_OBJ = cplex.o io.o | ||
104 | endif | ||
105 | |||
82 | .PHONY: all clean | 106 | .PHONY: all clean |
83 | 107 | ||
84 | all: ${ALL} | 108 | all: ${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 | ||
90 | testmain: testmain.o ${CORE_OBJ} ${SYNC_OBJ} ${EDF_OBJ} ${SCHED_OBJ} | 114 | testmain: 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 | |||
6 | Solution *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 | |||
9 | class CPLEXSolution : public Solution | ||
10 | { | ||
11 | private: | ||
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 | |||
34 | public: | ||
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 | |||
50 | CPLEXSolution::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 | |||
68 | void 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 | |||
100 | IloObjective 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 | |||
124 | IloRangeArray 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 | |||
137 | IloRange 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 | |||
152 | CPLEXSolution::~CPLEXSolution() | ||
153 | { | ||
154 | get_env().end(); | ||
155 | } | ||
156 | |||
157 | |||
158 | Solution *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 | } | ||