Commit ed708582 authored by Jukka-Pekka Iivonen's avatar Jukka-Pekka Iivonen Committed by jpekka

Implemented the results and reports dialog for the Solver tool.

2000-02-02  Jukka-Pekka Iivonen  <iivonen@iki.fi>

	* src/dialogs/dialog-solver.c, src/dialogs/solver.glade:
 	Implemented the results and reports dialog for the Solver tool.

	* src/solver-lp.c, src/solver.h: Implemented `Answer' report
 	generation for Solver.
parent b010f47d
2000-02-02 Jukka-Pekka Iivonen <iivonen@iki.fi>
* src/dialogs/dialog-solver.c, src/dialogs/solver.glade:
Implemented the results and reports dialog for the Solver tool.
* src/solver-lp.c, src/solver.h: Implemented `Answer' report
generation for Solver.
2000-02-02 Jukka-Pekka Iivonen <iivonen@iki.fi>
* src/dialogs/dialog-autocorrect.c: Killed bug #5719.
......
......@@ -4,6 +4,8 @@ Jukka:
* Added `>=' and `=' constraint support for the Solver tool.
Solver should be quite usable now for LP problems that are
assumed to be non-negative.
* Implemented `Answer Reports' for Solver tool.
* Major GUI improvementes for Solver
* Added `Advanced Filter' tool.
* Added the following distributions for the random number
generation tool:
......
2000-02-02 Jukka-Pekka Iivonen <iivonen@iki.fi>
* src/dialogs/dialog-solver.c, src/dialogs/solver.glade:
Implemented the results and reports dialog for the Solver tool.
* src/solver-lp.c, src/solver.h: Implemented `Answer' report
generation for Solver.
2000-02-02 Jukka-Pekka Iivonen <iivonen@iki.fi>
* src/dialogs/dialog-autocorrect.c: Killed bug #5719.
......
......@@ -3,6 +3,8 @@
*
* Author:
* Jukka-Pekka Iivonen <iivonen@iki.fi>
*
* (C) Copyright 2000 by Jukka-Pekka Iivonen <iivonen@iki.fi>
*/
#include <config.h>
......@@ -414,6 +416,140 @@ min_toggled(GtkWidget *widget, SolverParameters *data)
}
}
static void
original_values_toggled(GtkWidget *widget, gboolean *data)
{
if (GTK_TOGGLE_BUTTON (widget)->active)
*data = FALSE;
else
*data = TRUE;
}
static void
solver_values_toggled(GtkWidget *widget, gboolean *data)
{
if (GTK_TOGGLE_BUTTON (widget)->active)
*data = TRUE;
else
*data = FALSE;
}
static void
report_button_toggled(GtkWidget *widget, gboolean *data)
{
*data = GTK_TOGGLE_BUTTON (widget)->active;
}
static gboolean
dialog_results (Workbook *wb, int res,
gboolean *answer, gboolean *sensitivity, gboolean *limits)
{
GladeXML *gui = glade_xml_new (GNUMERIC_GLADEDIR "/solver.glade",
NULL);
GtkWidget *dialog;
GtkWidget *label;
GtkWidget *checkbutton1;
GtkWidget *checkbutton2;
GtkWidget *checkbutton3;
GtkWidget *radiobutton3;
GtkWidget *radiobutton4;
gchar *label_txt = "";
gboolean answer_s, sensitivity_s, limits_s;
gboolean keep_solver_solution;
int selection;
answer_s = sensitivity_s = limits_s = FALSE;
switch (res){
case SIMPLEX_DONE:
answer_s = TRUE;
label_txt = "Solver found an optimal solution. All "
"constraints and \noptimality conditions are satisfied.";
break;
case SIMPLEX_UNBOUNDED:
label_txt = "The Target Cell value does not converge.\n";
break;
default:
break;
}
if (!gui) {
printf ("Could not find solver.glade\n");
return FALSE;
}
dialog = glade_xml_get_widget (gui, "SolverResults");
label = glade_xml_get_widget (gui, "result-label");
checkbutton1 = glade_xml_get_widget (gui, "checkbutton1");
checkbutton2 = glade_xml_get_widget (gui, "checkbutton2");
checkbutton3 = glade_xml_get_widget (gui, "checkbutton3");
radiobutton3 = glade_xml_get_widget (gui, "radiobutton3");
radiobutton4 = glade_xml_get_widget (gui, "radiobutton4");
gtk_signal_connect (GTK_OBJECT (checkbutton1), "toggled",
GTK_SIGNAL_FUNC (report_button_toggled), answer);
gtk_signal_connect (GTK_OBJECT (checkbutton2), "toggled",
GTK_SIGNAL_FUNC (report_button_toggled),
sensitivity);
gtk_signal_connect (GTK_OBJECT (checkbutton3), "toggled",
GTK_SIGNAL_FUNC (report_button_toggled), limits);
gtk_signal_connect (GTK_OBJECT (radiobutton3), "toggled",
GTK_SIGNAL_FUNC (solver_values_toggled),
&keep_solver_solution);
gtk_signal_connect (GTK_OBJECT (radiobutton4), "toggled",
GTK_SIGNAL_FUNC (original_values_toggled),
&keep_solver_solution);
gtk_label_set_text (GTK_LABEL (label), label_txt);
gtk_widget_set_sensitive (checkbutton1, answer_s);
gtk_widget_set_sensitive (checkbutton2, sensitivity_s);
gtk_widget_set_sensitive (checkbutton3, limits_s);
/* Run the dialog */
selection = gnumeric_dialog_run (wb, GNOME_DIALOG (dialog));
if (selection != -1)
gtk_object_destroy (GTK_OBJECT (dialog));
gtk_object_unref (GTK_OBJECT (gui));
return keep_solver_solution;
}
static GSList *
save_original_values (CellList *input_cells)
{
GSList *ov = NULL;
while (input_cells != NULL) {
Cell *cell = (Cell *) input_cells->data;
char *str;
str = value_get_as_string (cell->value);
ov = g_slist_append (ov, str);
input_cells = input_cells->next;
}
return ov;
}
static void
restore_original_values (CellList *input_cells, GSList *ov)
{
while (ov != NULL) {
const char *str = (char *) ov->data;
Cell *cell = (Cell *) input_cells->data;
cell_set_text (cell, str);
ov = ov->next;
input_cells = input_cells->next;
}
}
void
dialog_solver (Workbook *wb, Sheet *sheet)
......@@ -427,7 +563,8 @@ dialog_solver (Workbook *wb, Sheet *sheet)
GtkWidget *constr_add_button;
GtkWidget *constr_change_button;
GtkWidget *constr_delete_button;
GSList *cur;
GSList *cur, *ov;
gboolean solver_solution;
static constraint_dialog_t *constraint_dialog = NULL;
static gchar *target_entry_str = NULL;
......@@ -435,10 +572,12 @@ dialog_solver (Workbook *wb, Sheet *sheet)
const char *text;
int selection, res;
float_t ov_target;
Cell *target_cell;
CellList *input_cells;
int target_cell_col, target_cell_row;
int error_flag;
gboolean answer, sensitivity, limits;
if (!gui) {
printf ("Could not find solver.glade\n");
......@@ -565,6 +704,7 @@ main_dialog:
target_cell_row);
cell_set_text (target_cell, "");
}
ov_target = value_get_as_float (target_cell->value);
/* Parse input cells entry */
text = gtk_entry_get_text (GTK_ENTRY (input_entry));
......@@ -585,23 +725,22 @@ main_dialog:
sheet->solver_parameters.input_cells = input_cells;
sheet->solver_parameters.constraints = constraint_dialog->constraints;
switch (selection) {
case 0: /* Solve */
if (1 ||sheet->solver_parameters.options.assume_linear_model) {
if (selection == 0) {
ov = save_original_values (input_cells);
if (sheet->solver_parameters.options.assume_linear_model) {
res = solver_simplex(wb, sheet);
if (res == SIMPLEX_UNBOUNDED) {
gnumeric_notice (wb, GNOME_MESSAGE_BOX_ERROR,
_("The problem is unbounded "
"and cannot be solved"));
break;
}
gtk_widget_hide (dialog);
answer = sensitivity = limits = FALSE;
solver_solution = dialog_results (wb, res,
&answer,
&sensitivity,
&limits);
solver_lp_reports (wb, sheet, ov, ov_target,
answer, sensitivity, limits);
if (! solver_solution)
restore_original_values (input_cells, ov);
} else
; /* NLP not implemented yet */
break;
case 2: /* Options */
default:
break;
}
text = gtk_entry_get_text (GTK_ENTRY (target_entry));
......
......@@ -914,4 +914,206 @@
</widget>
</widget>
<widget>
<class>GnomeDialog</class>
<name>SolverResults</name>
<visible>False</visible>
<type>GTK_WINDOW_TOPLEVEL</type>
<position>GTK_WIN_POS_NONE</position>
<modal>False</modal>
<allow_shrink>False</allow_shrink>
<allow_grow>False</allow_grow>
<auto_shrink>False</auto_shrink>
<auto_close>False</auto_close>
<hide_on_close>False</hide_on_close>
<widget>
<class>GtkVBox</class>
<child_name>GnomeDialog:vbox</child_name>
<name>dialog-vbox3</name>
<homogeneous>False</homogeneous>
<spacing>8</spacing>
<child>
<padding>4</padding>
<expand>True</expand>
<fill>True</fill>
</child>
<widget>
<class>GtkVBox</class>
<name>vbox4</name>
<homogeneous>False</homogeneous>
<spacing>0</spacing>
<child>
<padding>0</padding>
<expand>True</expand>
<fill>True</fill>
</child>
<widget>
<class>GtkLabel</class>
<name>result-label</name>
<label></label>
<justify>GTK_JUSTIFY_LEFT</justify>
<wrap>False</wrap>
<xalign>0.5</xalign>
<yalign>0.5</yalign>
<xpad>0</xpad>
<ypad>0</ypad>
<child>
<padding>0</padding>
<expand>False</expand>
<fill>False</fill>
</child>
</widget>
<widget>
<class>GtkFrame</class>
<name>frame2</name>
<label>Reports:</label>
<label_xalign>0</label_xalign>
<shadow_type>GTK_SHADOW_ETCHED_IN</shadow_type>
<child>
<padding>0</padding>
<expand>True</expand>
<fill>True</fill>
</child>
<widget>
<class>GtkVBox</class>
<name>vbox5</name>
<homogeneous>False</homogeneous>
<spacing>0</spacing>
<widget>
<class>GtkCheckButton</class>
<name>checkbutton1</name>
<can_focus>True</can_focus>
<label>Answer</label>
<active>False</active>
<draw_indicator>True</draw_indicator>
<child>
<padding>0</padding>
<expand>False</expand>
<fill>False</fill>
</child>
</widget>
<widget>
<class>GtkCheckButton</class>
<name>checkbutton2</name>
<can_focus>True</can_focus>
<label>Sensitivity</label>
<active>False</active>
<draw_indicator>True</draw_indicator>
<child>
<padding>0</padding>
<expand>False</expand>
<fill>False</fill>
</child>
</widget>
<widget>
<class>GtkCheckButton</class>
<name>checkbutton3</name>
<can_focus>True</can_focus>
<label>Limits</label>
<active>False</active>
<draw_indicator>True</draw_indicator>
<child>
<padding>0</padding>
<expand>False</expand>
<fill>False</fill>
</child>
</widget>
</widget>
</widget>
<widget>
<class>GtkFrame</class>
<name>frame3</name>
<label_xalign>0</label_xalign>
<shadow_type>GTK_SHADOW_ETCHED_IN</shadow_type>
<child>
<padding>0</padding>
<expand>True</expand>
<fill>True</fill>
</child>
<widget>
<class>GtkVBox</class>
<name>vbox6</name>
<homogeneous>False</homogeneous>
<spacing>0</spacing>
<widget>
<class>GtkRadioButton</class>
<name>radiobutton3</name>
<can_focus>True</can_focus>
<label>Keep Solver Solution</label>
<active>False</active>
<draw_indicator>True</draw_indicator>
<group>solution</group>
<child>
<padding>0</padding>
<expand>False</expand>
<fill>False</fill>
</child>
</widget>
<widget>
<class>GtkRadioButton</class>
<name>radiobutton4</name>
<can_focus>True</can_focus>
<label>Restore Original Values</label>
<active>False</active>
<draw_indicator>True</draw_indicator>
<group>solution</group>
<child>
<padding>0</padding>
<expand>False</expand>
<fill>False</fill>
</child>
</widget>
</widget>
</widget>
</widget>
<widget>
<class>GtkHButtonBox</class>
<child_name>GnomeDialog:action_area</child_name>
<name>dialog-action_area3</name>
<layout_style>GTK_BUTTONBOX_END</layout_style>
<spacing>8</spacing>
<child_min_width>85</child_min_width>
<child_min_height>27</child_min_height>
<child_ipad_x>7</child_ipad_x>
<child_ipad_y>0</child_ipad_y>
<child>
<padding>0</padding>
<expand>False</expand>
<fill>True</fill>
<pack>GTK_PACK_END</pack>
</child>
<widget>
<class>GtkButton</class>
<name>button7</name>
<can_default>True</can_default>
<has_default>True</has_default>
<can_focus>True</can_focus>
<stock_button>GNOME_STOCK_BUTTON_OK</stock_button>
</widget>
<widget>
<class>GtkButton</class>
<name>button8</name>
<can_default>True</can_default>
<can_focus>True</can_focus>
<stock_button>GNOME_STOCK_BUTTON_CANCEL</stock_button>
</widget>
</widget>
</widget>
</widget>
</GTK-Interface>
......@@ -15,6 +15,8 @@
#include "func.h"
#include "cell.h"
#include "eval.h"
#include "dialogs.h"
#include "mstyle.h"
......@@ -160,7 +162,7 @@ static int
simplex_step_three(float_t *table, int col, int tbl_cols, int tbl_rows,
int *status)
{
float_t a, min, test;
float_t a, min=0, test;
int i, min_i=-1;
table += tbl_cols;
......@@ -292,3 +294,202 @@ int solver_simplex (Workbook *wb, Sheet *sheet)
return SIMPLEX_DONE;
}
static char *
find_name (Sheet *sheet, int col, int row)
{
static char *str = NULL;
Cell *cell;
char *col_str, *row_str;
int col_n, row_n;
for (col_n = col-1; col_n >= 0; col_n--) {
cell = sheet_cell_get (sheet, col_n, row);
if (cell && !VALUE_IS_NUMBER (cell->value))
break;
}
if (col_n >= 0)
col_str = value_get_as_string (cell->value);
else
col_str = g_strdup ("");
for (row_n = row-1; row_n >= 0; row_n--) {
cell = sheet_cell_get (sheet, col, row_n);
if (cell && !VALUE_IS_NUMBER (cell->value))
break;
}
if (row_n >= 0)
row_str = value_get_as_string (cell->value);
else
row_str = g_strdup ("");
if (str)
g_free (str);
str = g_new (char, strlen(col_str) + strlen(row_str) + 2);
if (*col_str)
sprintf(str, "%s %s", col_str, row_str);
else
sprintf(str, "%s", row_str);
g_free (col_str);
g_free (row_str);
return str;
}
static void
solver_answer_report (Workbook *wb, Sheet *sheet, GSList *ov,
float_t ov_target)
{
data_analysis_output_t dao;
SolverParameters *param = &sheet->solver_parameters;
GSList *constraints;
CellList *cell_list = param->input_cells;
Cell *cell;
char buf[256];
char *str;
int row;
dao.type = NewSheetOutput;
prepare_output (wb, &dao, "Answer");
set_cell (&dao, 0, 0, "Gnumeric Solver Answer Report");
if (param->problem_type == SolverMaximize)
set_cell (&dao, 0, 1, "Target Cell (Maximize)");
else
set_cell (&dao, 0, 1, "Target Cell (Minimize)");
set_cell (&dao, 0, 2, "Cell");
set_cell (&dao, 1, 2, "Name");
set_cell (&dao, 2, 2, "Original Value");
set_cell (&dao, 3, 2, "Final Value");
/* Set `Cell' field */
set_cell (&dao, 0, 3, (char*) cell_name(param->target_cell->col->pos,
param->target_cell->row->pos));
/* Set `Name' field */
set_cell (&dao, 1, 3, find_name (sheet, param->target_cell->col->pos,
param->target_cell->row->pos));
/* Set `Original Value' field */
sprintf (buf, "%f", ov_target);
set_cell (&dao, 2, 3, buf);
/* Set `Final Value' field */
cell = sheet_cell_fetch (sheet, param->target_cell->col->pos,
param->target_cell->row->pos);
str = value_get_as_string (cell->value);
set_cell (&dao, 3, 3, str);
g_free (str);
row = 4;
set_cell (&dao, 0, row++, "Adjustable Cells");
set_cell (&dao, 0, row, "Cell");
set_cell (&dao, 1, row, "Name");
set_cell (&dao, 2, row, "Original Value");
set_cell (&dao, 3, row, "Final Value");
row++;
while (cell_list != NULL) {
char *str = (char *) ov->data;
cell = (Cell *) cell_list->data;
/* Set `Cell' column */
set_cell (&dao, 0, row, (char *) cell_name(cell->col->pos,
cell->row->pos));
/* Set `Name' column */
set_cell (&dao, 1, row, find_name (sheet, cell->col->pos,
cell->row->pos));
/* Set `Original Value' column */
set_cell (&dao, 2, row, str);
/* Set `Final Value' column */
cell = sheet_cell_fetch (sheet, cell->col->pos,
cell->row->pos);
str = value_get_as_string (cell->value);
set_cell (&dao, 3, row, str);
g_free (str);
/* Go to next row */
cell_list = cell_list->next;
ov = ov->next;
row++;
}
set_cell (&dao, 0, row++, "Constraints");
set_cell (&dao, 0, row, "Cell");
set_cell (&dao, 1, row, "Name");
set_cell (&dao, 2, row, "Cell Value");
set_cell (&dao, 3, row, "Formula");
set_cell (&dao, 4, row, "Status");
set_cell (&dao, 5, row, "Slack");
row++;
constraints = param->constraints;
while (constraints != NULL) {
SolverConstraint *c = (SolverConstraint *) constraints->data;
float_t lhs, rhs;
/* Set `Cell' column */
set_cell (&dao, 0, row,
(char *) cell_name (c->lhs_col, c->lhs_row));
/* Set `Name' column */
set_cell (&dao, 1, row, find_name (sheet, c->lhs_col,
c->lhs_row));