[gnumeric] Solver: add beginnings of solver reports.
- From: Morten Welinder <mortenw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnumeric] Solver: add beginnings of solver reports.
- Date: Mon, 9 Jul 2012 03:43:16 +0000 (UTC)
commit 56d5724e3036cf89dad2d63728a5e2bf214b3d48
Author: Morten Welinder <terra gnome org>
Date: Sun Jul 8 23:42:20 2012 -0400
Solver: add beginnings of solver reports.
This work is incomplete. Notably it's missing undo support.
But people seem to like solver reports so let's get going.
src/dialogs/ChangeLog | 5 +
src/dialogs/dialog-solver.c | 13 +++
src/tools/ChangeLog | 7 ++
src/tools/dao.c | 14 ++-
src/tools/gnm-solver.c | 248 +++++++++++++++++++++++++++++++++++++++++++
src/tools/gnm-solver.h | 2 +
6 files changed, 284 insertions(+), 5 deletions(-)
---
diff --git a/src/dialogs/ChangeLog b/src/dialogs/ChangeLog
index 91b1497..d36545c 100644
--- a/src/dialogs/ChangeLog
+++ b/src/dialogs/ChangeLog
@@ -1,3 +1,8 @@
+2012-07-08 Morten Welinder <terra gnome org>
+
+ * dialog-solver.c (run_solver): Create a report when requested.
+ No undo support yet.
+
2012-06-25 Morten Welinder <terra gnome org>
* Release 1.11.4
diff --git a/src/dialogs/dialog-solver.c b/src/dialogs/dialog-solver.c
index 090d8e6..9f261a8 100644
--- a/src/dialogs/dialog-solver.c
+++ b/src/dialogs/dialog-solver.c
@@ -630,6 +630,16 @@ cb_timer_tick (SolverState *state)
return TRUE;
}
+static void
+create_report (GnmSolver *sol, SolverState *state)
+{
+ Sheet *sheet = state->sheet;
+ char *base = g_strdup_printf ("%s Report", sheet->name_unquoted);
+ gnm_solver_create_report (sol, base);
+ g_free (base);
+}
+
+
static GnmSolverResult *
run_solver (SolverState *state, GnmSolverParameters *param)
{
@@ -800,6 +810,9 @@ run_solver (SolverState *state, GnmSolverParameters *param)
GOUndo *redo;
gnm_solver_store_result (sol);
+ if (param->options.program_report)
+ create_report (sol, state);
+
redo = clipboard_copy_range_undo (sr.sheet, &sr.range);
cmd_generic (WORKBOOK_CONTROL (state->wbcg),
_("Running solver"),
diff --git a/src/tools/ChangeLog b/src/tools/ChangeLog
index 866c213..a969be6 100644
--- a/src/tools/ChangeLog
+++ b/src/tools/ChangeLog
@@ -1,3 +1,10 @@
+2012-07-08 Morten Welinder <terra gnome org>
+
+ * gnm-solver.c (gnm_solver_create_report): New function.
+ Incomplete.
+
+ * dao.c (dao_prepare_output): Improve this for missing ->wbc.
+
2012-06-30 Morten Welinder <terra gnome org>
* gnm-solver.c (gnm_sub_solver_locate_binary): Mark various
diff --git a/src/tools/dao.c b/src/tools/dao.c
index 53f4035..f7d433d 100644
--- a/src/tools/dao.c
+++ b/src/tools/dao.c
@@ -85,6 +85,7 @@ dao_init (data_analysis_output_t *dao,
dao->retain_format = FALSE;
dao->retain_comments = FALSE;
dao->put_formulas = FALSE;
+ dao->wbc = NULL;
dao->sos = NULL;
dao->omit_so = FALSE;
@@ -248,8 +249,10 @@ dao_prepare_output (WorkbookControl *wbc, data_analysis_output_t *dao,
dao->wbc = wbc;
if (dao->type == NewSheetOutput) {
- Sheet *old_sheet = wb_control_cur_sheet (dao->wbc);
- Workbook *wb = wb_control_get_workbook (dao->wbc);
+ Sheet *old_sheet = dao->wbc
+ ? wb_control_cur_sheet (dao->wbc)
+ : dao->sheet;
+ Workbook *wb = old_sheet->workbook;
char *name_with_counter = g_strdup_printf ("%s (1)", name);
unique_name = workbook_sheet_get_free_name
(wb, name_with_counter, FALSE, TRUE);
@@ -270,7 +273,9 @@ dao_prepare_output (WorkbookControl *wbc, data_analysis_output_t *dao,
workbook_sheet_attach (wb, dao->sheet);
dao->wbc = wb_control_wrapper_new (dao->wbc, NULL, wb, NULL);
}
- wb_view_sheet_focus (wb_control_view (dao->wbc), dao->sheet);
+
+ if (dao->wbc)
+ wb_view_sheet_focus (wb_control_view (dao->wbc), dao->sheet);
if (dao->rows == 0 || (dao->rows == 1 && dao->cols == 1))
dao->rows = gnm_sheet_get_max_rows (dao->sheet) - dao->start_row;
@@ -678,8 +683,7 @@ dao_autofit_columns (data_analysis_output_t *dao)
* @row2:
* @style:
*
- * sets the given cell range to bold
- *
+ * Applies a partial style to the given region.
*
**/
static void
diff --git a/src/tools/gnm-solver.c b/src/tools/gnm-solver.c
index 0a61a55..e27ac9d 100644
--- a/src/tools/gnm-solver.c
+++ b/src/tools/gnm-solver.c
@@ -11,6 +11,7 @@
#include "workbook-view.h"
#include "workbook-control.h"
#include "gnm-marshalers.h"
+#include "dao.h"
#include <gsf/gsf-impl-utils.h>
#include <gsf/gsf-output-stdio.h>
#include <glib/gi18n-lib.h>
@@ -618,6 +619,24 @@ gnm_solver_param_valid (GnmSolverParameters const *sp, GError **err)
return TRUE;
}
+static char *
+gnm_solver_param_cell_name (GnmSolverParameters const *sp, GnmCell const *cell)
+{
+ GnmConventionsOut out;
+ GnmCellRef cr;
+ GnmParsePos pp;
+
+ gnm_cellref_init (&cr, cell->base.sheet,
+ cell->pos.col, cell->pos.row,
+ TRUE);
+ out.accum = g_string_new (NULL);
+ out.pp = parse_pos_init_sheet (&pp, sp->sheet);
+ out.convs = sheet_get_conventions (sp->sheet);
+ cellref_as_string (&out, &cr, cell->base.sheet == sp->sheet);
+ return g_string_free (out.accum, FALSE);
+}
+
+
static GObject *
gnm_solver_param_constructor (GType type,
guint n_construct_properties,
@@ -1229,6 +1248,235 @@ gnm_solver_saveas (GnmSolver *solver, WorkbookControl *wbc,
return TRUE;
}
+static gboolean
+cell_in_cr (GnmCell const *cell, GnmSheetRange *sr, gboolean follow,
+ int *px, int *py)
+{
+ if (!cell)
+ return FALSE;
+
+ if (sr->sheet != cell->base.sheet ||
+ !range_contains (&sr->range, cell->pos.col, cell->pos.row)) {
+ /* If the expression is just =X42 thenm look at X42 instead.
+ This is because the mps loader uses such a level of
+ indirection. Note: we follow only one such step. */
+ GnmCellRef const *cr = gnm_expr_top_get_cellref (cell->base.texpr);
+ GnmCellRef cr2;
+ GnmCell const *new_cell;
+ GnmEvalPos ep;
+
+ if (!cr)
+ return FALSE;
+
+ eval_pos_init_cell (&ep, cell);
+ gnm_cellref_make_abs (&cr2, cr, &ep);
+ new_cell = sheet_cell_get (eval_sheet (cr2.sheet, cell->base.sheet),
+ cr2.col, cr2.row);
+ return cell_in_cr (new_cell, sr, FALSE, px, py);
+
+ }
+
+ *px = cell->pos.col - sr->range.start.col;
+ *py = cell->pos.row - sr->range.start.row;
+ return TRUE;
+}
+
+static gboolean
+cell_is_constant (GnmCell const *cell, gnm_float *pc)
+{
+ if (!cell)
+ return TRUE;
+
+ if (cell->base.texpr)
+ return FALSE;
+
+ *pc = value_get_as_float (cell->value);
+ return TRUE;
+}
+
+#define SET_LOWER(l_) \
+ do { \
+ (*pmin)[y * w + x] = MAX ((*pmin)[y * w + x], (l_)); \
+ } while (0)
+
+#define SET_UPPER(l_) \
+ do { \
+ (*pmax)[y * w + x] = MIN ((*pmax)[y * w + x], (l_)); \
+ } while (0)
+
+
+
+static void
+gnm_solver_get_limits (GnmSolver *solver, gnm_float **pmin, gnm_float **pmax)
+{
+ GnmValue const *vinput;
+ GnmSolverParameters *params = solver->params;
+ int x, y, w, h;
+ GnmSheetRange sr;
+ GSList *l;
+
+ *pmin = *pmax = NULL;
+
+ vinput = gnm_solver_param_get_input (params);
+ if (!vinput) return;
+
+ gnm_sheet_range_from_value (&sr, vinput);
+ if (!sr.sheet) sr.sheet = params->sheet;
+ h = range_height (&sr.range);
+ w = range_width (&sr.range);
+
+ *pmin = g_new (gnm_float, h * w);
+ *pmax = g_new (gnm_float, h * w);
+
+ for (x = 0; x < w; x++) {
+ for (y = 0; y < h; y++) {
+ (*pmin)[y * w + x] = params->options.assume_non_negative ? 0 : gnm_ninf;
+ (*pmax)[y * w + x] = gnm_pinf;
+ }
+ }
+
+ for (l = params->constraints; l; l = l->next) {
+ GnmSolverConstraint *c = l->data;
+ int i;
+ gnm_float cl, cr;
+ GnmCell *lhs, *rhs;
+
+ for (i = 0;
+ gnm_solver_constraint_get_part (c, params, i,
+ &lhs, &cl,
+ &rhs, &cr);
+ i++) {
+ if (!cell_in_cr (lhs, &sr, TRUE, &x, &y))
+ continue;
+ if (!cell_is_constant (rhs, &cr))
+ continue;
+
+ switch (c->type) {
+ case GNM_SOLVER_INTEGER:
+ break;
+ case GNM_SOLVER_BOOLEAN:
+ SET_LOWER (0.0);
+ SET_UPPER (1.0);
+ break;
+ case GNM_SOLVER_LE:
+ SET_UPPER (cr);
+ break;
+ case GNM_SOLVER_GE:
+ SET_LOWER (cr);
+ break;
+ case GNM_SOLVER_EQ:
+ SET_LOWER (cr);
+ SET_UPPER (cr);
+ break;
+
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ }
+ }
+
+}
+
+#undef SET_LOWER
+#undef SET_UPPER
+
+#define ADD_HEADER(txt_) do { \
+ dao_set_cell (dao, 0, R, (txt_)); \
+ dao_set_bold (dao, 0, R, 0, R); \
+ R++; \
+} while (0)
+
+#define AT_LIMIT(s_,l_) \
+ (gnm_finite (l_) ? gnm_abs ((s_) - (l_)) <= (gnm_abs ((s_)) + gnm_abs ((l_))) / 1e10 : (s_) == (l_))
+
+void
+gnm_solver_create_report (GnmSolver *solver, const char *name)
+{
+ GnmSolverParameters *params = solver->params;
+ int R = 0;
+ GnmValue const *vinput;
+ data_analysis_output_t *dao;
+ char *tmp;
+
+ dao = dao_init_new_sheet (NULL);
+ dao->sheet = params->sheet;
+ dao_prepare_output (NULL, dao, name);
+
+ /* ---------------------------------------- */
+
+ ADD_HEADER (_("Target"));
+ tmp = gnm_solver_param_cell_name (params,
+ gnm_solver_param_get_target_cell (params));
+ dao_set_cell (dao, 1, R, tmp);
+ g_free (tmp);
+
+ dao_set_cell_float (dao, 2, R, solver->result->value);
+ R++;
+ R++;
+
+ /* ---------------------------------------- */
+
+ vinput = gnm_solver_param_get_input (params);
+ if (vinput) {
+ int x, y, w, h;
+ GnmSheetRange sr;
+ gnm_float *pmin, *pmax;
+
+ ADD_HEADER (_("Variables"));
+
+ gnm_sheet_range_from_value (&sr, vinput);
+ if (!sr.sheet) sr.sheet = params->sheet;
+ h = range_height (&sr.range);
+ w = range_width (&sr.range);
+
+ gnm_solver_get_limits (solver, &pmin, &pmax);
+
+ for (x = 0; x < w; x++) {
+ for (y = 0; y < h; y++) {
+ int vcol = sr.range.start.col + x;
+ int vrow = sr.range.start.row + y;
+ gnm_float m = pmin[y * w + x];
+ gnm_float M = pmax[y * w + x];
+ GnmValue const *vs = value_area_fetch_x_y (solver->result->solution, x, y, NULL);
+ gnm_float s = value_get_as_float (vs);
+ dao_set_cell (dao, 1, R, cell_coord_name (vcol, vrow));
+ dao_set_cell_value (dao, 2, R, value_dup (vs));
+ if (gnm_finite (m))
+ dao_set_cell_float (dao, 3, R, m);
+ else
+ dao_set_cell (dao, 3, R, "-");
+
+ if (gnm_finite (M))
+ dao_set_cell_float (dao, 4, R, M);
+ else
+ dao_set_cell (dao, 4, R, "-");
+
+ if (AT_LIMIT (s, m) || AT_LIMIT (s, M))
+ dao_set_cell (dao, 5, R, _("At limit"));
+
+
+ if (s < m || s > M)
+ dao_set_cell (dao, 6, R, _("Outside bounds"));
+
+ R++;
+ }
+ }
+
+ g_free (pmin);
+ g_free (pmax);
+ R++;
+ }
+
+ /* ---------------------------------------- */
+
+ dao_free (dao);
+}
+
+#undef AT_LIMIT
+#undef ADD_HEADER
+
+
static void
gnm_solver_class_init (GObjectClass *object_class)
{
diff --git a/src/tools/gnm-solver.h b/src/tools/gnm-solver.h
index 162ec16..3fb1281 100644
--- a/src/tools/gnm-solver.h
+++ b/src/tools/gnm-solver.h
@@ -228,6 +228,8 @@ void gnm_solver_set_reason (GnmSolver *solver, const char *reason);
void gnm_solver_store_result (GnmSolver *solver);
+void gnm_solver_create_report (GnmSolver *solver, const char *name);
+
double gnm_solver_elapsed (GnmSolver *solver);
gboolean gnm_solver_check_timeout (GnmSolver *solver);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]