[gnumeric] glpk: recover sensitivity information when requested
- From: Morten Welinder <mortenw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnumeric] glpk: recover sensitivity information when requested
- Date: Fri, 12 Feb 2016 03:23:43 +0000 (UTC)
commit a869e6a5e81c8e95b0cbb04d06c6d45086d58eb3
Author: Morten Welinder <terra gnome org>
Date: Thu Feb 11 22:23:04 2016 -0500
glpk: recover sensitivity information when requested
plugins/glpk/gnm-glpk.c | 170 +++++++++++++++++++++++++++++++++++++++++++---
1 files changed, 158 insertions(+), 12 deletions(-)
---
diff --git a/plugins/glpk/gnm-glpk.c b/plugins/glpk/gnm-glpk.c
index 53d9195..1ca7d8d 100644
--- a/plugins/glpk/gnm-glpk.c
+++ b/plugins/glpk/gnm-glpk.c
@@ -22,6 +22,7 @@
typedef struct {
GnmSubSolver *parent;
char *result_filename;
+ char *ranges_filename;
} GnmGlpk;
static void
@@ -33,6 +34,11 @@ gnm_glpk_cleanup (GnmGlpk *lp)
g_free (lp->result_filename);
lp->result_filename = NULL;
}
+ if (lp->ranges_filename) {
+ g_unlink (lp->ranges_filename);
+ g_free (lp->ranges_filename);
+ lp->ranges_filename = NULL;
+ }
}
static void
@@ -61,21 +67,56 @@ write_program (GnmSolver *sol, WorkbookControl *wbc, GError **err)
err);
}
+static char **
+my_strsplit (const char *line)
+{
+ GPtrArray *res = g_ptr_array_new ();
+
+ while (1) {
+ const char *end;
+
+ while (g_ascii_isspace (*line))
+ line++;
+
+ if (!*line)
+ break;
+
+ end = line;
+ while (*end && !g_ascii_isspace (*end))
+ end++;
+
+ g_ptr_array_add (res, g_strndup (line, end - line));
+ line = end;
+ }
+ g_ptr_array_add (res, NULL);
+
+ return (char **)g_ptr_array_free (res, FALSE);
+}
+
+static gnm_float
+parse_number (const char *s)
+{
+ if (strcmp (s, ".") == 0)
+ return 0;
+ return g_ascii_strtod (s, NULL);
+}
+
static void
gnm_glpk_read_solution (GnmGlpk *lp)
{
GnmSubSolver *subsol = lp->parent;
GnmSolver *sol = GNM_SOLVER (subsol);
GsfInput *input;
- GsfInputTextline *tl;
+ GsfInputTextline *tl = NULL;
const char *line;
unsigned rows, cols, c, r;
int pstat, dstat;
gnm_float val;
- GnmSolverResult *result;
- GnmSolverSensitivity *sensitivity;
+ GnmSolverResult *result = NULL;
+ GnmSolverSensitivity *sensitivity = NULL;
gboolean has_integer;
GSList *l;
+ enum { SEC_UNKNOWN, SEC_ROWS, SEC_COLUMNS } state;
/*
* glpsol's output format is different if there are any integer
@@ -90,8 +131,7 @@ gnm_glpk_read_solution (GnmGlpk *lp)
input = gsf_input_stdio_new (lp->result_filename, NULL);
if (!input)
- return;
-
+ goto fail;
tl = GSF_INPUT_TEXTLINE (gsf_input_textline_new (input));
g_object_unref (input);
@@ -132,10 +172,22 @@ gnm_glpk_read_solution (GnmGlpk *lp)
goto fail;
}
- for (r = 1; r <= rows; r++) {
+ for (r = 0; r < rows; r++) {
+ gnm_float pval, dval;
+ unsigned rstat;
+ unsigned cidx = r;
+
if ((line = gsf_input_textline_utf8_gets (tl)) == NULL)
goto fail;
- /* Ignore the line */
+
+ if (has_integer)
+ continue;
+
+ if (sscanf (line, "%u %" GNM_SCANF_g " %" GNM_SCANF_g,
+ &rstat, &pval, &dval) != 3)
+ goto fail;
+
+ sensitivity->constraints[cidx].shadow_price = dval;
}
for (c = 0; c < cols; c++) {
@@ -157,18 +209,99 @@ gnm_glpk_read_solution (GnmGlpk *lp)
sensitivity->vars[idx].reduced_cost = dval;
}
+ g_object_unref (tl);
+ tl = NULL;
+
+ // ----------------------------------------
+
+ if (!lp->ranges_filename)
+ goto done;
+
+ input = gsf_input_stdio_new (lp->ranges_filename, NULL);
+ if (!input)
+ goto fail;
+ tl = GSF_INPUT_TEXTLINE (gsf_input_textline_new (input));
+ g_object_unref (input);
+
+ state = SEC_UNKNOWN;
+ // We are reading a file intended for human consumption.
+ // That is unfortunately because it implies rounding, for example.
+ // The information does not appear to be available elsewhere.
+
+ while ((line = gsf_input_textline_utf8_gets (tl)) != NULL) {
+ gchar **items, **items2 = NULL;
+ int len, len2 = 0;
+
+ if (g_str_has_prefix (line, " No. Row name")) {
+ state = SEC_ROWS;
+ continue;
+ } else if (g_str_has_prefix (line, " No. Column name")) {
+ state = SEC_COLUMNS;
+ continue;
+ } else if (g_ascii_isalpha (line[0])) {
+ state = SEC_UNKNOWN;
+ continue;
+ }
+
+ if (state == SEC_UNKNOWN)
+ continue;
+
+ items = my_strsplit (line);
+ len = g_strv_length (items);
+
+ if (len == 10 && g_ascii_isdigit (items[0][0])) {
+ line = gsf_input_textline_utf8_gets (tl);
+ if (line) {
+ items2 = my_strsplit (line);
+ len2 = g_strv_length (items2);
+ }
+ }
+
+ if (len == 10 && len2 == 6 && state == SEC_COLUMNS) {
+ gnm_float low = parse_number (items[7]);
+ gnm_float high = parse_number (items2[3]);
+ GnmCell const *cell = gnm_sub_solver_find_cell (lp->parent, items[1]);
+ int idx = gnm_solver_cell_index (sol, cell);
+ if (idx >= 0) {
+ sensitivity->vars[idx].low = low;
+ sensitivity->vars[idx].high = high;
+ }
+ }
+
+ if (len == 10 && len2 == 6 && state == SEC_ROWS) {
+ gnm_float low = parse_number (items[6]);
+ gnm_float high = parse_number (items2[2]);
+ int cidx = gnm_sub_solver_find_constraint (lp->parent, items[1]);
+ if (cidx >= 0) {
+ sensitivity->constraints[cidx].low = low;
+ sensitivity->constraints[cidx].high = high;
+ }
+ }
+
+ g_strfreev (items);
+ g_strfreev (items2);
+
+ }
+
+ g_object_unref (tl);
+
+ // ----------------------------------------
+done:
gnm_solver_set_status (sol, GNM_SOLVER_STATUS_DONE);
g_object_set (subsol, "result", result, NULL);
g_object_unref (result);
g_object_set (subsol, "sensitivity", sensitivity, NULL);
g_object_unref (sensitivity);
- g_object_unref (tl);
return;
fail:
- g_object_unref (tl);
- g_object_unref (result);
+ if (tl)
+ g_object_unref (tl);
+ if (result)
+ g_object_unref (result);
+ if (sensitivity)
+ g_object_unref (sensitivity);
gnm_solver_set_status (sol, GNM_SOLVER_STATUS_ERROR);
}
@@ -238,9 +371,18 @@ gnm_glpk_prepare (GnmSolver *sol, WorkbookControl *wbc, GError **err,
_("Failed to create file for solution"));
goto fail;
}
-
close (fd);
+ if (sol->params->options.sensitivity_report) {
+ fd = g_file_open_tmp ("program-XXXXXX.ran", &lp->ranges_filename, err);
+ if (fd == -1) {
+ g_set_error (err, G_FILE_ERROR, 0,
+ _("Failed to create file for sensitivity report"));
+ goto fail;
+ }
+ close (fd);
+ }
+
gnm_solver_set_status (sol, GNM_SOLVER_STATUS_PREPARED);
return TRUE;
@@ -257,7 +399,7 @@ gnm_glpk_start (GnmSolver *sol, WorkbookControl *wbc, GError **err,
{
GnmSubSolver *subsol = GNM_SUB_SOLVER (sol);
gboolean ok;
- gchar *argv[7];
+ gchar *argv[9];
int argc = 0;
GnmSolverParameters *param = sol->params;
const char *binary;
@@ -274,6 +416,10 @@ gnm_glpk_start (GnmSolver *sol, WorkbookControl *wbc, GError **err,
: "--noscale");
argv[argc++] = (gchar *)"--write";
argv[argc++] = lp->result_filename;
+ if (lp->ranges_filename) {
+ argv[argc++] = (gchar *)"--ranges";
+ argv[argc++] = lp->ranges_filename;
+ }
argv[argc++] = (gchar *)"--cpxlp";
argv[argc++] = subsol->program_filename;
argv[argc] = NULL;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]