lemongraph 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.yardopts +8 -0
- data/LICENSE +674 -0
- data/README.md +6 -0
- data/ext/lemon-1.3.1/AUTHORS +26 -0
- data/ext/lemon-1.3.1/CMakeLists.txt +371 -0
- data/ext/lemon-1.3.1/INSTALL +167 -0
- data/ext/lemon-1.3.1/LICENSE +32 -0
- data/ext/lemon-1.3.1/NEWS +337 -0
- data/ext/lemon-1.3.1/README +50 -0
- data/ext/lemon-1.3.1/cmake/FindCOIN.cmake +110 -0
- data/ext/lemon-1.3.1/cmake/FindGLPK.cmake +55 -0
- data/ext/lemon-1.3.1/cmake/FindGhostscript.cmake +10 -0
- data/ext/lemon-1.3.1/cmake/FindILOG.cmake +102 -0
- data/ext/lemon-1.3.1/cmake/FindSOPLEX.cmake +23 -0
- data/ext/lemon-1.3.1/cmake/LEMONConfig.cmake.in +13 -0
- data/ext/lemon-1.3.1/cmake/nsis/lemon.ico +0 -0
- data/ext/lemon-1.3.1/cmake/nsis/uninstall.ico +0 -0
- data/ext/lemon-1.3.1/cmake/version.cmake +1 -0
- data/ext/lemon-1.3.1/cmake/version.cmake.in +1 -0
- data/ext/lemon-1.3.1/contrib/CMakeLists.txt +19 -0
- data/ext/lemon-1.3.1/lemon/CMakeLists.txt +91 -0
- data/ext/lemon-1.3.1/lemon/adaptors.h +3638 -0
- data/ext/lemon-1.3.1/lemon/arg_parser.cc +474 -0
- data/ext/lemon-1.3.1/lemon/arg_parser.h +440 -0
- data/ext/lemon-1.3.1/lemon/assert.h +214 -0
- data/ext/lemon-1.3.1/lemon/base.cc +37 -0
- data/ext/lemon-1.3.1/lemon/bellman_ford.h +1116 -0
- data/ext/lemon-1.3.1/lemon/bfs.h +1754 -0
- data/ext/lemon-1.3.1/lemon/bin_heap.h +347 -0
- data/ext/lemon-1.3.1/lemon/binomial_heap.h +445 -0
- data/ext/lemon-1.3.1/lemon/bits/alteration_notifier.h +472 -0
- data/ext/lemon-1.3.1/lemon/bits/array_map.h +351 -0
- data/ext/lemon-1.3.1/lemon/bits/bezier.h +174 -0
- data/ext/lemon-1.3.1/lemon/bits/default_map.h +182 -0
- data/ext/lemon-1.3.1/lemon/bits/edge_set_extender.h +627 -0
- data/ext/lemon-1.3.1/lemon/bits/enable_if.h +131 -0
- data/ext/lemon-1.3.1/lemon/bits/graph_adaptor_extender.h +401 -0
- data/ext/lemon-1.3.1/lemon/bits/graph_extender.h +1332 -0
- data/ext/lemon-1.3.1/lemon/bits/lock.h +65 -0
- data/ext/lemon-1.3.1/lemon/bits/map_extender.h +332 -0
- data/ext/lemon-1.3.1/lemon/bits/path_dump.h +177 -0
- data/ext/lemon-1.3.1/lemon/bits/solver_bits.h +194 -0
- data/ext/lemon-1.3.1/lemon/bits/traits.h +388 -0
- data/ext/lemon-1.3.1/lemon/bits/variant.h +494 -0
- data/ext/lemon-1.3.1/lemon/bits/vector_map.h +244 -0
- data/ext/lemon-1.3.1/lemon/bits/windows.cc +166 -0
- data/ext/lemon-1.3.1/lemon/bits/windows.h +44 -0
- data/ext/lemon-1.3.1/lemon/bucket_heap.h +594 -0
- data/ext/lemon-1.3.1/lemon/capacity_scaling.h +1014 -0
- data/ext/lemon-1.3.1/lemon/cbc.cc +460 -0
- data/ext/lemon-1.3.1/lemon/cbc.h +129 -0
- data/ext/lemon-1.3.1/lemon/christofides_tsp.h +254 -0
- data/ext/lemon-1.3.1/lemon/circulation.h +807 -0
- data/ext/lemon-1.3.1/lemon/clp.cc +464 -0
- data/ext/lemon-1.3.1/lemon/clp.h +164 -0
- data/ext/lemon-1.3.1/lemon/color.cc +44 -0
- data/ext/lemon-1.3.1/lemon/color.h +204 -0
- data/ext/lemon-1.3.1/lemon/concept_check.h +77 -0
- data/ext/lemon-1.3.1/lemon/concepts/bpgraph.h +1029 -0
- data/ext/lemon-1.3.1/lemon/concepts/digraph.h +491 -0
- data/ext/lemon-1.3.1/lemon/concepts/graph.h +788 -0
- data/ext/lemon-1.3.1/lemon/concepts/graph_components.h +2134 -0
- data/ext/lemon-1.3.1/lemon/concepts/heap.h +324 -0
- data/ext/lemon-1.3.1/lemon/concepts/maps.h +223 -0
- data/ext/lemon-1.3.1/lemon/concepts/path.h +312 -0
- data/ext/lemon-1.3.1/lemon/config.h.in +22 -0
- data/ext/lemon-1.3.1/lemon/connectivity.h +1688 -0
- data/ext/lemon-1.3.1/lemon/core.h +2506 -0
- data/ext/lemon-1.3.1/lemon/cost_scaling.h +1607 -0
- data/ext/lemon-1.3.1/lemon/counter.h +249 -0
- data/ext/lemon-1.3.1/lemon/cplex.cc +994 -0
- data/ext/lemon-1.3.1/lemon/cplex.h +292 -0
- data/ext/lemon-1.3.1/lemon/cycle_canceling.h +1230 -0
- data/ext/lemon-1.3.1/lemon/dfs.h +1637 -0
- data/ext/lemon-1.3.1/lemon/dheap.h +352 -0
- data/ext/lemon-1.3.1/lemon/dijkstra.h +1303 -0
- data/ext/lemon-1.3.1/lemon/dim2.h +726 -0
- data/ext/lemon-1.3.1/lemon/dimacs.h +448 -0
- data/ext/lemon-1.3.1/lemon/edge_set.h +1420 -0
- data/ext/lemon-1.3.1/lemon/edmonds_karp.h +556 -0
- data/ext/lemon-1.3.1/lemon/elevator.h +982 -0
- data/ext/lemon-1.3.1/lemon/error.h +276 -0
- data/ext/lemon-1.3.1/lemon/euler.h +287 -0
- data/ext/lemon-1.3.1/lemon/fib_heap.h +475 -0
- data/ext/lemon-1.3.1/lemon/fractional_matching.h +2139 -0
- data/ext/lemon-1.3.1/lemon/full_graph.h +1082 -0
- data/ext/lemon-1.3.1/lemon/glpk.cc +1012 -0
- data/ext/lemon-1.3.1/lemon/glpk.h +263 -0
- data/ext/lemon-1.3.1/lemon/gomory_hu.h +568 -0
- data/ext/lemon-1.3.1/lemon/graph_to_eps.h +1186 -0
- data/ext/lemon-1.3.1/lemon/greedy_tsp.h +251 -0
- data/ext/lemon-1.3.1/lemon/grid_graph.h +699 -0
- data/ext/lemon-1.3.1/lemon/grosso_locatelli_pullan_mc.h +840 -0
- data/ext/lemon-1.3.1/lemon/hao_orlin.h +1015 -0
- data/ext/lemon-1.3.1/lemon/hartmann_orlin_mmc.h +654 -0
- data/ext/lemon-1.3.1/lemon/howard_mmc.h +651 -0
- data/ext/lemon-1.3.1/lemon/hypercube_graph.h +459 -0
- data/ext/lemon-1.3.1/lemon/insertion_tsp.h +533 -0
- data/ext/lemon-1.3.1/lemon/karp_mmc.h +590 -0
- data/ext/lemon-1.3.1/lemon/kruskal.h +324 -0
- data/ext/lemon-1.3.1/lemon/lemon.pc.in +10 -0
- data/ext/lemon-1.3.1/lemon/lgf_reader.h +3854 -0
- data/ext/lemon-1.3.1/lemon/lgf_writer.h +2687 -0
- data/ext/lemon-1.3.1/lemon/list_graph.h +2510 -0
- data/ext/lemon-1.3.1/lemon/lp.h +95 -0
- data/ext/lemon-1.3.1/lemon/lp_base.cc +30 -0
- data/ext/lemon-1.3.1/lemon/lp_base.h +2147 -0
- data/ext/lemon-1.3.1/lemon/lp_skeleton.cc +143 -0
- data/ext/lemon-1.3.1/lemon/lp_skeleton.h +234 -0
- data/ext/lemon-1.3.1/lemon/maps.h +4057 -0
- data/ext/lemon-1.3.1/lemon/matching.h +3505 -0
- data/ext/lemon-1.3.1/lemon/math.h +77 -0
- data/ext/lemon-1.3.1/lemon/max_cardinality_search.h +794 -0
- data/ext/lemon-1.3.1/lemon/min_cost_arborescence.h +808 -0
- data/ext/lemon-1.3.1/lemon/nagamochi_ibaraki.h +702 -0
- data/ext/lemon-1.3.1/lemon/nauty_reader.h +113 -0
- data/ext/lemon-1.3.1/lemon/nearest_neighbor_tsp.h +238 -0
- data/ext/lemon-1.3.1/lemon/network_simplex.h +1659 -0
- data/ext/lemon-1.3.1/lemon/opt2_tsp.h +367 -0
- data/ext/lemon-1.3.1/lemon/pairing_heap.h +474 -0
- data/ext/lemon-1.3.1/lemon/path.h +1164 -0
- data/ext/lemon-1.3.1/lemon/planarity.h +2754 -0
- data/ext/lemon-1.3.1/lemon/preflow.h +985 -0
- data/ext/lemon-1.3.1/lemon/quad_heap.h +343 -0
- data/ext/lemon-1.3.1/lemon/radix_heap.h +438 -0
- data/ext/lemon-1.3.1/lemon/radix_sort.h +487 -0
- data/ext/lemon-1.3.1/lemon/random.cc +29 -0
- data/ext/lemon-1.3.1/lemon/random.h +1005 -0
- data/ext/lemon-1.3.1/lemon/smart_graph.h +1344 -0
- data/ext/lemon-1.3.1/lemon/soplex.cc +465 -0
- data/ext/lemon-1.3.1/lemon/soplex.h +158 -0
- data/ext/lemon-1.3.1/lemon/static_graph.h +476 -0
- data/ext/lemon-1.3.1/lemon/suurballe.h +776 -0
- data/ext/lemon-1.3.1/lemon/time_measure.h +610 -0
- data/ext/lemon-1.3.1/lemon/tolerance.h +242 -0
- data/ext/lemon-1.3.1/lemon/unionfind.h +1824 -0
- data/ext/lemon-1.3.1/scripts/unify-sources.sh +390 -0
- data/ext/lemon-1.3.1/scripts/valgrind-wrapper.sh +22 -0
- data/ext/lemongraph/arc_map.cc +1007 -0
- data/ext/lemongraph/digraph.cc +282 -0
- data/ext/lemongraph/digraph_arc.cc +153 -0
- data/ext/lemongraph/digraph_node.cc +277 -0
- data/ext/lemongraph/edge_map.cc +770 -0
- data/ext/lemongraph/extconf.rb +53 -0
- data/ext/lemongraph/graph.cc +351 -0
- data/ext/lemongraph/graph_arc.cc +95 -0
- data/ext/lemongraph/graph_edge.cc +153 -0
- data/ext/lemongraph/graph_item.cc +76 -0
- data/ext/lemongraph/graph_node.cc +321 -0
- data/ext/lemongraph/lemongraph.cc +260 -0
- data/ext/lemongraph/lemongraph.hh +295 -0
- data/ext/lemongraph/lemongraph.map +6 -0
- data/ext/lemongraph/lemongraph_export.hh +31 -0
- data/ext/lemongraph/node_map.cc +1011 -0
- data/lemongraph.gemspec +176 -0
- data/lib/lemongraph/graphviz.rb +240 -0
- data/lib/lemongraph/version.rb +4 -0
- data/lib/lemongraph.rb +21 -0
- data/samples/lemondeps.rb +38 -0
- metadata +202 -0
|
@@ -0,0 +1,994 @@
|
|
|
1
|
+
/* -*- mode: C++; indent-tabs-mode: nil; -*-
|
|
2
|
+
*
|
|
3
|
+
* This file is a part of LEMON, a generic C++ optimization library.
|
|
4
|
+
*
|
|
5
|
+
* Copyright (C) 2003-2013
|
|
6
|
+
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
|
|
7
|
+
* (Egervary Research Group on Combinatorial Optimization, EGRES).
|
|
8
|
+
*
|
|
9
|
+
* Permission to use, modify and distribute this software is granted
|
|
10
|
+
* provided that this copyright notice appears in all copies. For
|
|
11
|
+
* precise terms see the accompanying LICENSE file.
|
|
12
|
+
*
|
|
13
|
+
* This software is provided "AS IS" with no warranty of any kind,
|
|
14
|
+
* express or implied, and with no claim as to its suitability for any
|
|
15
|
+
* purpose.
|
|
16
|
+
*
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
#include <iostream>
|
|
20
|
+
#include <vector>
|
|
21
|
+
#include <cstring>
|
|
22
|
+
|
|
23
|
+
#include <lemon/cplex.h>
|
|
24
|
+
|
|
25
|
+
extern "C" {
|
|
26
|
+
#include <ilcplex/cplex.h>
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
///\file
|
|
31
|
+
///\brief Implementation of the LEMON-CPLEX lp solver interface.
|
|
32
|
+
namespace lemon {
|
|
33
|
+
|
|
34
|
+
CplexEnv::LicenseError::LicenseError(int status) {
|
|
35
|
+
if (!CPXgeterrorstring(0, status, _message)) {
|
|
36
|
+
std::strcpy(_message, "Cplex unknown error");
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
CplexEnv::CplexEnv() {
|
|
41
|
+
int status;
|
|
42
|
+
_cnt = new int;
|
|
43
|
+
(*_cnt) = 1;
|
|
44
|
+
_env = CPXopenCPLEX(&status);
|
|
45
|
+
if (_env == 0) {
|
|
46
|
+
delete _cnt;
|
|
47
|
+
_cnt = 0;
|
|
48
|
+
throw LicenseError(status);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
CplexEnv::CplexEnv(const CplexEnv& other) {
|
|
53
|
+
_env = other._env;
|
|
54
|
+
_cnt = other._cnt;
|
|
55
|
+
++(*_cnt);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
CplexEnv& CplexEnv::operator=(const CplexEnv& other) {
|
|
59
|
+
_env = other._env;
|
|
60
|
+
_cnt = other._cnt;
|
|
61
|
+
++(*_cnt);
|
|
62
|
+
return *this;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
CplexEnv::~CplexEnv() {
|
|
66
|
+
--(*_cnt);
|
|
67
|
+
if (*_cnt == 0) {
|
|
68
|
+
delete _cnt;
|
|
69
|
+
CPXcloseCPLEX(&_env);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
CplexBase::CplexBase() : LpBase() {
|
|
74
|
+
int status;
|
|
75
|
+
_prob = CPXcreateprob(cplexEnv(), &status, "Cplex problem");
|
|
76
|
+
messageLevel(MESSAGE_NOTHING);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
CplexBase::CplexBase(const CplexEnv& env)
|
|
80
|
+
: LpBase(), _env(env) {
|
|
81
|
+
int status;
|
|
82
|
+
_prob = CPXcreateprob(cplexEnv(), &status, "Cplex problem");
|
|
83
|
+
messageLevel(MESSAGE_NOTHING);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
CplexBase::CplexBase(const CplexBase& cplex)
|
|
87
|
+
: LpBase() {
|
|
88
|
+
int status;
|
|
89
|
+
_prob = CPXcloneprob(cplexEnv(), cplex._prob, &status);
|
|
90
|
+
rows = cplex.rows;
|
|
91
|
+
cols = cplex.cols;
|
|
92
|
+
messageLevel(MESSAGE_NOTHING);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
CplexBase::~CplexBase() {
|
|
96
|
+
CPXfreeprob(cplexEnv(),&_prob);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
int CplexBase::_addCol() {
|
|
100
|
+
int i = CPXgetnumcols(cplexEnv(), _prob);
|
|
101
|
+
double lb = -INF, ub = INF;
|
|
102
|
+
CPXnewcols(cplexEnv(), _prob, 1, 0, &lb, &ub, 0, 0);
|
|
103
|
+
return i;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
int CplexBase::_addRow() {
|
|
108
|
+
int i = CPXgetnumrows(cplexEnv(), _prob);
|
|
109
|
+
const double ub = INF;
|
|
110
|
+
const char s = 'L';
|
|
111
|
+
CPXnewrows(cplexEnv(), _prob, 1, &ub, &s, 0, 0);
|
|
112
|
+
return i;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
int CplexBase::_addRow(Value lb, ExprIterator b,
|
|
116
|
+
ExprIterator e, Value ub) {
|
|
117
|
+
int i = CPXgetnumrows(cplexEnv(), _prob);
|
|
118
|
+
if (lb == -INF) {
|
|
119
|
+
const char s = 'L';
|
|
120
|
+
CPXnewrows(cplexEnv(), _prob, 1, &ub, &s, 0, 0);
|
|
121
|
+
} else if (ub == INF) {
|
|
122
|
+
const char s = 'G';
|
|
123
|
+
CPXnewrows(cplexEnv(), _prob, 1, &lb, &s, 0, 0);
|
|
124
|
+
} else if (lb == ub){
|
|
125
|
+
const char s = 'E';
|
|
126
|
+
CPXnewrows(cplexEnv(), _prob, 1, &lb, &s, 0, 0);
|
|
127
|
+
} else {
|
|
128
|
+
const char s = 'R';
|
|
129
|
+
double len = ub - lb;
|
|
130
|
+
CPXnewrows(cplexEnv(), _prob, 1, &lb, &s, &len, 0);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
std::vector<int> indices;
|
|
134
|
+
std::vector<int> rowlist;
|
|
135
|
+
std::vector<Value> values;
|
|
136
|
+
|
|
137
|
+
for(ExprIterator it=b; it!=e; ++it) {
|
|
138
|
+
indices.push_back(it->first);
|
|
139
|
+
values.push_back(it->second);
|
|
140
|
+
rowlist.push_back(i);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
CPXchgcoeflist(cplexEnv(), _prob, values.size(),
|
|
144
|
+
&rowlist.front(), &indices.front(), &values.front());
|
|
145
|
+
|
|
146
|
+
return i;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
void CplexBase::_eraseCol(int i) {
|
|
150
|
+
CPXdelcols(cplexEnv(), _prob, i, i);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
void CplexBase::_eraseRow(int i) {
|
|
154
|
+
CPXdelrows(cplexEnv(), _prob, i, i);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
void CplexBase::_eraseColId(int i) {
|
|
158
|
+
cols.eraseIndex(i);
|
|
159
|
+
cols.shiftIndices(i);
|
|
160
|
+
}
|
|
161
|
+
void CplexBase::_eraseRowId(int i) {
|
|
162
|
+
rows.eraseIndex(i);
|
|
163
|
+
rows.shiftIndices(i);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
void CplexBase::_getColName(int col, std::string &name) const {
|
|
167
|
+
int size;
|
|
168
|
+
CPXgetcolname(cplexEnv(), _prob, 0, 0, 0, &size, col, col);
|
|
169
|
+
if (size == 0) {
|
|
170
|
+
name.clear();
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
size *= -1;
|
|
175
|
+
std::vector<char> buf(size);
|
|
176
|
+
char *cname;
|
|
177
|
+
int tmp;
|
|
178
|
+
CPXgetcolname(cplexEnv(), _prob, &cname, &buf.front(), size,
|
|
179
|
+
&tmp, col, col);
|
|
180
|
+
name = cname;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
void CplexBase::_setColName(int col, const std::string &name) {
|
|
184
|
+
char *cname;
|
|
185
|
+
cname = const_cast<char*>(name.c_str());
|
|
186
|
+
CPXchgcolname(cplexEnv(), _prob, 1, &col, &cname);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
int CplexBase::_colByName(const std::string& name) const {
|
|
190
|
+
int index;
|
|
191
|
+
if (CPXgetcolindex(cplexEnv(), _prob,
|
|
192
|
+
const_cast<char*>(name.c_str()), &index) == 0) {
|
|
193
|
+
return index;
|
|
194
|
+
}
|
|
195
|
+
return -1;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
void CplexBase::_getRowName(int row, std::string &name) const {
|
|
199
|
+
int size;
|
|
200
|
+
CPXgetrowname(cplexEnv(), _prob, 0, 0, 0, &size, row, row);
|
|
201
|
+
if (size == 0) {
|
|
202
|
+
name.clear();
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
size *= -1;
|
|
207
|
+
std::vector<char> buf(size);
|
|
208
|
+
char *cname;
|
|
209
|
+
int tmp;
|
|
210
|
+
CPXgetrowname(cplexEnv(), _prob, &cname, &buf.front(), size,
|
|
211
|
+
&tmp, row, row);
|
|
212
|
+
name = cname;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
void CplexBase::_setRowName(int row, const std::string &name) {
|
|
216
|
+
char *cname;
|
|
217
|
+
cname = const_cast<char*>(name.c_str());
|
|
218
|
+
CPXchgrowname(cplexEnv(), _prob, 1, &row, &cname);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
int CplexBase::_rowByName(const std::string& name) const {
|
|
222
|
+
int index;
|
|
223
|
+
if (CPXgetrowindex(cplexEnv(), _prob,
|
|
224
|
+
const_cast<char*>(name.c_str()), &index) == 0) {
|
|
225
|
+
return index;
|
|
226
|
+
}
|
|
227
|
+
return -1;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
void CplexBase::_setRowCoeffs(int i, ExprIterator b,
|
|
231
|
+
ExprIterator e)
|
|
232
|
+
{
|
|
233
|
+
std::vector<int> indices;
|
|
234
|
+
std::vector<int> rowlist;
|
|
235
|
+
std::vector<Value> values;
|
|
236
|
+
|
|
237
|
+
for(ExprIterator it=b; it!=e; ++it) {
|
|
238
|
+
indices.push_back(it->first);
|
|
239
|
+
values.push_back(it->second);
|
|
240
|
+
rowlist.push_back(i);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
CPXchgcoeflist(cplexEnv(), _prob, values.size(),
|
|
244
|
+
&rowlist.front(), &indices.front(), &values.front());
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
void CplexBase::_getRowCoeffs(int i, InsertIterator b) const {
|
|
248
|
+
int tmp1, tmp2, tmp3, length;
|
|
249
|
+
CPXgetrows(cplexEnv(), _prob, &tmp1, &tmp2, 0, 0, 0, &length, i, i);
|
|
250
|
+
|
|
251
|
+
length = -length;
|
|
252
|
+
std::vector<int> indices(length);
|
|
253
|
+
std::vector<double> values(length);
|
|
254
|
+
|
|
255
|
+
CPXgetrows(cplexEnv(), _prob, &tmp1, &tmp2,
|
|
256
|
+
&indices.front(), &values.front(),
|
|
257
|
+
length, &tmp3, i, i);
|
|
258
|
+
|
|
259
|
+
for (int i = 0; i < length; ++i) {
|
|
260
|
+
*b = std::make_pair(indices[i], values[i]);
|
|
261
|
+
++b;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
void CplexBase::_setColCoeffs(int i, ExprIterator b, ExprIterator e) {
|
|
266
|
+
std::vector<int> indices;
|
|
267
|
+
std::vector<int> collist;
|
|
268
|
+
std::vector<Value> values;
|
|
269
|
+
|
|
270
|
+
for(ExprIterator it=b; it!=e; ++it) {
|
|
271
|
+
indices.push_back(it->first);
|
|
272
|
+
values.push_back(it->second);
|
|
273
|
+
collist.push_back(i);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
CPXchgcoeflist(cplexEnv(), _prob, values.size(),
|
|
277
|
+
&indices.front(), &collist.front(), &values.front());
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
void CplexBase::_getColCoeffs(int i, InsertIterator b) const {
|
|
281
|
+
|
|
282
|
+
int tmp1, tmp2, tmp3, length;
|
|
283
|
+
CPXgetcols(cplexEnv(), _prob, &tmp1, &tmp2, 0, 0, 0, &length, i, i);
|
|
284
|
+
|
|
285
|
+
length = -length;
|
|
286
|
+
std::vector<int> indices(length);
|
|
287
|
+
std::vector<double> values(length);
|
|
288
|
+
|
|
289
|
+
CPXgetcols(cplexEnv(), _prob, &tmp1, &tmp2,
|
|
290
|
+
&indices.front(), &values.front(),
|
|
291
|
+
length, &tmp3, i, i);
|
|
292
|
+
|
|
293
|
+
for (int i = 0; i < length; ++i) {
|
|
294
|
+
*b = std::make_pair(indices[i], values[i]);
|
|
295
|
+
++b;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
void CplexBase::_setCoeff(int row, int col, Value value) {
|
|
301
|
+
CPXchgcoef(cplexEnv(), _prob, row, col, value);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
CplexBase::Value CplexBase::_getCoeff(int row, int col) const {
|
|
305
|
+
CplexBase::Value value;
|
|
306
|
+
CPXgetcoef(cplexEnv(), _prob, row, col, &value);
|
|
307
|
+
return value;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
void CplexBase::_setColLowerBound(int i, Value value) {
|
|
311
|
+
const char s = 'L';
|
|
312
|
+
CPXchgbds(cplexEnv(), _prob, 1, &i, &s, &value);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
CplexBase::Value CplexBase::_getColLowerBound(int i) const {
|
|
316
|
+
CplexBase::Value res;
|
|
317
|
+
CPXgetlb(cplexEnv(), _prob, &res, i, i);
|
|
318
|
+
return res <= -CPX_INFBOUND ? -INF : res;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
void CplexBase::_setColUpperBound(int i, Value value)
|
|
322
|
+
{
|
|
323
|
+
const char s = 'U';
|
|
324
|
+
CPXchgbds(cplexEnv(), _prob, 1, &i, &s, &value);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
CplexBase::Value CplexBase::_getColUpperBound(int i) const {
|
|
328
|
+
CplexBase::Value res;
|
|
329
|
+
CPXgetub(cplexEnv(), _prob, &res, i, i);
|
|
330
|
+
return res >= CPX_INFBOUND ? INF : res;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
CplexBase::Value CplexBase::_getRowLowerBound(int i) const {
|
|
334
|
+
char s;
|
|
335
|
+
CPXgetsense(cplexEnv(), _prob, &s, i, i);
|
|
336
|
+
CplexBase::Value res;
|
|
337
|
+
|
|
338
|
+
switch (s) {
|
|
339
|
+
case 'G':
|
|
340
|
+
case 'R':
|
|
341
|
+
case 'E':
|
|
342
|
+
CPXgetrhs(cplexEnv(), _prob, &res, i, i);
|
|
343
|
+
return res <= -CPX_INFBOUND ? -INF : res;
|
|
344
|
+
default:
|
|
345
|
+
return -INF;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
CplexBase::Value CplexBase::_getRowUpperBound(int i) const {
|
|
350
|
+
char s;
|
|
351
|
+
CPXgetsense(cplexEnv(), _prob, &s, i, i);
|
|
352
|
+
CplexBase::Value res;
|
|
353
|
+
|
|
354
|
+
switch (s) {
|
|
355
|
+
case 'L':
|
|
356
|
+
case 'E':
|
|
357
|
+
CPXgetrhs(cplexEnv(), _prob, &res, i, i);
|
|
358
|
+
return res >= CPX_INFBOUND ? INF : res;
|
|
359
|
+
case 'R':
|
|
360
|
+
CPXgetrhs(cplexEnv(), _prob, &res, i, i);
|
|
361
|
+
{
|
|
362
|
+
double rng;
|
|
363
|
+
CPXgetrngval(cplexEnv(), _prob, &rng, i, i);
|
|
364
|
+
res += rng;
|
|
365
|
+
}
|
|
366
|
+
return res >= CPX_INFBOUND ? INF : res;
|
|
367
|
+
default:
|
|
368
|
+
return INF;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
//This is easier to implement
|
|
373
|
+
void CplexBase::_set_row_bounds(int i, Value lb, Value ub) {
|
|
374
|
+
if (lb == -INF) {
|
|
375
|
+
const char s = 'L';
|
|
376
|
+
CPXchgsense(cplexEnv(), _prob, 1, &i, &s);
|
|
377
|
+
CPXchgrhs(cplexEnv(), _prob, 1, &i, &ub);
|
|
378
|
+
} else if (ub == INF) {
|
|
379
|
+
const char s = 'G';
|
|
380
|
+
CPXchgsense(cplexEnv(), _prob, 1, &i, &s);
|
|
381
|
+
CPXchgrhs(cplexEnv(), _prob, 1, &i, &lb);
|
|
382
|
+
} else if (lb == ub){
|
|
383
|
+
const char s = 'E';
|
|
384
|
+
CPXchgsense(cplexEnv(), _prob, 1, &i, &s);
|
|
385
|
+
CPXchgrhs(cplexEnv(), _prob, 1, &i, &lb);
|
|
386
|
+
} else {
|
|
387
|
+
const char s = 'R';
|
|
388
|
+
CPXchgsense(cplexEnv(), _prob, 1, &i, &s);
|
|
389
|
+
CPXchgrhs(cplexEnv(), _prob, 1, &i, &lb);
|
|
390
|
+
double len = ub - lb;
|
|
391
|
+
CPXchgrngval(cplexEnv(), _prob, 1, &i, &len);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
void CplexBase::_setRowLowerBound(int i, Value lb)
|
|
396
|
+
{
|
|
397
|
+
LEMON_ASSERT(lb != INF, "Invalid bound");
|
|
398
|
+
_set_row_bounds(i, lb, CplexBase::_getRowUpperBound(i));
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
void CplexBase::_setRowUpperBound(int i, Value ub)
|
|
402
|
+
{
|
|
403
|
+
|
|
404
|
+
LEMON_ASSERT(ub != -INF, "Invalid bound");
|
|
405
|
+
_set_row_bounds(i, CplexBase::_getRowLowerBound(i), ub);
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
void CplexBase::_setObjCoeffs(ExprIterator b, ExprIterator e)
|
|
409
|
+
{
|
|
410
|
+
std::vector<int> indices;
|
|
411
|
+
std::vector<Value> values;
|
|
412
|
+
for(ExprIterator it=b; it!=e; ++it) {
|
|
413
|
+
indices.push_back(it->first);
|
|
414
|
+
values.push_back(it->second);
|
|
415
|
+
}
|
|
416
|
+
CPXchgobj(cplexEnv(), _prob, values.size(),
|
|
417
|
+
&indices.front(), &values.front());
|
|
418
|
+
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
void CplexBase::_getObjCoeffs(InsertIterator b) const
|
|
422
|
+
{
|
|
423
|
+
int num = CPXgetnumcols(cplexEnv(), _prob);
|
|
424
|
+
std::vector<Value> x(num);
|
|
425
|
+
|
|
426
|
+
CPXgetobj(cplexEnv(), _prob, &x.front(), 0, num - 1);
|
|
427
|
+
for (int i = 0; i < num; ++i) {
|
|
428
|
+
if (x[i] != 0.0) {
|
|
429
|
+
*b = std::make_pair(i, x[i]);
|
|
430
|
+
++b;
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
void CplexBase::_setObjCoeff(int i, Value obj_coef)
|
|
436
|
+
{
|
|
437
|
+
CPXchgobj(cplexEnv(), _prob, 1, &i, &obj_coef);
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
CplexBase::Value CplexBase::_getObjCoeff(int i) const
|
|
441
|
+
{
|
|
442
|
+
Value x;
|
|
443
|
+
CPXgetobj(cplexEnv(), _prob, &x, i, i);
|
|
444
|
+
return x;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
void CplexBase::_setSense(CplexBase::Sense sense) {
|
|
448
|
+
switch (sense) {
|
|
449
|
+
case MIN:
|
|
450
|
+
CPXchgobjsen(cplexEnv(), _prob, CPX_MIN);
|
|
451
|
+
break;
|
|
452
|
+
case MAX:
|
|
453
|
+
CPXchgobjsen(cplexEnv(), _prob, CPX_MAX);
|
|
454
|
+
break;
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
CplexBase::Sense CplexBase::_getSense() const {
|
|
459
|
+
switch (CPXgetobjsen(cplexEnv(), _prob)) {
|
|
460
|
+
case CPX_MIN:
|
|
461
|
+
return MIN;
|
|
462
|
+
case CPX_MAX:
|
|
463
|
+
return MAX;
|
|
464
|
+
default:
|
|
465
|
+
LEMON_ASSERT(false, "Invalid sense");
|
|
466
|
+
return CplexBase::Sense();
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
void CplexBase::_clear() {
|
|
471
|
+
CPXfreeprob(cplexEnv(),&_prob);
|
|
472
|
+
int status;
|
|
473
|
+
_prob = CPXcreateprob(cplexEnv(), &status, "Cplex problem");
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
void CplexBase::_messageLevel(MessageLevel level) {
|
|
477
|
+
switch (level) {
|
|
478
|
+
case MESSAGE_NOTHING:
|
|
479
|
+
_message_enabled = false;
|
|
480
|
+
break;
|
|
481
|
+
case MESSAGE_ERROR:
|
|
482
|
+
case MESSAGE_WARNING:
|
|
483
|
+
case MESSAGE_NORMAL:
|
|
484
|
+
case MESSAGE_VERBOSE:
|
|
485
|
+
_message_enabled = true;
|
|
486
|
+
break;
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
void CplexBase::_applyMessageLevel() {
|
|
491
|
+
CPXsetintparam(cplexEnv(), CPX_PARAM_SCRIND,
|
|
492
|
+
_message_enabled ? CPX_ON : CPX_OFF);
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
void CplexBase::_write(std::string file, std::string format) const
|
|
496
|
+
{
|
|
497
|
+
if(format == "MPS" || format == "LP")
|
|
498
|
+
CPXwriteprob(cplexEnv(), cplexLp(), file.c_str(), format.c_str());
|
|
499
|
+
else if(format == "SOL")
|
|
500
|
+
CPXsolwrite(cplexEnv(), cplexLp(), file.c_str());
|
|
501
|
+
else throw UnsupportedFormatError(format);
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
|
|
505
|
+
|
|
506
|
+
// CplexLp members
|
|
507
|
+
|
|
508
|
+
CplexLp::CplexLp()
|
|
509
|
+
: LpBase(), LpSolver(), CplexBase() {}
|
|
510
|
+
|
|
511
|
+
CplexLp::CplexLp(const CplexEnv& env)
|
|
512
|
+
: LpBase(), LpSolver(), CplexBase(env) {}
|
|
513
|
+
|
|
514
|
+
CplexLp::CplexLp(const CplexLp& other)
|
|
515
|
+
: LpBase(), LpSolver(), CplexBase(other) {}
|
|
516
|
+
|
|
517
|
+
CplexLp::~CplexLp() {}
|
|
518
|
+
|
|
519
|
+
CplexLp* CplexLp::newSolver() const { return new CplexLp; }
|
|
520
|
+
CplexLp* CplexLp::cloneSolver() const {return new CplexLp(*this); }
|
|
521
|
+
|
|
522
|
+
const char* CplexLp::_solverName() const { return "CplexLp"; }
|
|
523
|
+
|
|
524
|
+
void CplexLp::_clear_temporals() {
|
|
525
|
+
_col_status.clear();
|
|
526
|
+
_row_status.clear();
|
|
527
|
+
_primal_ray.clear();
|
|
528
|
+
_dual_ray.clear();
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
// The routine returns zero unless an error occurred during the
|
|
532
|
+
// optimization. Examples of errors include exhausting available
|
|
533
|
+
// memory (CPXERR_NO_MEMORY) or encountering invalid data in the
|
|
534
|
+
// CPLEX problem object (CPXERR_NO_PROBLEM). Exceeding a
|
|
535
|
+
// user-specified CPLEX limit, or proving the model infeasible or
|
|
536
|
+
// unbounded, are not considered errors. Note that a zero return
|
|
537
|
+
// value does not necessarily mean that a solution exists. Use query
|
|
538
|
+
// routines CPXsolninfo, CPXgetstat, and CPXsolution to obtain
|
|
539
|
+
// further information about the status of the optimization.
|
|
540
|
+
CplexLp::SolveExitStatus CplexLp::convertStatus(int status) {
|
|
541
|
+
#if CPX_VERSION >= 800
|
|
542
|
+
if (status == 0) {
|
|
543
|
+
switch (CPXgetstat(cplexEnv(), _prob)) {
|
|
544
|
+
case CPX_STAT_OPTIMAL:
|
|
545
|
+
case CPX_STAT_INFEASIBLE:
|
|
546
|
+
case CPX_STAT_UNBOUNDED:
|
|
547
|
+
return SOLVED;
|
|
548
|
+
default:
|
|
549
|
+
return UNSOLVED;
|
|
550
|
+
}
|
|
551
|
+
} else {
|
|
552
|
+
return UNSOLVED;
|
|
553
|
+
}
|
|
554
|
+
#else
|
|
555
|
+
if (status == 0) {
|
|
556
|
+
//We want to exclude some cases
|
|
557
|
+
switch (CPXgetstat(cplexEnv(), _prob)) {
|
|
558
|
+
case CPX_OBJ_LIM:
|
|
559
|
+
case CPX_IT_LIM_FEAS:
|
|
560
|
+
case CPX_IT_LIM_INFEAS:
|
|
561
|
+
case CPX_TIME_LIM_FEAS:
|
|
562
|
+
case CPX_TIME_LIM_INFEAS:
|
|
563
|
+
return UNSOLVED;
|
|
564
|
+
default:
|
|
565
|
+
return SOLVED;
|
|
566
|
+
}
|
|
567
|
+
} else {
|
|
568
|
+
return UNSOLVED;
|
|
569
|
+
}
|
|
570
|
+
#endif
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
CplexLp::SolveExitStatus CplexLp::_solve() {
|
|
574
|
+
_clear_temporals();
|
|
575
|
+
_applyMessageLevel();
|
|
576
|
+
return convertStatus(CPXlpopt(cplexEnv(), _prob));
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
CplexLp::SolveExitStatus CplexLp::solvePrimal() {
|
|
580
|
+
_clear_temporals();
|
|
581
|
+
_applyMessageLevel();
|
|
582
|
+
return convertStatus(CPXprimopt(cplexEnv(), _prob));
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
CplexLp::SolveExitStatus CplexLp::solveDual() {
|
|
586
|
+
_clear_temporals();
|
|
587
|
+
_applyMessageLevel();
|
|
588
|
+
return convertStatus(CPXdualopt(cplexEnv(), _prob));
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
CplexLp::SolveExitStatus CplexLp::solveBarrier() {
|
|
592
|
+
_clear_temporals();
|
|
593
|
+
_applyMessageLevel();
|
|
594
|
+
return convertStatus(CPXbaropt(cplexEnv(), _prob));
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
CplexLp::Value CplexLp::_getPrimal(int i) const {
|
|
598
|
+
Value x;
|
|
599
|
+
CPXgetx(cplexEnv(), _prob, &x, i, i);
|
|
600
|
+
return x;
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
CplexLp::Value CplexLp::_getDual(int i) const {
|
|
604
|
+
Value y;
|
|
605
|
+
CPXgetpi(cplexEnv(), _prob, &y, i, i);
|
|
606
|
+
return y;
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
CplexLp::Value CplexLp::_getPrimalValue() const {
|
|
610
|
+
Value objval;
|
|
611
|
+
CPXgetobjval(cplexEnv(), _prob, &objval);
|
|
612
|
+
return objval;
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
CplexLp::VarStatus CplexLp::_getColStatus(int i) const {
|
|
616
|
+
if (_col_status.empty()) {
|
|
617
|
+
_col_status.resize(CPXgetnumcols(cplexEnv(), _prob));
|
|
618
|
+
CPXgetbase(cplexEnv(), _prob, &_col_status.front(), 0);
|
|
619
|
+
}
|
|
620
|
+
switch (_col_status[i]) {
|
|
621
|
+
case CPX_BASIC:
|
|
622
|
+
return BASIC;
|
|
623
|
+
case CPX_FREE_SUPER:
|
|
624
|
+
return FREE;
|
|
625
|
+
case CPX_AT_LOWER:
|
|
626
|
+
return LOWER;
|
|
627
|
+
case CPX_AT_UPPER:
|
|
628
|
+
return UPPER;
|
|
629
|
+
default:
|
|
630
|
+
LEMON_ASSERT(false, "Wrong column status");
|
|
631
|
+
return CplexLp::VarStatus();
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
CplexLp::VarStatus CplexLp::_getRowStatus(int i) const {
|
|
636
|
+
if (_row_status.empty()) {
|
|
637
|
+
_row_status.resize(CPXgetnumrows(cplexEnv(), _prob));
|
|
638
|
+
CPXgetbase(cplexEnv(), _prob, 0, &_row_status.front());
|
|
639
|
+
}
|
|
640
|
+
switch (_row_status[i]) {
|
|
641
|
+
case CPX_BASIC:
|
|
642
|
+
return BASIC;
|
|
643
|
+
case CPX_AT_LOWER:
|
|
644
|
+
{
|
|
645
|
+
char s;
|
|
646
|
+
CPXgetsense(cplexEnv(), _prob, &s, i, i);
|
|
647
|
+
return s != 'L' ? LOWER : UPPER;
|
|
648
|
+
}
|
|
649
|
+
case CPX_AT_UPPER:
|
|
650
|
+
return UPPER;
|
|
651
|
+
default:
|
|
652
|
+
LEMON_ASSERT(false, "Wrong row status");
|
|
653
|
+
return CplexLp::VarStatus();
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
CplexLp::Value CplexLp::_getPrimalRay(int i) const {
|
|
658
|
+
if (_primal_ray.empty()) {
|
|
659
|
+
_primal_ray.resize(CPXgetnumcols(cplexEnv(), _prob));
|
|
660
|
+
CPXgetray(cplexEnv(), _prob, &_primal_ray.front());
|
|
661
|
+
}
|
|
662
|
+
return _primal_ray[i];
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
CplexLp::Value CplexLp::_getDualRay(int i) const {
|
|
666
|
+
if (_dual_ray.empty()) {
|
|
667
|
+
|
|
668
|
+
}
|
|
669
|
+
return _dual_ray[i];
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
// Cplex 7.0 status values
|
|
673
|
+
// This table lists the statuses, returned by the CPXgetstat()
|
|
674
|
+
// routine, for solutions to LP problems or mixed integer problems. If
|
|
675
|
+
// no solution exists, the return value is zero.
|
|
676
|
+
|
|
677
|
+
// For Simplex, Barrier
|
|
678
|
+
// 1 CPX_OPTIMAL
|
|
679
|
+
// Optimal solution found
|
|
680
|
+
// 2 CPX_INFEASIBLE
|
|
681
|
+
// Problem infeasible
|
|
682
|
+
// 3 CPX_UNBOUNDED
|
|
683
|
+
// Problem unbounded
|
|
684
|
+
// 4 CPX_OBJ_LIM
|
|
685
|
+
// Objective limit exceeded in Phase II
|
|
686
|
+
// 5 CPX_IT_LIM_FEAS
|
|
687
|
+
// Iteration limit exceeded in Phase II
|
|
688
|
+
// 6 CPX_IT_LIM_INFEAS
|
|
689
|
+
// Iteration limit exceeded in Phase I
|
|
690
|
+
// 7 CPX_TIME_LIM_FEAS
|
|
691
|
+
// Time limit exceeded in Phase II
|
|
692
|
+
// 8 CPX_TIME_LIM_INFEAS
|
|
693
|
+
// Time limit exceeded in Phase I
|
|
694
|
+
// 9 CPX_NUM_BEST_FEAS
|
|
695
|
+
// Problem non-optimal, singularities in Phase II
|
|
696
|
+
// 10 CPX_NUM_BEST_INFEAS
|
|
697
|
+
// Problem non-optimal, singularities in Phase I
|
|
698
|
+
// 11 CPX_OPTIMAL_INFEAS
|
|
699
|
+
// Optimal solution found, unscaled infeasibilities
|
|
700
|
+
// 12 CPX_ABORT_FEAS
|
|
701
|
+
// Aborted in Phase II
|
|
702
|
+
// 13 CPX_ABORT_INFEAS
|
|
703
|
+
// Aborted in Phase I
|
|
704
|
+
// 14 CPX_ABORT_DUAL_INFEAS
|
|
705
|
+
// Aborted in barrier, dual infeasible
|
|
706
|
+
// 15 CPX_ABORT_PRIM_INFEAS
|
|
707
|
+
// Aborted in barrier, primal infeasible
|
|
708
|
+
// 16 CPX_ABORT_PRIM_DUAL_INFEAS
|
|
709
|
+
// Aborted in barrier, primal and dual infeasible
|
|
710
|
+
// 17 CPX_ABORT_PRIM_DUAL_FEAS
|
|
711
|
+
// Aborted in barrier, primal and dual feasible
|
|
712
|
+
// 18 CPX_ABORT_CROSSOVER
|
|
713
|
+
// Aborted in crossover
|
|
714
|
+
// 19 CPX_INForUNBD
|
|
715
|
+
// Infeasible or unbounded
|
|
716
|
+
// 20 CPX_PIVOT
|
|
717
|
+
// User pivot used
|
|
718
|
+
//
|
|
719
|
+
// Pending return values
|
|
720
|
+
// ??case CPX_ABORT_DUAL_INFEAS
|
|
721
|
+
// ??case CPX_ABORT_CROSSOVER
|
|
722
|
+
// ??case CPX_INForUNBD
|
|
723
|
+
// ??case CPX_PIVOT
|
|
724
|
+
|
|
725
|
+
//Some more interesting stuff:
|
|
726
|
+
|
|
727
|
+
// CPX_PARAM_PROBMETHOD 1062 int LPMETHOD
|
|
728
|
+
// 0 Automatic
|
|
729
|
+
// 1 Primal Simplex
|
|
730
|
+
// 2 Dual Simplex
|
|
731
|
+
// 3 Network Simplex
|
|
732
|
+
// 4 Standard Barrier
|
|
733
|
+
// Default: 0
|
|
734
|
+
// Description: Method for linear optimization.
|
|
735
|
+
// Determines which algorithm is used when CPXlpopt() (or "optimize"
|
|
736
|
+
// in the Interactive Optimizer) is called. Currently the behavior of
|
|
737
|
+
// the "Automatic" setting is that CPLEX simply invokes the dual
|
|
738
|
+
// simplex method, but this capability may be expanded in the future
|
|
739
|
+
// so that CPLEX chooses the method based on problem characteristics
|
|
740
|
+
#if CPX_VERSION < 900
|
|
741
|
+
void statusSwitch(CPXENVptr cplexEnv(),int& stat){
|
|
742
|
+
int lpmethod;
|
|
743
|
+
CPXgetintparam (cplexEnv(),CPX_PARAM_PROBMETHOD,&lpmethod);
|
|
744
|
+
if (lpmethod==2){
|
|
745
|
+
if (stat==CPX_UNBOUNDED){
|
|
746
|
+
stat=CPX_INFEASIBLE;
|
|
747
|
+
}
|
|
748
|
+
else{
|
|
749
|
+
if (stat==CPX_INFEASIBLE)
|
|
750
|
+
stat=CPX_UNBOUNDED;
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
#else
|
|
755
|
+
void statusSwitch(CPXENVptr,int&){}
|
|
756
|
+
#endif
|
|
757
|
+
|
|
758
|
+
CplexLp::ProblemType CplexLp::_getPrimalType() const {
|
|
759
|
+
// Unboundedness not treated well: the following is from cplex 9.0 doc
|
|
760
|
+
// About Unboundedness
|
|
761
|
+
|
|
762
|
+
// The treatment of models that are unbounded involves a few
|
|
763
|
+
// subtleties. Specifically, a declaration of unboundedness means that
|
|
764
|
+
// ILOG CPLEX has determined that the model has an unbounded
|
|
765
|
+
// ray. Given any feasible solution x with objective z, a multiple of
|
|
766
|
+
// the unbounded ray can be added to x to give a feasible solution
|
|
767
|
+
// with objective z-1 (or z+1 for maximization models). Thus, if a
|
|
768
|
+
// feasible solution exists, then the optimal objective is
|
|
769
|
+
// unbounded. Note that ILOG CPLEX has not necessarily concluded that
|
|
770
|
+
// a feasible solution exists. Users can call the routine CPXsolninfo
|
|
771
|
+
// to determine whether ILOG CPLEX has also concluded that the model
|
|
772
|
+
// has a feasible solution.
|
|
773
|
+
|
|
774
|
+
int stat = CPXgetstat(cplexEnv(), _prob);
|
|
775
|
+
#if CPX_VERSION >= 800
|
|
776
|
+
switch (stat)
|
|
777
|
+
{
|
|
778
|
+
case CPX_STAT_OPTIMAL:
|
|
779
|
+
return OPTIMAL;
|
|
780
|
+
case CPX_STAT_UNBOUNDED:
|
|
781
|
+
return UNBOUNDED;
|
|
782
|
+
case CPX_STAT_INFEASIBLE:
|
|
783
|
+
return INFEASIBLE;
|
|
784
|
+
default:
|
|
785
|
+
return UNDEFINED;
|
|
786
|
+
}
|
|
787
|
+
#else
|
|
788
|
+
statusSwitch(cplexEnv(),stat);
|
|
789
|
+
//CPXgetstat(cplexEnv(), _prob);
|
|
790
|
+
switch (stat) {
|
|
791
|
+
case 0:
|
|
792
|
+
return UNDEFINED; //Undefined
|
|
793
|
+
case CPX_OPTIMAL://Optimal
|
|
794
|
+
return OPTIMAL;
|
|
795
|
+
case CPX_UNBOUNDED://Unbounded
|
|
796
|
+
return INFEASIBLE;//In case of dual simplex
|
|
797
|
+
//return UNBOUNDED;
|
|
798
|
+
case CPX_INFEASIBLE://Infeasible
|
|
799
|
+
// case CPX_IT_LIM_INFEAS:
|
|
800
|
+
// case CPX_TIME_LIM_INFEAS:
|
|
801
|
+
// case CPX_NUM_BEST_INFEAS:
|
|
802
|
+
// case CPX_OPTIMAL_INFEAS:
|
|
803
|
+
// case CPX_ABORT_INFEAS:
|
|
804
|
+
// case CPX_ABORT_PRIM_INFEAS:
|
|
805
|
+
// case CPX_ABORT_PRIM_DUAL_INFEAS:
|
|
806
|
+
return UNBOUNDED;//In case of dual simplex
|
|
807
|
+
//return INFEASIBLE;
|
|
808
|
+
// case CPX_OBJ_LIM:
|
|
809
|
+
// case CPX_IT_LIM_FEAS:
|
|
810
|
+
// case CPX_TIME_LIM_FEAS:
|
|
811
|
+
// case CPX_NUM_BEST_FEAS:
|
|
812
|
+
// case CPX_ABORT_FEAS:
|
|
813
|
+
// case CPX_ABORT_PRIM_DUAL_FEAS:
|
|
814
|
+
// return FEASIBLE;
|
|
815
|
+
default:
|
|
816
|
+
return UNDEFINED; //Everything else comes here
|
|
817
|
+
//FIXME error
|
|
818
|
+
}
|
|
819
|
+
#endif
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
// Cplex 9.0 status values
|
|
823
|
+
// CPX_STAT_ABORT_DUAL_OBJ_LIM
|
|
824
|
+
// CPX_STAT_ABORT_IT_LIM
|
|
825
|
+
// CPX_STAT_ABORT_OBJ_LIM
|
|
826
|
+
// CPX_STAT_ABORT_PRIM_OBJ_LIM
|
|
827
|
+
// CPX_STAT_ABORT_TIME_LIM
|
|
828
|
+
// CPX_STAT_ABORT_USER
|
|
829
|
+
// CPX_STAT_FEASIBLE_RELAXED
|
|
830
|
+
// CPX_STAT_INFEASIBLE
|
|
831
|
+
// CPX_STAT_INForUNBD
|
|
832
|
+
// CPX_STAT_NUM_BEST
|
|
833
|
+
// CPX_STAT_OPTIMAL
|
|
834
|
+
// CPX_STAT_OPTIMAL_FACE_UNBOUNDED
|
|
835
|
+
// CPX_STAT_OPTIMAL_INFEAS
|
|
836
|
+
// CPX_STAT_OPTIMAL_RELAXED
|
|
837
|
+
// CPX_STAT_UNBOUNDED
|
|
838
|
+
|
|
839
|
+
CplexLp::ProblemType CplexLp::_getDualType() const {
|
|
840
|
+
int stat = CPXgetstat(cplexEnv(), _prob);
|
|
841
|
+
#if CPX_VERSION >= 800
|
|
842
|
+
switch (stat) {
|
|
843
|
+
case CPX_STAT_OPTIMAL:
|
|
844
|
+
return OPTIMAL;
|
|
845
|
+
case CPX_STAT_UNBOUNDED:
|
|
846
|
+
return INFEASIBLE;
|
|
847
|
+
default:
|
|
848
|
+
return UNDEFINED;
|
|
849
|
+
}
|
|
850
|
+
#else
|
|
851
|
+
statusSwitch(cplexEnv(),stat);
|
|
852
|
+
switch (stat) {
|
|
853
|
+
case 0:
|
|
854
|
+
return UNDEFINED; //Undefined
|
|
855
|
+
case CPX_OPTIMAL://Optimal
|
|
856
|
+
return OPTIMAL;
|
|
857
|
+
case CPX_UNBOUNDED:
|
|
858
|
+
return INFEASIBLE;
|
|
859
|
+
default:
|
|
860
|
+
return UNDEFINED; //Everything else comes here
|
|
861
|
+
//FIXME error
|
|
862
|
+
}
|
|
863
|
+
#endif
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
// CplexMip members
|
|
867
|
+
|
|
868
|
+
CplexMip::CplexMip()
|
|
869
|
+
: LpBase(), MipSolver(), CplexBase() {
|
|
870
|
+
|
|
871
|
+
#if CPX_VERSION < 800
|
|
872
|
+
CPXchgprobtype(cplexEnv(), _prob, CPXPROB_MIP);
|
|
873
|
+
#else
|
|
874
|
+
CPXchgprobtype(cplexEnv(), _prob, CPXPROB_MILP);
|
|
875
|
+
#endif
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
CplexMip::CplexMip(const CplexEnv& env)
|
|
879
|
+
: LpBase(), MipSolver(), CplexBase(env) {
|
|
880
|
+
|
|
881
|
+
#if CPX_VERSION < 800
|
|
882
|
+
CPXchgprobtype(cplexEnv(), _prob, CPXPROB_MIP);
|
|
883
|
+
#else
|
|
884
|
+
CPXchgprobtype(cplexEnv(), _prob, CPXPROB_MILP);
|
|
885
|
+
#endif
|
|
886
|
+
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
CplexMip::CplexMip(const CplexMip& other)
|
|
890
|
+
: LpBase(), MipSolver(), CplexBase(other) {}
|
|
891
|
+
|
|
892
|
+
CplexMip::~CplexMip() {}
|
|
893
|
+
|
|
894
|
+
CplexMip* CplexMip::newSolver() const { return new CplexMip; }
|
|
895
|
+
CplexMip* CplexMip::cloneSolver() const {return new CplexMip(*this); }
|
|
896
|
+
|
|
897
|
+
const char* CplexMip::_solverName() const { return "CplexMip"; }
|
|
898
|
+
|
|
899
|
+
void CplexMip::_setColType(int i, CplexMip::ColTypes col_type) {
|
|
900
|
+
|
|
901
|
+
// Note If a variable is to be changed to binary, a call to CPXchgbds
|
|
902
|
+
// should also be made to change the bounds to 0 and 1.
|
|
903
|
+
|
|
904
|
+
switch (col_type){
|
|
905
|
+
case INTEGER: {
|
|
906
|
+
const char t = 'I';
|
|
907
|
+
CPXchgctype (cplexEnv(), _prob, 1, &i, &t);
|
|
908
|
+
} break;
|
|
909
|
+
case REAL: {
|
|
910
|
+
const char t = 'C';
|
|
911
|
+
CPXchgctype (cplexEnv(), _prob, 1, &i, &t);
|
|
912
|
+
} break;
|
|
913
|
+
default:
|
|
914
|
+
break;
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
CplexMip::ColTypes CplexMip::_getColType(int i) const {
|
|
919
|
+
char t;
|
|
920
|
+
CPXgetctype (cplexEnv(), _prob, &t, i, i);
|
|
921
|
+
switch (t) {
|
|
922
|
+
case 'I':
|
|
923
|
+
return INTEGER;
|
|
924
|
+
case 'C':
|
|
925
|
+
return REAL;
|
|
926
|
+
default:
|
|
927
|
+
LEMON_ASSERT(false, "Invalid column type");
|
|
928
|
+
return ColTypes();
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
CplexMip::SolveExitStatus CplexMip::_solve() {
|
|
934
|
+
int status;
|
|
935
|
+
_applyMessageLevel();
|
|
936
|
+
status = CPXmipopt (cplexEnv(), _prob);
|
|
937
|
+
if (status==0)
|
|
938
|
+
return SOLVED;
|
|
939
|
+
else
|
|
940
|
+
return UNSOLVED;
|
|
941
|
+
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
|
|
945
|
+
CplexMip::ProblemType CplexMip::_getType() const {
|
|
946
|
+
|
|
947
|
+
int stat = CPXgetstat(cplexEnv(), _prob);
|
|
948
|
+
|
|
949
|
+
//Fortunately, MIP statuses did not change for cplex 8.0
|
|
950
|
+
switch (stat) {
|
|
951
|
+
case CPXMIP_OPTIMAL:
|
|
952
|
+
// Optimal integer solution has been found.
|
|
953
|
+
case CPXMIP_OPTIMAL_TOL:
|
|
954
|
+
// Optimal soluton with the tolerance defined by epgap or epagap has
|
|
955
|
+
// been found.
|
|
956
|
+
return OPTIMAL;
|
|
957
|
+
//This also exists in later issues
|
|
958
|
+
// case CPXMIP_UNBOUNDED:
|
|
959
|
+
//return UNBOUNDED;
|
|
960
|
+
case CPXMIP_INFEASIBLE:
|
|
961
|
+
return INFEASIBLE;
|
|
962
|
+
default:
|
|
963
|
+
return UNDEFINED;
|
|
964
|
+
}
|
|
965
|
+
//Unboundedness not treated well: the following is from cplex 9.0 doc
|
|
966
|
+
// About Unboundedness
|
|
967
|
+
|
|
968
|
+
// The treatment of models that are unbounded involves a few
|
|
969
|
+
// subtleties. Specifically, a declaration of unboundedness means that
|
|
970
|
+
// ILOG CPLEX has determined that the model has an unbounded
|
|
971
|
+
// ray. Given any feasible solution x with objective z, a multiple of
|
|
972
|
+
// the unbounded ray can be added to x to give a feasible solution
|
|
973
|
+
// with objective z-1 (or z+1 for maximization models). Thus, if a
|
|
974
|
+
// feasible solution exists, then the optimal objective is
|
|
975
|
+
// unbounded. Note that ILOG CPLEX has not necessarily concluded that
|
|
976
|
+
// a feasible solution exists. Users can call the routine CPXsolninfo
|
|
977
|
+
// to determine whether ILOG CPLEX has also concluded that the model
|
|
978
|
+
// has a feasible solution.
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
CplexMip::Value CplexMip::_getSol(int i) const {
|
|
982
|
+
Value x;
|
|
983
|
+
CPXgetmipx(cplexEnv(), _prob, &x, i, i);
|
|
984
|
+
return x;
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
CplexMip::Value CplexMip::_getSolValue() const {
|
|
988
|
+
Value objval;
|
|
989
|
+
CPXgetmipobjval(cplexEnv(), _prob, &objval);
|
|
990
|
+
return objval;
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
} //namespace lemon
|
|
994
|
+
|