static gboolean cb_read_stdout (GIOChannel *channel, GIOCondition cond, GnmLPSolve *lp) { const char obj_line_prefix[] = "Value of objective function:"; size_t obj_line_len = sizeof (obj_line_prefix) - 1; const char val_header_line[] = "Actual values of the variables:"; size_t val_header_len = sizeof (val_header_line) - 1; do { GIOStatus status; gchar *line = NULL; gsize tpos; status = g_io_channel_read_line (channel, &line, NULL, &tpos, NULL); if (status != G_IO_STATUS_NORMAL) break; line[tpos] = 0; if (line[0] == 0 || g_ascii_isspace (line[0])) lp->section = SEC_UNKNOWN; else if (lp->section == SEC_UNKNOWN && !strncmp (line, obj_line_prefix, obj_line_len)) { GnmSolverResult *r; gnm_lpsolve_flush_solution (lp); r = gnm_lpsolve_start_solution (lp); r->quality = GNM_SOLVER_RESULT_FEASIBLE; r->value = g_ascii_strtod (line + obj_line_len, NULL); } else if (lp->section == SEC_UNKNOWN && !strncmp (line, val_header_line, val_header_len)) { lp->section = SEC_VALUES; } else if (lp->section == SEC_VALUES && lp->result) { GnmSolverResult *r = lp->result; int x, y; double v; char *space = strchr (line, ' '); GnmCell *cell; if (!space) { lp->section = SEC_UNKNOWN; continue; } *space = 0; cell = gnm_sub_solver_find_cell (lp->parent, line); if (!cell) { g_printerr ("Strange cell %s in output\n", line); lp->section = SEC_UNKNOWN; continue; } v = g_ascii_strtod (space + 1, NULL); x = cell->pos.col - lp->srinput.range.start.col; y = cell->pos.row - lp->srinput.range.start.row; if (x >= 0 && x < value_area_get_width (r->solution, NULL) && y >= 0 && y < value_area_get_height (r->solution, NULL)) value_array_set (r->solution, x, y, value_new_float (v)); } g_free (line); } while (1); return TRUE; }
static void gnm_glpk_read_solution (GnmGlpk *lp) { GnmSubSolver *subsol = lp->parent; GnmSolver *sol = GNM_SOLVER (subsol); GsfInput *input; GsfInputTextline *tl = NULL; const char *line; GnmSolverResult *result = NULL; GnmSolverSensitivity *sensitivity = NULL; enum { SEC_UNKNOWN, SEC_ROWS, SEC_COLUMNS } state; gboolean has_integer; GSList *l; input = gsf_input_stdio_new (lp->result_filename, NULL); if (!input) goto fail; tl = GSF_INPUT_TEXTLINE (gsf_input_textline_new (input)); g_object_unref (input); result = g_object_new (GNM_SOLVER_RESULT_TYPE, NULL); result->solution = g_new0 (gnm_float, sol->input_cells->len); sensitivity = gnm_solver_sensitivity_new (sol); /* * glpsol's output format is different if there are any integer * constraint. Go figure. */ has_integer = sol->params->options.assume_discrete; for (l = sol->params->constraints; !has_integer && l; l = l->next) { GnmSolverConstraint *c = l->data; has_integer = (c->type == GNM_SOLVER_INTEGER || c->type == GNM_SOLVER_BOOLEAN); } switch (gnm_glpk_detect_version (lp, tl)) { case GLPK_457: if (gnm_glpk_read_solution_457 (lp, tl, result, sensitivity, has_integer)) goto fail; break; case GLPK_458: if (gnm_glpk_read_solution_458 (lp, tl, result, sensitivity, has_integer)) goto fail; break; default: goto fail; } 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); return; fail: 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); }