|
#include <cstdio> |
|
#include <vector> |
|
#include <random> |
|
#include <algorithm> |
|
#include <stdexcept> |
|
#include <limits> |
|
#include <cmath> |
|
|
|
#include <glpk.h> |
|
|
|
#include "defer.h" |
|
|
|
using namespace std; |
|
|
|
// solution function |
|
pair<double, vector<double>> simplex(const vector<vector<double>> &, |
|
const vector<double> &, |
|
const vector<double> &); |
|
|
|
pair<double, vector<double>> simplex_glpk(const vector<vector<double>> & A, |
|
const vector<double> & b, |
|
const vector<double> & c) { |
|
const int n = c.size(); |
|
const int m = b.size(); |
|
|
|
int seq[n]; |
|
iota(seq, seq + n, 1); |
|
|
|
glp_prob * lp; |
|
lp = glp_create_prob(); |
|
defer { |
|
glp_delete_prob(lp); |
|
}; |
|
glp_set_obj_dir(lp, GLP_MAX); |
|
glp_add_rows(lp, m); |
|
glp_add_cols(lp, n); |
|
for (int i = 0; i < m; ++i) { |
|
glp_set_row_bnds(lp, i + 1, GLP_UP, 0.0, b[i]); |
|
glp_set_mat_row(lp, i + 1, n, seq - 1, A[i].data() - 1); |
|
} |
|
for (int i = 0; i < n; ++i) { |
|
glp_set_col_bnds(lp, i + 1, GLP_LO, 0.0, 0.0); |
|
glp_set_obj_coef(lp, i + 1, c[i]); |
|
} |
|
|
|
glp_smcp parm; |
|
glp_init_smcp(&parm); |
|
parm.msg_lev = GLP_MSG_ERR; |
|
int res = glp_simplex(lp, &parm); |
|
if (res != 0) { |
|
throw runtime_error("glp_simplex_failed"); |
|
} |
|
|
|
int status = glp_get_status(lp); |
|
if (status == GLP_OPT) { |
|
vector<double> res(n); |
|
for (int i = 0; i < n; ++i) { |
|
res[i] = glp_get_col_prim(lp, i + 1); |
|
} |
|
return {glp_get_obj_val(lp), res}; |
|
} else if (status == GLP_UNBND) { |
|
return {numeric_limits<double>::infinity(), vector<double>()}; |
|
} else { |
|
throw runtime_error( |
|
"unexpected unknown siplex solution: " + to_string(status)); |
|
} |
|
} |
|
|
|
bool are_same(double x, double y, double EPS = 1e-6) { |
|
return fabs(x - y) <= EPS * max(1.0, max(fabs(x), fabs(y))); |
|
} |
|
|
|
#ifdef GTEST |
|
int main() { |
|
random_device rd; |
|
mt19937 gen(rd()); |
|
uniform_int_distribution<int> b_dist(0, 10000), |
|
a_dist(-10000, 10000), |
|
c_dist = a_dist, |
|
n_dist(20, 50), |
|
m_dist(20, 50); |
|
|
|
auto gen_b = [&] (const int m) { |
|
vector<double> b(m, 0.0); |
|
for (int i = 0; i < m; ++i) b[i] = b_dist(gen); |
|
return b; |
|
}; |
|
|
|
auto gen_c = [&] (const int n) { |
|
vector<double> c(n, 0.0); |
|
for (int i = 0; i < n; ++i) c[i] = c_dist(gen); |
|
return c; |
|
}; |
|
|
|
auto gen_A = [&] (const int n, const int m) { |
|
vector<vector<double>> A(m, vector<double>(n, 0.0)); |
|
for (int i = 0; i < m; ++i) { |
|
for (int j = 0; j < n; ++j) { |
|
A[i][j] = a_dist(gen); |
|
} |
|
} |
|
return A; |
|
}; |
|
|
|
// prints problem in satori format |
|
auto print_problem = [] (vector<vector<double>> & A, |
|
vector<double> & b, |
|
vector<double> & c) { |
|
const int n = c.size(); |
|
const int m = b.size(); |
|
printf("%d %d\n", n, m); |
|
for (int i = 0; i < n; ++i) { |
|
printf("%.0lf ", c[i]); |
|
} |
|
printf("\n"); |
|
for (int i = 0; i < m; ++i) { |
|
for (int j = 0; j < n; ++j) { |
|
printf("%.0lf ", A[i][j]); |
|
} |
|
printf("%.0lf\n", b[i]); |
|
} |
|
}; |
|
|
|
for (int i = 0; i < 100000000; ++i) { |
|
if (i % 10 == 0) { |
|
printf("\r%9d", i); |
|
fflush(stdout); |
|
} |
|
const int n = n_dist(gen); |
|
const int m = m_dist(gen); |
|
auto A = gen_A(n, m); |
|
auto b = gen_b(m); |
|
auto c = gen_c(n); |
|
auto res1 = simplex(A, b, c); |
|
auto res2 = simplex_glpk(A, b, c); |
|
if (std::isinf(res1.first) != std::isinf(res2.first)) { |
|
printf("my: %lg glpk: %lg\n", res1.first, res2.first); |
|
print_problem(A, b, c); |
|
return 1; |
|
} |
|
if (isfinite(res1.first) && !are_same(res1.first, res2.first)) { |
|
printf("my: %lg glpk: %lg diff: %lg\n", |
|
res1.first, res2.first, fabs(res1.first - res2.first)); |
|
print_problem(A, b, c); |
|
printf(" x my glpk\n"); |
|
for (unsigned i = 1; i < res1.second.size(); ++i) { |
|
printf("%2d %8lg %8lg\n", i, res1.second[i], res2.second[i]); |
|
} |
|
return 2; |
|
} |
|
} |
|
printf("\n"); |
|
|
|
return 0; |
|
} |
|
#endif |