[gnumeric] solver: namespace and code moving.



commit d4f2fc4f368c3d6c00d15c5e52a266d59b1aa1ae
Author: Morten Welinder <terra gnome org>
Date:   Thu Nov 12 14:36:58 2009 -0500

    solver: namespace and code moving.

 plugins/lpsolve/gnm-lpsolve.c    |    4 +-
 plugins/lpsolve/lpsolve-write.c  |   13 +-
 plugins/mps/mps.c                |    6 +-
 src/dialogs/dialog-solver.c      |  142 ++----------
 src/gnm-plugin.c                 |    6 +-
 src/gnumeric.h                   |    2 +-
 src/sheet.h                      |    2 +-
 src/solver.h                     |   71 +------
 src/tools/gnm-solver.c           |  477 ++++++++++++++++++++++++++++++++++++-
 src/tools/gnm-solver.h           |   88 +++++++-
 src/tools/solver/Makefile.am     |    2 -
 src/tools/solver/api.c           |    2 +-
 src/tools/solver/api.h           |    2 +-
 src/tools/solver/reports-write.c |   20 +-
 src/tools/solver/reports.c       |  343 --------------------------
 src/tools/solver/reports.h       |   13 -
 src/tools/solver/solver.c        |  491 +-------------------------------------
 src/xml-sax-write.c              |    2 +-
 18 files changed, 608 insertions(+), 1078 deletions(-)
---
diff --git a/plugins/lpsolve/gnm-lpsolve.c b/plugins/lpsolve/gnm-lpsolve.c
index ea8f956..85b56b9 100644
--- a/plugins/lpsolve/gnm-lpsolve.c
+++ b/plugins/lpsolve/gnm-lpsolve.c
@@ -266,10 +266,10 @@ gnm_lpsolve_stop (GnmSolver *sol, GError *err, GnmLPSolve *lp)
 }
 
 GnmSolver *
-lpsolve_solver_factory (GnmSolverFactory *factory, SolverParameters *params);
+lpsolve_solver_factory (GnmSolverFactory *factory, GnmSolverParameters *params);
 
 GnmSolver *
-lpsolve_solver_factory (GnmSolverFactory *factory, SolverParameters *params)
+lpsolve_solver_factory (GnmSolverFactory *factory, GnmSolverParameters *params)
 {
 	GnmSolver *res = g_object_new (GNM_SUB_SOLVER_TYPE,
 					  "params", params,
diff --git a/plugins/lpsolve/lpsolve-write.c b/plugins/lpsolve/lpsolve-write.c
index a8d8f1e..6cbbdd4 100644
--- a/plugins/lpsolve/lpsolve-write.c
+++ b/plugins/lpsolve/lpsolve-write.c
@@ -154,7 +154,7 @@ fail:
 static GString *
 lpsolve_create_program (Sheet *sheet, GOIOContext *io_context, GError **err)
 {
-	SolverParameters *sp = sheet->solver_parameters;
+	GnmSolverParameters *sp = sheet->solver_parameters;
 	GString *prg = NULL;
 	GString *constraints = g_string_new (NULL);
 	GString *declarations = g_string_new (NULL);
@@ -176,17 +176,10 @@ lpsolve_create_program (Sheet *sheet, GOIOContext *io_context, GError **err)
 	/* ---------------------------------------- */
 
 	switch (sp->problem_type) {
-	case SolverEqualTo:
-		if (!lpsolve_affine_func (constraints, target_cell,
-					  input_cells, err))
-			goto fail;
-		/* FIXME -- what value goes here?  */
-		g_string_append (constraints, " = 42;\n");
-		/* Fall through */
-	case SolverMinimize:
+	case GNM_SOLVER_MINIMIZE:
 		g_string_append (objfunc, "min: ");
 		break;
-	case SolverMaximize:
+	case GNM_SOLVER_MAXIMIZE:
 		g_string_append (objfunc, "max: ");
 		break;
 	default:
diff --git a/plugins/mps/mps.c b/plugins/mps/mps.c
index 016f032..613d806 100644
--- a/plugins/mps/mps.c
+++ b/plugins/mps/mps.c
@@ -274,7 +274,7 @@ mps_write_sheet_labels (MpsInputContext *ctxt, Sheet *sh)
 
 static void
 mps_write_coefficients (MpsInputContext *ctxt, Sheet *sh,
-			SolverParameters *param)
+			GnmSolverParameters *param)
 {
 	GSList  *current;
 	int     i, n, r, ecol, inc2;
@@ -448,7 +448,7 @@ mps_create_sheet (MpsInputContext *ctxt, WorkbookView *wbv)
         Sheet            *sh = wbv->current_sheet;
 	gint             i;
 	int              n_rows_per_fn;
-	SolverParameters *param = sh->solver_parameters;
+	GnmSolverParameters *param = sh->solver_parameters;
 	const char *row_name =
 		ctxt->objective_row
 		? ctxt->objective_row->name
@@ -480,7 +480,7 @@ mps_create_sheet (MpsInputContext *ctxt, WorkbookView *wbv)
 
 	gnm_cellref_init (&cr, NULL, OBJECTIVE_VALUE_COL, MAIN_INFO_ROW, TRUE);
 	gnm_solver_param_set_target (param, &cr);
-	param->problem_type = SolverMinimize;
+	param->problem_type = GNM_SOLVER_MINIMIZE;
 
 	/* Write the name of the program. */
 	if (ctxt->name != NULL)
diff --git a/src/dialogs/dialog-solver.c b/src/dialogs/dialog-solver.c
index e08162a..52ffbe6 100644
--- a/src/dialogs/dialog-solver.c
+++ b/src/dialogs/dialog-solver.c
@@ -133,7 +133,7 @@ dialog_set_sec_button_sensitivity (G_GNUC_UNUSED GtkWidget *dummy,
 	gboolean select_ready = (state->constr != NULL);
 	GnmSolverConstraint *test = gnm_solver_constraint_new (NULL);
 	gboolean ready, has_rhs;
-	SolverParameters const *param = state->sheet->solver_parameters;
+	GnmSolverParameters const *param = state->sheet->solver_parameters;
 
 	constraint_fill (test, state);
 	ready = gnm_solver_constraint_valid (test, param);
@@ -213,7 +213,7 @@ cb_dialog_delete_clicked (G_GNUC_UNUSED GtkWidget *button, SolverState *state)
 	if (state->constr != NULL) {
 		GtkTreeIter iter;
 		GtkTreeModel *store;
-		SolverParameters *param = state->sheet->solver_parameters;
+		GnmSolverParameters *param = state->sheet->solver_parameters;
 
 		param->constraints =
 			g_slist_remove (param->constraints, state->constr);
@@ -247,7 +247,7 @@ cb_dialog_add_clicked (SolverState *state)
 	if (dialog_set_sec_button_sensitivity (NULL, state)) {
 		GtkTreeIter   iter;
 		GtkListStore *store = GTK_LIST_STORE (gtk_tree_view_get_model (state->constraint_list));
-		SolverParameters *param = state->sheet->solver_parameters;
+		GnmSolverParameters *param = state->sheet->solver_parameters;
 
 		gtk_list_store_append (store, &iter);
 		state->constr = gnm_solver_constraint_new (state->sheet);
@@ -285,7 +285,7 @@ dialog_set_main_button_sensitivity (G_GNUC_UNUSED GtkWidget *dummy,
 }
 
 static gboolean
-fill_algorithm_combo (SolverState *state, SolverModelType type)
+fill_algorithm_combo (SolverState *state, GnmSolverModelType type)
 {
 	GtkListStore *store =
 		gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_POINTER);
@@ -328,7 +328,7 @@ static void
 cb_dialog_model_type_clicked (G_GNUC_UNUSED GtkWidget *button,
 			      SolverState *state)
 {
-	SolverModelType type;
+	GnmSolverModelType type;
 	gboolean any;
 
 	type = gnumeric_glade_group_value (state->gui, model_type_group);
@@ -368,117 +368,6 @@ cb_dialog_close_clicked (G_GNUC_UNUSED GtkWidget *button,
 	gtk_widget_destroy (state->dialog);
 }
 
-/* Returns FALSE if the reports deleted the current sheet
- * and forced the dialog to die */
-static gboolean
-solver_reporting (SolverState *state, SolverResults *res)
-{
-	SolverOptions *opt = &res->param->options;
-	gchar         *err = NULL;
-
-	g_object_add_weak_pointer (G_OBJECT (state->dialog), (gpointer)&state);
-	switch (res->status) {
-	case SolverOptimal :
-		go_gtk_notice_nonmodal_dialog
-			((GtkWindow *) state->dialog,
-			 &(state->warning_dialog),
-			 GTK_MESSAGE_INFO,
-			 _("Solver found an optimal solution.  All "
-			   "constraints and optimality conditions are "
-			   "satisfied.\n"));
-		if ((opt->sensitivity_report || opt->limits_report)
-		    && res->ilp_flag)
-			go_gtk_notice_nonmodal_dialog
-				((GtkWindow *) state->dialog,
-				 &(state->warning_dialog),
-				 GTK_MESSAGE_INFO,
-				 _("Neither sensitivity nor limits report are "
-				   "meaningful if the program has "
-				   "integer constraints.  These reports "
-				   "will not be created."));
-		err = solver_reports (WORKBOOK_CONTROL(state->wbcg),
-				      state->sheet, res,
-				      opt->answer_report,
-				      opt->sensitivity_report,
-				      opt->limits_report,
-				      opt->performance_report,
-				      opt->program_report,
-				      opt->dual_program_report);
-		break;
-	case SolverUnbounded :
-		go_gtk_notice_nonmodal_dialog
-			((GtkWindow *) state->dialog,
-			 &(state->warning_dialog),
-			 GTK_MESSAGE_WARNING,
-			 _("The Target Cell value specified does not "
-			   "converge!  The program is unbounded."));
-		err = solver_reports (WORKBOOK_CONTROL(state->wbcg),
-				      state->sheet, res,
-				      FALSE, FALSE, FALSE,
-				      opt->performance_report,
-				      opt->program_report,
-				      opt->dual_program_report);
-		break;
-	case SolverInfeasible :
-		go_gtk_notice_nonmodal_dialog
-			((GtkWindow *) state->dialog,
-			 &(state->warning_dialog),
-			 GTK_MESSAGE_WARNING,
-			 _("A feasible solution could not be found.  "
-			   "All specified constraints cannot be met "
-			   "simultaneously. "));
-		err = solver_reports (WORKBOOK_CONTROL(state->wbcg),
-				      state->sheet, res,
-				      FALSE, FALSE, FALSE,
-				      opt->performance_report,
-				      opt->program_report,
-				      opt->dual_program_report);
-		break;
-	case SolverMaxIterExc :
-		go_gtk_notice_nonmodal_dialog
-			((GtkWindow *) state->dialog,
-			 &(state->warning_dialog),
-			 GTK_MESSAGE_ERROR,
-			 _("The maximum number of iterations exceeded. "
-			   "The optimal value could not be found."));
-		err = solver_reports (WORKBOOK_CONTROL(state->wbcg),
-				      state->sheet, res,
-				      FALSE, FALSE, FALSE,
-				      opt->performance_report,
-				      opt->program_report,
-				      opt->dual_program_report);
-		break;
-	case SolverMaxTimeExc :
-		go_gtk_notice_nonmodal_dialog
-			((GtkWindow *) state->dialog,
-			 &(state->warning_dialog),
-			 GTK_MESSAGE_ERROR,
-			 SOLVER_MAX_TIME_ERR);
-		err = solver_reports (WORKBOOK_CONTROL(state->wbcg),
-				      state->sheet, res,
-				      FALSE, FALSE, FALSE,
-				      opt->performance_report,
-				      opt->program_report,
-				      opt->dual_program_report);
-		break;
-	default:
-		go_gtk_notice_nonmodal_dialog
-			((GtkWindow *) state->dialog,
-			 &(state->warning_dialog),
-			 GTK_MESSAGE_ERROR,
-			 _("Unknown error."));
-		break;
-	}
-	if (NULL != state)
-		g_object_remove_weak_pointer (G_OBJECT (state->dialog), (gpointer)&state);
-
-	if (err)
-		go_gtk_notice_nonmodal_dialog (state ? ((GtkWindow *) state->dialog) : NULL,
-			 &(state->warning_dialog), GTK_MESSAGE_ERROR, err);
-
-	return state != NULL;
-}
-
 static void
 cb_stop_solver (SolverState *state)
 {
@@ -604,7 +493,7 @@ cb_timer_tick (SolverState *state)
 }
 
 static GnmSolverResult *
-run_solver (SolverState *state, SolverParameters *param)
+run_solver (SolverState *state, GnmSolverParameters *param)
 {
 	GtkDialog *dialog;
 	GtkWidget *hbox;
@@ -752,7 +641,7 @@ fail:
 static void
 solver_add_scenario (SolverState *state, SolverResults *res, gchar const *name)
 {
-	SolverParameters *param = res->param;
+	GnmSolverParameters *param = res->param;
 	GnmValue         *input_range;
 	gchar const      *comment = _("Optimal solution created by solver.\n");
 	scenario_t       *scenario;
@@ -784,7 +673,7 @@ cb_dialog_solve_clicked (G_GNUC_UNUSED GtkWidget *button,
 	gboolean                answer, sensitivity, limits, performance;
 	gboolean                program, dual_program;
 	GError *err = NULL;
-	SolverParameters        *param;
+	GnmSolverParameters        *param;
 	GtkTreeIter iter;
 	GnmCell *target_cell;
 	GnmSolverFactory *factory = NULL;
@@ -875,12 +764,11 @@ cb_dialog_solve_clicked (G_GNUC_UNUSED GtkWidget *button,
 	workbook_recalc (state->sheet->workbook);
 
 	if (res != NULL) {
-		SolverResults *oldres;
+		SolverResults *oldres = NULL;
 		/* WARNING : The dialog may be deleted by the reports
 		 * solver_reporting will return FALSE if state is gone and cleared */
 		if (0 &&
-		    solver_reporting (state, oldres) &&
-		    oldres->status == SolverOptimal &&
+		    res->quality == GNM_SOLVER_RESULT_OPTIMAL &&
 		    param->options.add_scenario)
 			solver_add_scenario (state, oldres,
 					     param->options.scenario_name);
@@ -912,7 +800,7 @@ static gboolean
 dialog_init (SolverState *state)
 {
 	GtkTable                *table;
-	SolverParameters        *param;
+	GnmSolverParameters        *param;
 	GtkCellRenderer *renderer;
 	GtkListStore *store;
 	GtkTreeViewColumn *column;
@@ -1154,16 +1042,16 @@ dialog_init (SolverState *state)
 					       cell_name (target_cell));
 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (
 		glade_xml_get_widget(state->gui, "max_button")),
-			param->problem_type == SolverMaximize);
+			param->problem_type == GNM_SOLVER_MAXIMIZE);
 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (
 		glade_xml_get_widget(state->gui, "min_button")),
-			param->problem_type == SolverMinimize);
+			param->problem_type == GNM_SOLVER_MINIMIZE);
 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (
 		glade_xml_get_widget(state->gui, "lp_model_button")),
-			param->options.model_type == SolverLPModel);
+			param->options.model_type == GNM_SOLVER_LP);
 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (
 		glade_xml_get_widget(state->gui, "qp_model_button")),
-			param->options.model_type == SolverQPModel);
+			param->options.model_type == GNM_SOLVER_QP);
 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (
 		glade_xml_get_widget(state->gui, "no_scenario")),
 			! param->options.add_scenario);
diff --git a/src/gnm-plugin.c b/src/gnm-plugin.c
index 5796100..240462c 100644
--- a/src/gnm-plugin.c
+++ b/src/gnm-plugin.c
@@ -486,7 +486,7 @@ struct _PluginServiceSolver {
 };
 
 static GnmSolver *
-cb_load_and_create (GnmSolverFactory *factory, SolverParameters *param)
+cb_load_and_create (GnmSolverFactory *factory, GnmSolverParameters *param)
 {
 	PluginServiceSolver *ssol =
 		g_object_get_data (G_OBJECT (factory), "ssol");
@@ -539,14 +539,14 @@ plugin_service_solver_read_xml (GOPluginService *service, xmlNode *tree,
 {
 	PluginServiceSolver *ssol = GNM_PLUGIN_SERVICE_SOLVER (service);
 	xmlChar *s_id, *s_name, *s_type;
-	SolverProblemType type = SolverLPModel;
+	GnmSolverProblemType type = GNM_SOLVER_LP;
 	xmlNode *information_node;
 
 	GO_INIT_RET_ERROR_INFO (ret_error);
 
 	s_type = go_xml_node_get_cstr (tree, "problem_type");
 	if (s_type && strcmp (CXML2C (s_type), "mip") == 0)
-		type = SolverLPModel;
+		type = GNM_SOLVER_LP;
 	else {
 		*ret_error = go_error_info_new_str (_("Invalid solver problem type."));
 		return;
diff --git a/src/gnumeric.h b/src/gnumeric.h
index 559cc7c..8ae267c 100644
--- a/src/gnumeric.h
+++ b/src/gnumeric.h
@@ -183,7 +183,7 @@ typedef struct _GnmSheetSlicer		GnmSheetSlicer;
 
 typedef struct _PrintInformation        PrintInformation;
 
-typedef struct _SolverParameters	SolverParameters;
+typedef struct GnmSolverParameters_	GnmSolverParameters;
 typedef struct GnmSolverConstraint_     GnmSolverConstraint;
 typedef struct GnmSolverFactory_        GnmSolverFactory;
 
diff --git a/src/sheet.h b/src/sheet.h
index 1dc56bb..78181f1 100644
--- a/src/sheet.h
+++ b/src/sheet.h
@@ -94,7 +94,7 @@ struct _Sheet {
 
 	gboolean    has_filtered_rows;
 
-        SolverParameters *solver_parameters;
+        GnmSolverParameters *solver_parameters;
 	GList            *scenarios;
 
 	gint simulation_round;
diff --git a/src/solver.h b/src/solver.h
index 3066a61..38b2c85 100644
--- a/src/solver.h
+++ b/src/solver.h
@@ -14,75 +14,6 @@ G_BEGIN_DECLS
 
 /* -------------------------------------------------------------------------- */
 
-typedef enum {
-	SolverLPModel, SolverQPModel, SolverNLPModel
-} SolverModelType;
-
-typedef enum {
-	LPSolve = 0, GLPKSimplex, QPDummy
-} SolverAlgorithmType;
-
-typedef struct {
-	int                 max_time_sec;
-	int                 max_iter;
-	GnmSolverFactory   *algorithm;
-	SolverModelType     model_type;
-	gboolean            assume_non_negative;
-	gboolean            assume_discrete;
-	gboolean            automatic_scaling;
-	gboolean            show_iter_results;
-	gboolean            answer_report;
-	gboolean            sensitivity_report;
-	gboolean            limits_report;
-	gboolean            performance_report;
-	gboolean            program_report;
-	gboolean            dual_program_report;
-	gboolean            add_scenario;
-	gchar               *scenario_name;
-} SolverOptions;
-
-/* -------------------------------------------------------------------------- */
-
-typedef enum {
-        SolverMinimize, SolverMaximize, SolverEqualTo
-} SolverProblemType;
-
-struct _SolverParameters {
-	SolverProblemType  problem_type;
-	Sheet             *sheet;
-	GnmDependent       target;
-	GnmDependent       input;
-	GSList             *constraints;
-	int                n_constraints;
-	int                n_variables;
-	int                n_int_constraints;
-	int                n_bool_constraints;
-	int                n_total_constraints;
-	SolverOptions      options;
-};
-
-/* Creates a new SolverParameters object. */
-SolverParameters *gnm_solver_param_new (Sheet *sheet);
-
-/* Duplicate a SolverParameters object. */
-SolverParameters *gnm_solver_param_dup (SolverParameters const *src_param,
-					Sheet *new_sheet);
-
-/* Frees the memory resources in the solver parameter structure. */
-void gnm_solver_param_free (SolverParameters *sp);
-
-GnmValue const *gnm_solver_param_get_input (SolverParameters const *sp);
-void gnm_solver_param_set_input (SolverParameters *sp, GnmValue *v);
-GSList *gnm_solver_param_get_input_cells (SolverParameters const *sp);
-
-const GnmCellRef *gnm_solver_param_get_target (SolverParameters const *sp);
-void gnm_solver_param_set_target (SolverParameters *sp, GnmCellRef const *cr);
-GnmCell *gnm_solver_param_get_target_cell (SolverParameters const *sp);
-
-gboolean gnm_solver_param_valid (SolverParameters const *sp, GError **err);
-
-/* -------------------------------------------------------------------------- */
-
 #ifdef GNM_ENABLE_SOLVER
 
 typedef enum {
@@ -135,7 +66,7 @@ typedef struct {
         gnm_float       *obj_coeff;
         gnm_float       **constr_coeff;
         SolverLimits     *limits;
-        SolverParameters *param;
+        GnmSolverParameters *param;
 } SolverResults;
 
 
diff --git a/src/tools/gnm-solver.c b/src/tools/gnm-solver.c
index 187a5c5..2eb544b 100644
--- a/src/tools/gnm-solver.c
+++ b/src/tools/gnm-solver.c
@@ -2,6 +2,7 @@
 #include "gnumeric.h"
 #include "value.h"
 #include "cell.h"
+#include "expr.h"
 #include "sheet.h"
 #include "workbook.h"
 #include "ranges.h"
@@ -63,6 +64,478 @@ gnm_solver_status_get_type (void)
 
 /* ------------------------------------------------------------------------- */
 
+GnmSolverConstraint *
+gnm_solver_constraint_new (Sheet *sheet)
+{
+	GnmSolverConstraint *res = g_new0 (GnmSolverConstraint, 1);
+	dependent_managed_init (&res->lhs, sheet);
+	dependent_managed_init (&res->rhs, sheet);
+	return res;
+}
+
+void
+gnm_solver_constraint_free (GnmSolverConstraint *c)
+{
+	gnm_solver_constraint_set_lhs (c, NULL);
+	gnm_solver_constraint_set_rhs (c, NULL);
+	g_free (c);
+}
+
+GnmSolverConstraint *
+gnm_solver_constraint_dup (GnmSolverConstraint *c, Sheet *sheet)
+{
+	GnmSolverConstraint *res = gnm_solver_constraint_new (sheet);
+	res->type = c->type;
+	dependent_managed_set_expr (&res->lhs, res->lhs.texpr);
+	dependent_managed_set_expr (&res->rhs, res->lhs.texpr);
+	return res;
+}
+
+gboolean
+gnm_solver_constraint_has_rhs (GnmSolverConstraint const *c)
+{
+	g_return_val_if_fail (c != NULL, FALSE);
+
+	switch (c->type) {
+	case GNM_SOLVER_LE:
+	case GNM_SOLVER_GE:
+	case GNM_SOLVER_EQ:
+		return TRUE;
+	case GNM_SOLVER_INTEGER:
+	case GNM_SOLVER_BOOLEAN:
+	default:
+		return FALSE;
+	}
+}
+
+gboolean
+gnm_solver_constraint_valid (GnmSolverConstraint const *c,
+			     GnmSolverParameters const *sp)
+{
+	GnmValue const *lhs;
+
+	g_return_val_if_fail (c != NULL, FALSE);
+
+	lhs = gnm_solver_constraint_get_lhs (c);
+	if (lhs == NULL || lhs->type != VALUE_CELLRANGE)
+		return FALSE;
+
+	if (gnm_solver_constraint_has_rhs (c)) {
+		GnmValue const *rhs = gnm_solver_constraint_get_lhs (c);
+		if (rhs == NULL)
+			return FALSE;
+		if (rhs->type == VALUE_CELLRANGE) {
+			GnmRange rl, rr;
+
+			range_init_value (&rl, lhs);
+			range_init_value (&rr, rhs);
+
+			if (range_width (&rl) != range_width (&rr) ||
+			    range_height (&rl) != range_height (&rr))
+				return FALSE;
+		} else if (VALUE_IS_FLOAT (rhs)) {
+			/* Nothing */
+		} else
+			return FALSE;
+	}
+
+	switch (c->type) {
+	case GNM_SOLVER_INTEGER:
+	case GNM_SOLVER_BOOLEAN: {
+		GnmValue const *vinput = gnm_solver_param_get_input (sp);
+		GnmSheetRange sr_input, sr_c;
+
+		if (!vinput)
+			break; /* No need to blame contraint.  */
+
+		gnm_sheet_range_from_value (&sr_input, vinput);
+		gnm_sheet_range_from_value (&sr_c, lhs);
+
+		if (eval_sheet (sr_input.sheet, sp->sheet) !=
+		    eval_sheet (sr_c.sheet, sp->sheet) ||
+		    !range_contained (&sr_c.range, &sr_input.range))
+			return FALSE;
+		break;
+	}
+
+	default:
+		break;
+	}
+
+	return TRUE;
+}
+
+GnmValue const *
+gnm_solver_constraint_get_lhs (GnmSolverConstraint const *c)
+{
+	GnmExprTop const *texpr = c->lhs.texpr;
+	return texpr ? gnm_expr_top_get_constant (texpr) : NULL;
+}
+
+void
+gnm_solver_constraint_set_lhs (GnmSolverConstraint *c, GnmValue *v)
+{
+	/* Takes ownership.  */
+	GnmExprTop const *texpr = v ? gnm_expr_top_new_constant (v) : NULL;
+	dependent_managed_set_expr (&c->lhs, texpr);
+	if (texpr) gnm_expr_top_unref (texpr);
+}
+
+GnmValue const *
+gnm_solver_constraint_get_rhs (GnmSolverConstraint const *c)
+{
+	GnmExprTop const *texpr = c->rhs.texpr;
+	return texpr ? gnm_expr_top_get_constant (texpr) : NULL;
+}
+
+void
+gnm_solver_constraint_set_rhs (GnmSolverConstraint *c, GnmValue *v)
+{
+	/* Takes ownership.  */
+	GnmExprTop const *texpr = v ? gnm_expr_top_new_constant (v) : NULL;
+	dependent_managed_set_expr (&c->rhs, texpr);
+	if (texpr) gnm_expr_top_unref (texpr);
+}
+
+gboolean
+gnm_solver_constraint_get_part (GnmSolverConstraint const *c,
+				GnmSolverParameters const *sp, int i,
+				GnmCell **lhs, gnm_float *cl,
+				GnmCell **rhs, gnm_float *cr)
+{
+	GnmRange r;
+	int h, w, dx, dy;
+	GnmValue const *vl, *vr;
+
+	if (cl)	*cl = 0;
+	if (cr)	*cr = 0;
+	if (lhs) *lhs = NULL;
+	if (rhs) *rhs = NULL;
+
+	if (!gnm_solver_constraint_valid (c, sp))
+		return FALSE;
+
+	vl = gnm_solver_constraint_get_lhs (c);
+	vr = gnm_solver_constraint_get_rhs (c);
+
+	range_init_value (&r, vl);
+	w = range_width (&r);
+	h = range_height (&r);
+
+	dy = i / w;
+	dx = i % w;
+	if (dy >= h)
+		return FALSE;
+
+	if (lhs)
+		*lhs = sheet_cell_get (sp->sheet,
+				       r.start.col + dx, r.start.row + dy);
+
+	if (gnm_solver_constraint_has_rhs (c)) {
+		if (VALUE_IS_FLOAT (vr)) {
+			if (cr)
+				*cr = value_get_as_float (vr);
+		} else {
+			range_init_value (&r, vr);
+			if (rhs)
+				*rhs = sheet_cell_get (sp->sheet,
+						       r.start.col + dx,
+						       r.start.row + dy);
+		}
+	}
+
+	return TRUE;
+}
+
+void
+gnm_solver_constraint_set_old (GnmSolverConstraint *c,
+			       GnmSolverConstraintType type,
+			       int lhs_col, int lhs_row,
+			       int rhs_col, int rhs_row,
+			       int cols, int rows)
+{
+	GnmRange r;
+
+	c->type = type;
+
+	range_init (&r,
+		    lhs_col, lhs_row,
+		    lhs_col + (cols - 1), lhs_row + (rows - 1));
+	gnm_solver_constraint_set_lhs
+		(c, value_new_cellrange_r (NULL, &r));
+
+	if (gnm_solver_constraint_has_rhs (c)) {
+		range_init (&r,
+			    rhs_col, rhs_row,
+			    rhs_col + (cols - 1), rhs_row + (rows - 1));
+		gnm_solver_constraint_set_rhs
+			(c, value_new_cellrange_r (NULL, &r));
+	} else
+		gnm_solver_constraint_set_rhs (c, NULL);
+}
+
+void
+gnm_solver_constraint_side_as_str (GnmSolverConstraint const *c,
+				   Sheet const *sheet,
+				   GString *buf, gboolean lhs)
+{
+	GnmExprTop const *texpr;
+
+	texpr = lhs ? c->lhs.texpr : c->rhs.texpr;
+	if (texpr) {
+		GnmConventionsOut out;
+		GnmParsePos pp;
+
+		out.accum = buf;
+		out.pp = parse_pos_init_sheet (&pp, sheet);
+		out.convs = sheet->convs;
+		gnm_expr_top_as_gstring (texpr, &out);
+	} else
+		g_string_append (buf,
+				 value_error_name (GNM_ERROR_REF,
+						   sheet->convs->output.translated));
+}
+
+char *
+gnm_solver_constraint_as_str (GnmSolverConstraint const *c, Sheet *sheet)
+{
+	const char * const type_str[] =	{
+		"\xe2\x89\xa4" /* "<=" */,
+		"\xe2\x89\xa5" /* ">=" */,
+		"=", "Int", "Bool"
+	};
+	GString *buf = g_string_new (NULL);
+
+	gnm_solver_constraint_side_as_str (c, sheet, buf, TRUE);
+	g_string_append_c (buf, ' ');
+	g_string_append (buf, type_str[c->type]);
+	if (gnm_solver_constraint_has_rhs (c)) {
+		g_string_append_c (buf, ' ');
+		gnm_solver_constraint_side_as_str (c, sheet, buf, FALSE);
+	}
+
+	return g_string_free (buf, FALSE);
+}
+
+/* ------------------------------------------------------------------------- */
+
+GnmSolverParameters *
+gnm_solver_param_new (Sheet *sheet)
+{
+	GnmSolverParameters *res = g_new0 (GnmSolverParameters, 1);
+
+	dependent_managed_init (&res->target, sheet);
+	dependent_managed_init (&res->input, sheet);
+
+	res->options.model_type          = GNM_SOLVER_LP;
+	res->sheet                       = sheet;
+	res->options.assume_non_negative = TRUE;
+	res->options.algorithm           = NULL;
+	res->options.scenario_name       = g_strdup ("Optimal");
+	res->problem_type                = GNM_SOLVER_MAXIMIZE;
+	res->constraints                 = NULL;
+	res->constraints		 = NULL;
+
+	return res;
+}
+
+void
+gnm_solver_param_free (GnmSolverParameters *sp)
+{
+	dependent_managed_set_expr (&sp->target, NULL);
+	dependent_managed_set_expr (&sp->input, NULL);
+	go_slist_free_custom (sp->constraints,
+			      (GFreeFunc)gnm_solver_constraint_free);
+	g_free (sp->options.scenario_name);
+	g_free (sp);
+}
+
+GnmSolverParameters *
+gnm_solver_param_dup (const GnmSolverParameters *src_param, Sheet *new_sheet)
+{
+	GnmSolverParameters *dst_param = gnm_solver_param_new (new_sheet);
+	GSList           *constraints;
+
+	dst_param->problem_type = src_param->problem_type;
+	dependent_managed_set_expr (&dst_param->target,
+				    src_param->target.texpr);
+	dependent_managed_set_expr (&dst_param->input,
+				    src_param->input.texpr);
+
+	g_free (dst_param->options.scenario_name);
+	dst_param->options = src_param->options;
+	dst_param->options.scenario_name = g_strdup (src_param->options.scenario_name);
+	/* Had there been any non-scalar options, we'd copy them here.  */
+
+	/* Copy the constraints */
+	for (constraints = src_param->constraints; constraints;
+	     constraints = constraints->next) {
+		GnmSolverConstraint *old = constraints->data;
+		GnmSolverConstraint *new = gnm_solver_constraint_dup (old, new_sheet);
+
+		dst_param->constraints =
+		        g_slist_prepend (dst_param->constraints, new);
+	}
+	dst_param->constraints = g_slist_reverse (dst_param->constraints);
+
+	dst_param->n_constraints       = src_param->n_constraints;
+	dst_param->n_variables         = src_param->n_variables;
+	dst_param->n_int_constraints   = src_param->n_int_constraints;
+	dst_param->n_bool_constraints  = src_param->n_bool_constraints;
+	dst_param->n_total_constraints = src_param->n_total_constraints;
+
+	return dst_param;
+}
+
+GnmValue const *
+gnm_solver_param_get_input (GnmSolverParameters const *sp)
+{
+	return sp->input.texpr
+		? gnm_expr_top_get_constant (sp->input.texpr)
+		: NULL;
+}
+
+void
+gnm_solver_param_set_input (GnmSolverParameters *sp, GnmValue *v)
+{
+	/* Takes ownership.  */
+	GnmExprTop const *texpr = v ? gnm_expr_top_new_constant (v) : NULL;
+	dependent_managed_set_expr (&sp->input, texpr);
+	if (texpr) gnm_expr_top_unref (texpr);
+}
+
+static GnmValue *
+cb_grab_cells (GnmCellIter const *iter, gpointer user)
+{
+	GSList **the_list = user;
+	GnmCell *cell;
+
+	if (NULL == (cell = iter->cell))
+		cell = sheet_cell_create (iter->pp.sheet,
+			iter->pp.eval.col, iter->pp.eval.row);
+	*the_list = g_slist_append (*the_list, cell);
+	return NULL;
+}
+
+GSList *
+gnm_solver_param_get_input_cells (GnmSolverParameters const *sp)
+{
+	GnmValue const *vr = gnm_solver_param_get_input (sp);
+	GSList *input_cells = NULL;
+	GnmEvalPos ep;
+
+	if (!vr)
+		return NULL;
+
+	eval_pos_init_sheet (&ep, sp->sheet);
+	workbook_foreach_cell_in_range (&ep, vr, CELL_ITER_ALL,
+					cb_grab_cells,
+					&input_cells);
+	return input_cells;
+}
+
+void
+gnm_solver_param_set_target (GnmSolverParameters *sp, GnmCellRef const *cr)
+{
+	GnmCellRef cr2 = *cr;
+	GnmExprTop const *texpr;
+
+	/* Make reference absolute to avoid tracking problems on row/col
+	   insert.  */
+	cr2.row_relative = FALSE;
+	cr2.col_relative = FALSE;
+
+	texpr = gnm_expr_top_new (gnm_expr_new_cellref (&cr2));
+	dependent_managed_set_expr (&sp->target, texpr);
+	gnm_expr_top_unref (texpr);
+}
+
+const GnmCellRef *
+gnm_solver_param_get_target (GnmSolverParameters const *sp)
+{
+	return sp->target.texpr
+		? gnm_expr_top_get_cellref (sp->target.texpr)
+		: NULL;
+}
+
+GnmCell *
+gnm_solver_param_get_target_cell (GnmSolverParameters const *sp)
+{
+	const GnmCellRef *cr = gnm_solver_param_get_target (sp);
+	if (!cr)
+		return NULL;
+
+        return sheet_cell_get (eval_sheet (cr->sheet, sp->sheet),
+			       cr->col, cr->row);
+}
+
+gboolean
+gnm_solver_param_valid (GnmSolverParameters const *sp, GError **err)
+{
+	GSList *l;
+	int i;
+	GnmCell *target_cell;
+	GSList *input_cells;
+
+	target_cell = gnm_solver_param_get_target_cell (sp);
+	if (!target_cell) {
+		g_set_error (err,
+			     go_error_invalid (),
+			     0,
+			     _("Invalid solver target"));
+		return FALSE;
+	}
+
+	if (!gnm_cell_has_expr (target_cell) ||
+	    target_cell->value == NULL ||
+	    !VALUE_IS_FLOAT (target_cell->value)) {
+		g_set_error (err,
+			     go_error_invalid (),
+			     0,
+			     _("Target cell, %s, must contain a formula that evaluates to a number"),
+			     cell_name (target_cell));
+		return FALSE;
+	}
+
+	if (!gnm_solver_param_get_input (sp)) {
+		g_set_error (err,
+			     go_error_invalid (),
+			     0,
+			     _("Invalid solver input range"));
+		return FALSE;
+	}
+	input_cells = gnm_solver_param_get_input_cells (sp);
+	for (l = input_cells; l; l = l->next) {
+		GnmCell *cell = l->data;
+		if (gnm_cell_has_expr (cell)) {
+			g_set_error (err,
+				     go_error_invalid (),
+				     0,
+				     _("Input cell %s contains a formula"),
+				     cell_name (cell));
+			g_slist_free (input_cells);
+			return FALSE;
+		}
+	}
+	g_slist_free (input_cells);
+
+	for (i = 1, l = sp->constraints; l; i++, l = l->next) {
+		GnmSolverConstraint *c = l->data;
+		if (!gnm_solver_constraint_valid (c, sp)) {
+			g_set_error (err,
+				     go_error_invalid (),
+				     0,
+				     _("Solver constraint #%d is invalid"),
+				     i);
+			return FALSE;
+		}
+	}
+
+	return TRUE;
+}
+
+/* ------------------------------------------------------------------------- */
+
 enum {
 	SOL_SIG_PREPARE,
 	SOL_SIG_START,
@@ -622,7 +1095,7 @@ gnm_solver_db_get (void)
 GnmSolverFactory *
 gnm_solver_factory_new (const char *id,
 			const char *name,
-			SolverModelType type,
+			GnmSolverModelType type,
 			GnmSolverCreator creator)
 {
 	GnmSolverFactory *res;
@@ -641,7 +1114,7 @@ gnm_solver_factory_new (const char *id,
 
 GnmSolver *
 gnm_solver_factory_create (GnmSolverFactory *factory,
-			   SolverParameters *param)
+			   GnmSolverParameters *param)
 {
 	g_return_val_if_fail (GNM_IS_SOLVER_FACTORY (factory), NULL);
 	return factory->creator (factory, param);
diff --git a/src/tools/gnm-solver.h b/src/tools/gnm-solver.h
index 218f1a5..9f4fbaf 100644
--- a/src/tools/gnm-solver.h
+++ b/src/tools/gnm-solver.h
@@ -31,6 +31,7 @@ typedef enum {
 	GNM_SOLVER_STATUS_CANCELLED
 } GnmSolverStatus;
 
+
 typedef enum {
         GNM_SOLVER_LE,
 	GNM_SOLVER_GE,
@@ -39,6 +40,17 @@ typedef enum {
 	GNM_SOLVER_BOOLEAN
 } GnmSolverConstraintType;
 
+
+typedef enum {
+	GNM_SOLVER_LP, GNM_SOLVER_QP
+} GnmSolverModelType;
+
+
+typedef enum {
+        GNM_SOLVER_MINIMIZE, GNM_SOLVER_MAXIMIZE
+} GnmSolverProblemType;
+
+
 /* -------------------------------------------------------------------------- */
 
 struct GnmSolverConstraint_ {
@@ -53,6 +65,8 @@ struct GnmSolverConstraint_ {
 
 GnmSolverConstraint *gnm_solver_constraint_new (Sheet *sheet);
 void gnm_solver_constraint_free (GnmSolverConstraint *c);
+GnmSolverConstraint *gnm_solver_constraint_dup (GnmSolverConstraint *c,
+						Sheet *sheet);
 
 void gnm_solver_constraint_set_old (GnmSolverConstraint *c,
 				    GnmSolverConstraintType type,
@@ -62,9 +76,9 @@ void gnm_solver_constraint_set_old (GnmSolverConstraint *c,
 
 gboolean gnm_solver_constraint_has_rhs (GnmSolverConstraint const *c);
 gboolean gnm_solver_constraint_valid (GnmSolverConstraint const *c,
-				      SolverParameters const *sp);
+				      GnmSolverParameters const *sp);
 gboolean gnm_solver_constraint_get_part (GnmSolverConstraint const *c,
-					 SolverParameters const *sp, int i,
+					 GnmSolverParameters const *sp, int i,
 					 GnmCell **lhs, gnm_float *cl,
 					 GnmCell **rhs, gnm_float *cr);
 
@@ -81,6 +95,62 @@ char *gnm_solver_constraint_as_str (GnmSolverConstraint const *c, Sheet *sheet);
 
 /* ------------------------------------------------------------------------- */
 
+typedef struct {
+	int                 max_time_sec;
+	int                 max_iter;
+	GnmSolverFactory   *algorithm;
+	GnmSolverModelType  model_type;
+	gboolean            assume_non_negative;
+	gboolean            assume_discrete;
+	gboolean            automatic_scaling;
+	gboolean            show_iter_results;
+	gboolean            answer_report;
+	gboolean            sensitivity_report;
+	gboolean            limits_report;
+	gboolean            performance_report;
+	gboolean            program_report;
+	gboolean            dual_program_report;
+	gboolean            add_scenario;
+	gchar               *scenario_name;
+} GnmSolverOptions;
+
+struct GnmSolverParameters_ {
+	GnmSolverProblemType  problem_type;
+	Sheet                *sheet;
+	GnmDependent          target;
+	GnmDependent          input;
+	GSList                *constraints;
+	int                   n_constraints;
+	int                   n_variables;
+	int                   n_int_constraints;
+	int                   n_bool_constraints;
+	int                   n_total_constraints;
+	GnmSolverOptions         options;
+};
+
+/* Creates a new GnmSolverParameters object. */
+GnmSolverParameters *gnm_solver_param_new (Sheet *sheet);
+
+/* Duplicate a GnmSolverParameters object. */
+GnmSolverParameters *gnm_solver_param_dup (GnmSolverParameters const *src_param,
+					   Sheet *new_sheet);
+
+/* Frees the memory resources in the solver parameter structure. */
+void gnm_solver_param_free (GnmSolverParameters *sp);
+
+GnmValue const *gnm_solver_param_get_input (GnmSolverParameters const *sp);
+void gnm_solver_param_set_input (GnmSolverParameters *sp, GnmValue *v);
+GSList *gnm_solver_param_get_input_cells (GnmSolverParameters const *sp);
+
+const GnmCellRef *gnm_solver_param_get_target (GnmSolverParameters const *sp);
+void gnm_solver_param_set_target (GnmSolverParameters *sp,
+				  GnmCellRef const *cr);
+GnmCell *gnm_solver_param_get_target_cell (GnmSolverParameters const *sp);
+
+gboolean gnm_solver_param_valid (GnmSolverParameters const *sp, GError **err);
+
+/* -------------------------------------------------------------------------- */
+
 #define GNM_SOLVER_RESULT_TYPE   (gnm_solver_result_get_type ())
 #define GNM_SOLVER_RESULT(o)     (G_TYPE_CHECK_INSTANCE_CAST ((o), GNM_SOLVER_RESULT_TYPE, GnmSolverResult))
 
@@ -88,7 +158,11 @@ typedef struct {
 	GObject parent;
 
 	GnmSolverResultQuality quality;
+
+	/* Objective value, if any */
 	gnm_float value;
+
+	/* Array value of solution, if any */
 	GnmValue *solution;
 } GnmSolverResult;
 
@@ -110,7 +184,7 @@ typedef struct {
 	GObject parent;
 
 	GnmSolverStatus status;
-	SolverParameters *params;
+	GnmSolverParameters *params;
 	GnmSolverResult *result;
 } GnmSolver;
 
@@ -195,14 +269,14 @@ void gnm_sub_solver_flush (GnmSubSolver *subsol);
 #define GNM_IS_SOLVER_FACTORY(o)       (G_TYPE_CHECK_INSTANCE_TYPE ((o), GNM_SOLVER_FACTORY_TYPE))
 
 typedef GnmSolver * (*GnmSolverCreator) (GnmSolverFactory *,
-					 SolverParameters *);
+					 GnmSolverParameters *);
 
 struct GnmSolverFactory_ {
 	GObject parent;
 
 	char *id;
 	char *name; /* Already translated */
-	SolverModelType type;
+	GnmSolverModelType type;
 	GnmSolverCreator creator;
 };
 
@@ -214,10 +288,10 @@ GType gnm_solver_factory_get_type (void);
 
 GnmSolverFactory *gnm_solver_factory_new (const char *id,
 					  const char *name,
-					  SolverModelType type,
+					  GnmSolverModelType type,
 					  GnmSolverCreator creator);
 GnmSolver *gnm_solver_factory_create (GnmSolverFactory *factory,
-				      SolverParameters *param);
+				      GnmSolverParameters *param);
 
 GSList *gnm_solver_db_get (void);
 void gnm_solver_db_register (GnmSolverFactory *factory);
diff --git a/src/tools/solver/Makefile.am b/src/tools/solver/Makefile.am
index 98c1b59..73f1970 100644
--- a/src/tools/solver/Makefile.am
+++ b/src/tools/solver/Makefile.am
@@ -16,7 +16,5 @@ libsolver_la_SOURCES =				\
 	api.c					\
 	api.h					\
 	solver.c				\
-	reports.c				\
-	reports.h				\
 	reports-write.h				\
 	reports-write.c
diff --git a/src/tools/solver/api.c b/src/tools/solver/api.c
index b906462..71f27ae 100644
--- a/src/tools/solver/api.c
+++ b/src/tools/solver/api.c
@@ -58,7 +58,7 @@
  */
 
 static SolverProgram
-w_qp_dummy_init (const SolverParameters *param)
+w_qp_dummy_init (const GnmSolverParameters *param)
 {
         printf ("w_qp_dummy_init\n");
 	return NULL;
diff --git a/src/tools/solver/api.h b/src/tools/solver/api.h
index 083a83b..e0c611b 100644
--- a/src/tools/solver/api.h
+++ b/src/tools/solver/api.h
@@ -33,7 +33,7 @@
  * Solver's API for LP solving algorithms
  */
 typedef SolverProgram
-        (solver_init_fn)                (SolverParameters const *param);
+        (solver_init_fn)                (GnmSolverParameters const *param);
 typedef void
         (solver_remove_fn)              (SolverProgram p);
 typedef void
diff --git a/src/tools/solver/reports-write.c b/src/tools/solver/reports-write.c
index 1b71deb..8b0d641 100644
--- a/src/tools/solver/reports-write.c
+++ b/src/tools/solver/reports-write.c
@@ -194,7 +194,7 @@ solver_answer_report (WorkbookControl *wbc,
 	 */
 
 	/* Fill in the column A labels into the answer report sheet. */
-	if (res->param->problem_type == SolverMaximize)
+	if (res->param->problem_type == GNM_SOLVER_MAXIMIZE)
 	        dao_set_cell (&dao, 0, 5, _("Target Cell (Maximize)"));
 	else
 	        dao_set_cell (&dao, 0, 5, _("Target Cell (Minimize)"));
@@ -532,15 +532,12 @@ solver_performance_report (WorkbookControl *wbc,
 
 	/* Print the problem type. */
 	switch (res->param->problem_type) {
-	case SolverMinimize:
+	case GNM_SOLVER_MINIMIZE:
 	        dao_set_cell (&dao, 2, 6, _("Minimization"));
 		break;
-	case SolverMaximize:
+	case GNM_SOLVER_MAXIMIZE:
 	        dao_set_cell (&dao, 2, 6, _("Maximization"));
 		break;
-	case SolverEqualTo:
-	        dao_set_cell (&dao, 2, 6, _("Target value search"));
-		break;
 	}
 
 	/* Print the status. */
@@ -790,7 +787,7 @@ solver_program_report (WorkbookControl *wbc,
 
 	/* Print the objective function. */
 	max_col = 0;
-	if (res->param->options.model_type == SolverLPModel) {
+	if (res->param->options.model_type == GNM_SOLVER_LP) {
 	        /* This is for linear models. */
 	        col = 0;
 		for (i = 0; i < vars; i++) {
@@ -818,7 +815,7 @@ solver_program_report (WorkbookControl *wbc,
 			}
 		}
 	} else {
-	        /* This is for quadratic models. (SolverQPModel) */
+	        /* This is for quadratic models. (GNM_SOLVER_QP) */
 	}
 
 
@@ -921,15 +918,12 @@ solver_program_report (WorkbookControl *wbc,
 
 	/* Print the type of the program. */
 	switch (res->param->problem_type) {
-	case SolverMinimize:
+	case GNM_SOLVER_MINIMIZE:
 	        dao_set_cell (&dao, 0, 5, _("Minimize"));
 		break;
-	case SolverMaximize:
+	case GNM_SOLVER_MAXIMIZE:
 	        dao_set_cell (&dao, 0, 5, _("Maximize"));
 		break;
-	case SolverEqualTo:
-	        dao_set_cell (&dao, 0, 5, _("Equal to"));
-		break;
 	}
 	dao_set_bold (&dao, 0, 5, 0, 5);
 
diff --git a/src/tools/solver/solver.c b/src/tools/solver/solver.c
index 575038d..30bd130 100644
--- a/src/tools/solver/solver.c
+++ b/src/tools/solver/solver.c
@@ -24,7 +24,6 @@
 
 #include <gnumeric-config.h>
 #include <glib/gi18n-lib.h>
-#include "reports.h"
 
 #include "parse-util.h"
 #include "solver.h"
@@ -67,194 +66,13 @@ attr_eq (const xmlChar *a, const char *s)
 
 /* ------------------------------------------------------------------------- */
 
-
-SolverParameters *
-gnm_solver_param_new (Sheet *sheet)
-{
-	SolverParameters *res = g_new0 (SolverParameters, 1);
-
-	dependent_managed_init (&res->target, sheet);
-	dependent_managed_init (&res->input, sheet);
-
-	res->options.model_type          = SolverLPModel;
-	res->sheet                       = sheet;
-	res->options.assume_non_negative = TRUE;
-	res->options.algorithm           = NULL;
-	res->options.scenario_name       = g_strdup ("Optimal");
-	res->problem_type                = SolverMaximize;
-	res->constraints                 = NULL;
-	res->constraints		 = NULL;
-
-	return res;
-}
-
-void
-gnm_solver_param_free (SolverParameters *sp)
-{
-	dependent_managed_set_expr (&sp->target, NULL);
-	dependent_managed_set_expr (&sp->input, NULL);
-	go_slist_free_custom (sp->constraints,
-			      (GFreeFunc)gnm_solver_constraint_free);
-	g_free (sp->options.scenario_name);
-	g_free (sp);
-}
-
-GnmValue const *
-gnm_solver_param_get_input (SolverParameters const *sp)
-{
-	return sp->input.texpr
-		? gnm_expr_top_get_constant (sp->input.texpr)
-		: NULL;
-}
-
-void
-gnm_solver_param_set_input (SolverParameters *sp, GnmValue *v)
-{
-	/* Takes ownership.  */
-	GnmExprTop const *texpr = v ? gnm_expr_top_new_constant (v) : NULL;
-	dependent_managed_set_expr (&sp->input, texpr);
-	if (texpr) gnm_expr_top_unref (texpr);
-}
-
-static GnmValue *
-cb_grab_cells (GnmCellIter const *iter, gpointer user)
-{
-	GSList **the_list = user;
-	GnmCell *cell;
-
-	if (NULL == (cell = iter->cell))
-		cell = sheet_cell_create (iter->pp.sheet,
-			iter->pp.eval.col, iter->pp.eval.row);
-	*the_list = g_slist_append (*the_list, cell);
-	return NULL;
-}
-
-GSList *
-gnm_solver_param_get_input_cells (SolverParameters const *sp)
-{
-	GnmValue const *vr = gnm_solver_param_get_input (sp);
-	GSList *input_cells = NULL;
-	GnmEvalPos ep;
-
-	if (!vr)
-		return NULL;
-
-	eval_pos_init_sheet (&ep, sp->sheet);
-	workbook_foreach_cell_in_range (&ep, vr, CELL_ITER_ALL,
-					cb_grab_cells,
-					&input_cells);
-	return input_cells;
-}
-
-void
-gnm_solver_param_set_target (SolverParameters *sp, GnmCellRef const *cr)
-{
-	GnmCellRef cr2 = *cr;
-	GnmExprTop const *texpr;
-
-	/* Make reference absolute to avoid tracking problems on row/col
-	   insert.  */
-	cr2.row_relative = FALSE;
-	cr2.col_relative = FALSE;
-
-	texpr = gnm_expr_top_new (gnm_expr_new_cellref (&cr2));
-	dependent_managed_set_expr (&sp->target, texpr);
-	gnm_expr_top_unref (texpr);
-}
-
-const GnmCellRef *
-gnm_solver_param_get_target (SolverParameters const *sp)
-{
-	return sp->target.texpr
-		? gnm_expr_top_get_cellref (sp->target.texpr)
-		: NULL;
-}
-
-GnmCell *
-gnm_solver_param_get_target_cell (SolverParameters const *sp)
-{
-	const GnmCellRef *cr = gnm_solver_param_get_target (sp);
-	if (!cr)
-		return NULL;
-
-        return sheet_cell_get (eval_sheet (cr->sheet, sp->sheet),
-			       cr->col, cr->row);
-}
-
-gboolean
-gnm_solver_param_valid (SolverParameters const *sp, GError **err)
-{
-	GSList *l;
-	int i;
-	GnmCell *target_cell;
-	GSList *input_cells;
-
-	target_cell = gnm_solver_param_get_target_cell (sp);
-	if (!target_cell) {
-		g_set_error (err,
-			     go_error_invalid (),
-			     0,
-			     _("Invalid solver target"));
-		return FALSE;
-	}
-
-	if (!gnm_cell_has_expr (target_cell) ||
-	    target_cell->value == NULL ||
-	    !VALUE_IS_FLOAT (target_cell->value)) {
-		g_set_error (err,
-			     go_error_invalid (),
-			     0,
-			     _("Target cell, %s, must contain a formula that evaluates to a number"),
-			     cell_name (target_cell));
-		return FALSE;
-	}
-
-	if (!gnm_solver_param_get_input (sp)) {
-		g_set_error (err,
-			     go_error_invalid (),
-			     0,
-			     _("Invalid solver input range"));
-		return FALSE;
-	}
-	input_cells = gnm_solver_param_get_input_cells (sp);
-	for (l = input_cells; l; l = l->next) {
-		GnmCell *cell = l->data;
-		if (gnm_cell_has_expr (cell)) {
-			g_set_error (err,
-				     go_error_invalid (),
-				     0,
-				     _("Input cell %s contains a formula"),
-				     cell_name (cell));
-			g_slist_free (input_cells);
-			return FALSE;
-		}
-	}
-	g_slist_free (input_cells);
-
-	for (i = 1, l = sp->constraints; l; i++, l = l->next) {
-		GnmSolverConstraint *c = l->data;
-		if (!gnm_solver_constraint_valid (c, sp)) {
-			g_set_error (err,
-				     go_error_invalid (),
-				     0,
-				     _("Solver constraint #%d is invalid"),
-				     i);
-			return FALSE;
-		}
-	}
-
-	return TRUE;
-}
-
-/* ------------------------------------------------------------------------- */
-
 static void
 solver_constr_start (GsfXMLIn *xin, xmlChar const **attrs)
 {
 	int type = 0;
 	GnmSolverConstraint *c;
 	Sheet *sheet = gnm_xml_in_cur_sheet (xin);
-	SolverParameters *sp = sheet->solver_parameters;
+	GnmSolverParameters *sp = sheet->solver_parameters;
 	int lhs_col = 0, lhs_row = 0, rhs_col = 0, rhs_row = 0;
 	int cols = 1, rows = 1;
 	gboolean old = FALSE;
@@ -308,7 +126,7 @@ void
 solver_param_read_sax (GsfXMLIn *xin, xmlChar const **attrs)
 {
 	Sheet *sheet = gnm_xml_in_cur_sheet (xin);
-	SolverParameters *sp = sheet->solver_parameters;
+	GnmSolverParameters *sp = sheet->solver_parameters;
 	int col = -1, row = -1;
 	int ptype;
 	GnmParsePos pp;
@@ -324,7 +142,7 @@ solver_param_read_sax (GsfXMLIn *xin, xmlChar const **attrs)
 
 	for (; attrs && attrs[0] && attrs[1] ; attrs += 2) {
 		if (gnm_xml_attr_int (attrs, "ProblemType", &ptype)) {
-			sp->problem_type = (SolverProblemType)ptype;
+			sp->problem_type = (GnmSolverProblemType)ptype;
 		} else if (attr_eq (attrs[0], "Inputs")) {
 			GnmValue *v = value_new_cellrange_parsepos_str
 				(&pp,
@@ -418,6 +236,16 @@ solver_results_free (SolverResults *res)
 
 /* ------------------------------------------------------------------------- */
 
+gchar *
+solver_reports (WorkbookControl *wbc, Sheet *sheet, SolverResults *res,
+		gboolean answer, gboolean sensitivity, gboolean limits,
+		gboolean performance, gboolean program, gboolean dual)
+{
+	return NULL;
+}
+
+/* ------------------------------------------------------------------------- */
+
 GnmCell *
 solver_get_input_var (SolverResults *res, int n)
 {
@@ -430,297 +258,4 @@ solver_get_constraint (SolverResults *res, int n)
         return res->constraints_array[n];
 }
 
-GnmSolverConstraint *
-gnm_solver_constraint_new (Sheet *sheet)
-{
-	GnmSolverConstraint *res = g_new0 (GnmSolverConstraint, 1);
-	dependent_managed_init (&res->lhs, sheet);
-	dependent_managed_init (&res->rhs, sheet);
-	return res;
-}
-
-void
-gnm_solver_constraint_free (GnmSolverConstraint *c)
-{
-	gnm_solver_constraint_set_lhs (c, NULL);
-	gnm_solver_constraint_set_rhs (c, NULL);
-	g_free (c);
-}
-
-static GnmSolverConstraint *
-gnm_solver_constraint_dup (GnmSolverConstraint *c, Sheet *sheet)
-{
-	GnmSolverConstraint *res = gnm_solver_constraint_new (sheet);
-	res->type = c->type;
-	dependent_managed_set_expr (&res->lhs, res->lhs.texpr);
-	dependent_managed_set_expr (&res->rhs, res->lhs.texpr);
-	return res;
-}
-
-gboolean
-gnm_solver_constraint_has_rhs (GnmSolverConstraint const *c)
-{
-	g_return_val_if_fail (c != NULL, FALSE);
-
-	switch (c->type) {
-	case GNM_SOLVER_LE:
-	case GNM_SOLVER_GE:
-	case GNM_SOLVER_EQ:
-		return TRUE;
-	case GNM_SOLVER_INTEGER:
-	case GNM_SOLVER_BOOLEAN:
-	default:
-		return FALSE;
-	}
-}
-
-gboolean
-gnm_solver_constraint_valid (GnmSolverConstraint const *c,
-			     SolverParameters const *sp)
-{
-	GnmValue const *lhs;
-
-	g_return_val_if_fail (c != NULL, FALSE);
-
-	lhs = gnm_solver_constraint_get_lhs (c);
-	if (lhs == NULL || lhs->type != VALUE_CELLRANGE)
-		return FALSE;
-
-	if (gnm_solver_constraint_has_rhs (c)) {
-		GnmValue const *rhs = gnm_solver_constraint_get_lhs (c);
-		if (rhs == NULL)
-			return FALSE;
-		if (rhs->type == VALUE_CELLRANGE) {
-			GnmRange rl, rr;
-
-			range_init_value (&rl, lhs);
-			range_init_value (&rr, rhs);
-
-			if (range_width (&rl) != range_width (&rr) ||
-			    range_height (&rl) != range_height (&rr))
-				return FALSE;
-		} else if (VALUE_IS_FLOAT (rhs)) {
-			/* Nothing */
-		} else
-			return FALSE;
-	}
-
-	switch (c->type) {
-	case GNM_SOLVER_INTEGER:
-	case GNM_SOLVER_BOOLEAN: {
-		GnmValue const *vinput = gnm_solver_param_get_input (sp);
-		GnmSheetRange sr_input, sr_c;
-
-		if (!vinput)
-			break; /* No need to blame contraint.  */
-
-		gnm_sheet_range_from_value (&sr_input, vinput);
-		gnm_sheet_range_from_value (&sr_c, lhs);
-
-		if (eval_sheet (sr_input.sheet, sp->sheet) !=
-		    eval_sheet (sr_c.sheet, sp->sheet) ||
-		    !range_contained (&sr_c.range, &sr_input.range))
-			return FALSE;
-		break;
-	}
-
-	default:
-		break;
-	}
-
-	return TRUE;
-}
-
-GnmValue const *
-gnm_solver_constraint_get_lhs (GnmSolverConstraint const *c)
-{
-	GnmExprTop const *texpr = c->lhs.texpr;
-	return texpr ? gnm_expr_top_get_constant (texpr) : NULL;
-}
-
-void
-gnm_solver_constraint_set_lhs (GnmSolverConstraint *c, GnmValue *v)
-{
-	/* Takes ownership.  */
-	GnmExprTop const *texpr = v ? gnm_expr_top_new_constant (v) : NULL;
-	dependent_managed_set_expr (&c->lhs, texpr);
-	if (texpr) gnm_expr_top_unref (texpr);
-}
-
-GnmValue const *
-gnm_solver_constraint_get_rhs (GnmSolverConstraint const *c)
-{
-	GnmExprTop const *texpr = c->rhs.texpr;
-	return texpr ? gnm_expr_top_get_constant (texpr) : NULL;
-}
-
-void
-gnm_solver_constraint_set_rhs (GnmSolverConstraint *c, GnmValue *v)
-{
-	/* Takes ownership.  */
-	GnmExprTop const *texpr = v ? gnm_expr_top_new_constant (v) : NULL;
-	dependent_managed_set_expr (&c->rhs, texpr);
-	if (texpr) gnm_expr_top_unref (texpr);
-}
-
-
-gboolean
-gnm_solver_constraint_get_part (GnmSolverConstraint const *c,
-				SolverParameters const *sp, int i,
-				GnmCell **lhs, gnm_float *cl,
-				GnmCell **rhs, gnm_float *cr)
-{
-	GnmRange r;
-	int h, w, dx, dy;
-	GnmValue const *vl, *vr;
-
-	if (cl)	*cl = 0;
-	if (cr)	*cr = 0;
-	if (lhs) *lhs = NULL;
-	if (rhs) *rhs = NULL;
-
-	if (!gnm_solver_constraint_valid (c, sp))
-		return FALSE;
-
-	vl = gnm_solver_constraint_get_lhs (c);
-	vr = gnm_solver_constraint_get_rhs (c);
-
-	range_init_value (&r, vl);
-	w = range_width (&r);
-	h = range_height (&r);
-
-	dy = i / w;
-	dx = i % w;
-	if (dy >= h)
-		return FALSE;
-
-	if (lhs)
-		*lhs = sheet_cell_get (sp->sheet,
-				       r.start.col + dx, r.start.row + dy);
-
-	if (gnm_solver_constraint_has_rhs (c)) {
-		if (VALUE_IS_FLOAT (vr)) {
-			if (cr)
-				*cr = value_get_as_float (vr);
-		} else {
-			range_init_value (&r, vr);
-			if (rhs)
-				*rhs = sheet_cell_get (sp->sheet,
-						       r.start.col + dx,
-						       r.start.row + dy);
-		}
-	}
-
-	return TRUE;
-}
-
-void
-gnm_solver_constraint_set_old (GnmSolverConstraint *c,
-			       GnmSolverConstraintType type,
-			       int lhs_col, int lhs_row,
-			       int rhs_col, int rhs_row,
-			       int cols, int rows)
-{
-	GnmRange r;
-
-	c->type = type;
-
-	range_init (&r,
-		    lhs_col, lhs_row,
-		    lhs_col + (cols - 1), lhs_row + (rows - 1));
-	gnm_solver_constraint_set_lhs
-		(c, value_new_cellrange_r (NULL, &r));
-
-	if (gnm_solver_constraint_has_rhs (c)) {
-		range_init (&r,
-			    rhs_col, rhs_row,
-			    rhs_col + (cols - 1), rhs_row + (rows - 1));
-		gnm_solver_constraint_set_rhs
-			(c, value_new_cellrange_r (NULL, &r));
-	} else
-		gnm_solver_constraint_set_rhs (c, NULL);
-}
-
-/* ------------------------------------------------------------------------- */
-
-void
-gnm_solver_constraint_side_as_str (GnmSolverConstraint const *c,
-				   Sheet const *sheet,
-				   GString *buf, gboolean lhs)
-{
-	GnmExprTop const *texpr;
-
-	texpr = lhs ? c->lhs.texpr : c->rhs.texpr;
-	if (texpr) {
-		GnmConventionsOut out;
-		GnmParsePos pp;
-
-		out.accum = buf;
-		out.pp = parse_pos_init_sheet (&pp, sheet);
-		out.convs = sheet->convs;
-		gnm_expr_top_as_gstring (texpr, &out);
-	} else
-		g_string_append (buf,
-				 value_error_name (GNM_ERROR_REF,
-						   sheet->convs->output.translated));
-}
-
-char *
-gnm_solver_constraint_as_str (GnmSolverConstraint const *c, Sheet *sheet)
-{
-	const char * const type_str[] =	{
-		"\xe2\x89\xa4" /* "<=" */,
-		"\xe2\x89\xa5" /* ">=" */,
-		"=", "Int", "Bool"
-	};
-	GString *buf = g_string_new (NULL);
-
-	gnm_solver_constraint_side_as_str (c, sheet, buf, TRUE);
-	g_string_append_c (buf, ' ');
-	g_string_append (buf, type_str[c->type]);
-	if (gnm_solver_constraint_has_rhs (c)) {
-		g_string_append_c (buf, ' ');
-		gnm_solver_constraint_side_as_str (c, sheet, buf, FALSE);
-	}
-
-	return g_string_free (buf, FALSE);
-}
-
 /* ------------------------------------------------------------------------- */
-
-SolverParameters *
-gnm_solver_param_dup (const SolverParameters *src_param, Sheet *new_sheet)
-{
-	SolverParameters *dst_param = gnm_solver_param_new (new_sheet);
-	GSList           *constraints;
-
-	dst_param->problem_type = src_param->problem_type;
-	dependent_managed_set_expr (&dst_param->target,
-				    src_param->target.texpr);
-	dependent_managed_set_expr (&dst_param->input,
-				    src_param->input.texpr);
-
-	g_free (dst_param->options.scenario_name);
-	dst_param->options = src_param->options;
-	dst_param->options.scenario_name = g_strdup (src_param->options.scenario_name);
-	/* Had there been any non-scalar options, we'd copy them here.  */
-
-	/* Copy the constraints */
-	for (constraints = src_param->constraints; constraints;
-	     constraints = constraints->next) {
-		GnmSolverConstraint *old = constraints->data;
-		GnmSolverConstraint *new = gnm_solver_constraint_dup (old, new_sheet);
-
-		dst_param->constraints =
-		        g_slist_prepend (dst_param->constraints, new);
-	}
-	dst_param->constraints = g_slist_reverse (dst_param->constraints);
-
-	dst_param->n_constraints       = src_param->n_constraints;
-	dst_param->n_variables         = src_param->n_variables;
-	dst_param->n_int_constraints   = src_param->n_int_constraints;
-	dst_param->n_bool_constraints  = src_param->n_bool_constraints;
-	dst_param->n_total_constraints = src_param->n_total_constraints;
-
-	return dst_param;
-}
diff --git a/src/xml-sax-write.c b/src/xml-sax-write.c
index 7a5a6d9..7dc040f 100644
--- a/src/xml-sax-write.c
+++ b/src/xml-sax-write.c
@@ -965,7 +965,7 @@ xml_write_sheet_filters (GnmOutputXML *state)
 static void
 xml_write_solver (GnmOutputXML *state)
 {
-        SolverParameters *param = state->sheet->solver_parameters;
+        GnmSolverParameters *param = state->sheet->solver_parameters;
 	GSList *ptr;
 	GnmCellRef const *target;
 	GnmValue const *input;



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]