Пример #1
0
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;
}
Пример #2
0
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);
}