[gnumeric] solver: namespace and code moving.
- From: Morten Welinder <mortenw src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [gnumeric] solver: namespace and code moving.
- Date: Thu, 12 Nov 2009 19:37:15 +0000 (UTC)
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]