Esempio n. 1
0
GnmSolver *
nlsolve_solver_factory (GnmSolverFactory *factory, GnmSolverParameters *params)
{
	GnmSolver *res = g_object_new (GNM_SOLVER_TYPE,
				       "params", params,
				       NULL);
	GnmNlsolve *nl = g_new0 (GnmNlsolve, 1);
	GSList *input_cells, *l;
	int n;
	GnmValue const *vinput = gnm_solver_param_get_input (params);
	GnmEvalPos ep;
	GnmCellRef origin;

	nl->parent = GNM_SOLVER (res);

	nl->maximize = (params->problem_type == GNM_SOLVER_MAXIMIZE);

	eval_pos_init_sheet (&ep, params->sheet);
	if (vinput) {
		gnm_cellref_make_abs (&origin, &vinput->v_range.cell.a, &ep);
		nl->origin.col = origin.col;
		nl->origin.row = origin.row;
		nl->input_width = value_area_get_width (vinput, &ep);
		nl->input_height = value_area_get_height (vinput, &ep);
	}

	nl->debug = gnm_solver_debug ();
	nl->max_iter = params->options.max_iter;
	nl->min_factor = 1e-10;

	nl->target = gnm_solver_param_get_target_cell (params);

	nl->vars = g_ptr_array_new ();
	input_cells = gnm_solver_param_get_input_cells (params);
	for (l = input_cells; l; l = l->next)
		g_ptr_array_add (nl->vars, l->data);
	g_slist_free (input_cells);
	n = nl->vars->len;

	nl->x0 = g_new (gnm_float, n);
	nl->xk = g_new (gnm_float, n);

	g_signal_connect (res, "prepare", G_CALLBACK (gnm_nlsolve_prepare), nl);
	g_signal_connect (res, "start", G_CALLBACK (gnm_nlsolve_start), nl);
	g_signal_connect (res, "stop", G_CALLBACK (gnm_nlsolve_stop), nl);

	g_object_set_data_full (G_OBJECT (res), PRIVATE_KEY, nl,
				(GDestroyNotify)gnm_nlsolve_final);

	return res;
}
Esempio n. 2
0
/**
 * dialog_init:
 * @state:
 *
 * Create the dialog (guru).
 *
 **/
static gboolean
dialog_init (SolverState *state)
{
	GtkGrid *grid;
	GnmSolverParameters *param;
	GtkCellRenderer *renderer;
	GtkListStore *store;
	GtkTreeViewColumn *column;
	GSList *cl;
	GnmCell *target_cell;
	GnmValue const *input;
	int i;

	param = state->sheet->solver_parameters;

	state->gui = gnm_gtk_builder_load ("solver.ui", NULL, GO_CMD_CONTEXT (state->wbcg));
        if (state->gui == NULL)
                return TRUE;

	state->dialog = go_gtk_builder_get_widget (state->gui, "Solver");
        if (state->dialog == NULL)
                return TRUE;

	state->notebook = go_gtk_builder_get_widget (state->gui, "solver_notebook");

	/*  buttons  */
	state->solve_button  = go_gtk_builder_get_widget (state->gui, "solvebutton");
	g_signal_connect (G_OBJECT (state->solve_button), "clicked",
			  G_CALLBACK (cb_dialog_solve_clicked), state);

	state->close_button  = go_gtk_builder_get_widget (state->gui, "closebutton");
	g_signal_connect (G_OBJECT (state->close_button), "clicked",
			  G_CALLBACK (cb_dialog_close_clicked), state);

	state->help_button = go_gtk_builder_get_widget (state->gui, "helpbutton");
	gnm_init_help_button (state->help_button, GNUMERIC_HELP_LINK_SOLVER);

	state->add_button  = go_gtk_builder_get_widget (state->gui, "addbutton");
	gtk_button_set_alignment (GTK_BUTTON (state->add_button), 0.5, .5);
	g_signal_connect_swapped (G_OBJECT (state->add_button), "clicked",
		G_CALLBACK (cb_dialog_add_clicked), state);

	state->change_button = go_gtk_builder_get_widget (state->gui,
						     "changebutton");
	g_signal_connect (G_OBJECT (state->change_button), "clicked",
			  G_CALLBACK (cb_dialog_change_clicked), state);

	state->delete_button = go_gtk_builder_get_widget (state->gui,
						     "deletebutton");
	gtk_button_set_alignment (GTK_BUTTON (state->delete_button), 0.5, .5);
	g_signal_connect (G_OBJECT (state->delete_button), "clicked",
			  G_CALLBACK (cb_dialog_delete_clicked), state);

	state->stop_button = go_gtk_builder_get_widget (state->gui, "stopbutton");
	g_signal_connect_swapped (G_OBJECT (state->stop_button),
				  "clicked", G_CALLBACK (cb_stop_solver),
				  state);

	/* target_entry */
	grid = GTK_GRID (go_gtk_builder_get_widget (state->gui,
						 "parameter-grid"));
	state->target_entry = gnm_expr_entry_new (state->wbcg, TRUE);
	gnm_expr_entry_set_flags (state->target_entry,
		GNM_EE_SINGLE_RANGE |
		GNM_EE_FORCE_ABS_REF |
		GNM_EE_SHEET_OPTIONAL, GNM_EE_MASK);
	gtk_widget_set_hexpand (GTK_WIDGET (state->target_entry), TRUE);
	gtk_grid_attach (grid, GTK_WIDGET (state->target_entry), 1, 0, 2, 1);
	gnm_editable_enters (GTK_WINDOW (state->dialog),
				  GTK_WIDGET (state->target_entry));
	gtk_widget_show (GTK_WIDGET (state->target_entry));
	g_signal_connect_after (G_OBJECT (state->target_entry),	"changed",
			G_CALLBACK (dialog_set_main_button_sensitivity),
				state);

	/* change_cell_entry */
	state->change_cell_entry = gnm_expr_entry_new (state->wbcg, TRUE);
	gnm_expr_entry_set_flags (state->change_cell_entry,
		GNM_EE_SINGLE_RANGE |
		GNM_EE_FORCE_ABS_REF |
		GNM_EE_SHEET_OPTIONAL, GNM_EE_MASK);
	gtk_widget_set_hexpand (GTK_WIDGET (state->change_cell_entry), TRUE);
	gtk_grid_attach (grid,
	                 GTK_WIDGET (state->change_cell_entry), 1, 2, 2, 1);
	gnm_editable_enters (GTK_WINDOW (state->dialog),
				  GTK_WIDGET (state->change_cell_entry));
	gtk_widget_show (GTK_WIDGET (state->change_cell_entry));
	g_signal_connect_after (G_OBJECT (state->change_cell_entry), "changed",
		G_CALLBACK (dialog_set_main_button_sensitivity), state);

	/* Algorithm */
	state->algorithm_combo = GTK_COMBO_BOX
		(go_gtk_builder_get_widget (state->gui, "algorithm_combo"));
	renderer = (GtkCellRenderer*) gtk_cell_renderer_text_new();
	gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (state->algorithm_combo), renderer, TRUE);
	gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (state->algorithm_combo), renderer,
					"text", 0,
					NULL);
	fill_algorithm_combo (state, param->options.model_type);

	for (i = 0; model_type_group[i]; i++) {
		const char *bname = model_type_group[i];
		GtkWidget *w = go_gtk_builder_get_widget(state->gui, bname);
		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w),
					      param->options.model_type ==
					      (GnmSolverModelType)i);
		g_signal_connect (G_OBJECT (w), "clicked",
				  G_CALLBACK (cb_dialog_model_type_clicked), state);
	}

	/* Options */
	state->max_iter_entry = go_gtk_builder_get_widget (state->gui,
						      "max_iter_entry");
	gtk_spin_button_set_value (GTK_SPIN_BUTTON (state->max_iter_entry),
				   param->options.max_iter);

	state->max_time_entry = go_gtk_builder_get_widget (state->gui,
						      "max_time_entry");
	gtk_spin_button_set_value (GTK_SPIN_BUTTON (state->max_time_entry),
				   param->options.max_time_sec);

	state->gradient_order_entry = go_gtk_builder_get_widget (state->gui,
								 "gradient_order_entry");
	gtk_spin_button_set_value (GTK_SPIN_BUTTON (state->gradient_order_entry),
				   param->options.gradient_order);

	/* lhs_entry */
	grid = GTK_GRID (go_gtk_builder_get_widget (state->gui,
	                                            "constraints-grid"));
	state->lhs.entry = gnm_expr_entry_new (state->wbcg, TRUE);
	gnm_expr_entry_set_flags (state->lhs.entry,
		GNM_EE_SINGLE_RANGE |
		GNM_EE_FORCE_ABS_REF |
		GNM_EE_SHEET_OPTIONAL, GNM_EE_MASK);
	gtk_widget_set_hexpand (GTK_WIDGET (state->lhs.entry), TRUE);
	gtk_grid_attach (grid, GTK_WIDGET (state->lhs.entry), 0, 4, 1, 1);
	state->lhs.label = go_gtk_builder_get_widget (state->gui, "lhs_label");
	gtk_label_set_mnemonic_widget (GTK_LABEL (state->lhs.label),
		GTK_WIDGET (state->lhs.entry));
	gtk_widget_show (GTK_WIDGET (state->lhs.entry));
	g_signal_connect_after (G_OBJECT (state->lhs.entry),
		"changed",
		G_CALLBACK (dialog_set_sec_button_sensitivity), state);
	g_signal_connect_swapped (
		gnm_expr_entry_get_entry (GNM_EXPR_ENTRY (state->lhs.entry)),
		"activate", G_CALLBACK (cb_dialog_add_clicked), state);

	/* rhs_entry */
	state->rhs.entry = gnm_expr_entry_new (state->wbcg, TRUE);
	gnm_expr_entry_set_flags (state->rhs.entry,
				  GNM_EE_SINGLE_RANGE |
				  GNM_EE_FORCE_ABS_REF |
				  GNM_EE_SHEET_OPTIONAL |
				  GNM_EE_CONSTANT_ALLOWED,
				  GNM_EE_MASK);
	gtk_widget_set_hexpand (GTK_WIDGET (state->rhs.entry), TRUE);
	gtk_grid_attach (grid, GTK_WIDGET (state->rhs.entry), 2, 4, 1, 1);
	gtk_widget_show (GTK_WIDGET (state->rhs.entry));
	state->rhs.label = go_gtk_builder_get_widget (state->gui, "rhs_label");
	gtk_label_set_mnemonic_widget (
		GTK_LABEL (state->rhs.label), GTK_WIDGET (state->rhs.entry));
	g_signal_connect_after (G_OBJECT (state->rhs.entry),
		"changed",
		G_CALLBACK (dialog_set_sec_button_sensitivity), state);
	g_signal_connect_swapped (
		gnm_expr_entry_get_entry (GNM_EXPR_ENTRY (state->rhs.entry)),
		"activate", G_CALLBACK (cb_dialog_add_clicked), state);

	/* type_menu */
	state->type_combo = GTK_COMBO_BOX
		(go_gtk_builder_get_widget (state->gui, "type_menu"));
	gtk_combo_box_set_active (state->type_combo, 0);
	g_signal_connect (state->type_combo, "changed",
			  G_CALLBACK (dialog_set_sec_button_sensitivity),
			  state);

	/* constraint_list */
	state->constraint_list = GTK_TREE_VIEW (go_gtk_builder_get_widget
					    (state->gui, "constraint_list"));

	state->constr = NULL;
	g_signal_connect (G_OBJECT (gtk_tree_view_get_selection (state->constraint_list)), "changed",
			  G_CALLBACK (constraint_select_click), state);
	gtk_tree_view_set_reorderable (state->constraint_list, TRUE);
	store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_POINTER);
	gtk_tree_view_set_model (state->constraint_list, GTK_TREE_MODEL(store));
	renderer = gtk_cell_renderer_text_new ();
	column = gtk_tree_view_column_new_with_attributes (
			_("Subject to the Constraints:"),
			renderer, "text", 0, NULL);
	gtk_tree_view_column_set_expand (column, TRUE);
	gtk_tree_view_append_column (state->constraint_list, column);

	{
		GtkWidget *w = GTK_WIDGET (state->constraint_list);
		int width, height, vsep;
		PangoLayout *layout =
			gtk_widget_create_pango_layout (w, "Mg19");

		gtk_widget_style_get (w,
				      "vertical_separator", &vsep,
				      NULL);

		pango_layout_get_pixel_size (layout, &width, &height);
		gtk_widget_set_size_request (w,
					     -1,
					     (2 * height + vsep) * (4 + 1));
		g_object_unref (layout);
	}

/* Loading the old solver specs... from param  */

	for (cl = param->constraints; cl; cl = cl->next) {
		GnmSolverConstraint const *c = cl->data;
		GtkTreeIter iter;
		char *str;

		gtk_list_store_append (store, &iter);
		str = gnm_solver_constraint_as_str (c, state->sheet);
		gtk_list_store_set (store, &iter, 0, str, 1, c, -1);
		g_free (str);
	}
	g_object_unref (store);

	INIT_BOOL_ENTRY ("autoscale_button", options.automatic_scaling);
	INIT_BOOL_ENTRY ("non_neg_button", options.assume_non_negative);
	INIT_BOOL_ENTRY ("all_int_button", options.assume_discrete);
	INIT_BOOL_ENTRY ("program", options.program_report);
	INIT_BOOL_ENTRY ("sensitivity", options.sensitivity_report);

	input = gnm_solver_param_get_input (param);
	if (input != NULL)
		gnm_expr_entry_load_from_text (state->change_cell_entry,
					       value_peek_string (input));
	target_cell = gnm_solver_param_get_target_cell (param);
	if (target_cell)
		gnm_expr_entry_load_from_text (state->target_entry,
					       cell_name (target_cell));
	else {
		SheetView *sv = wb_control_cur_sheet_view
			(GNM_WBC (state->wbcg));
		if (sv) {
			GnmRange first = {sv->edit_pos, sv->edit_pos};
			gnm_expr_entry_load_from_range (state->target_entry,
							state->sheet, &first);
		}
	}

	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (
		go_gtk_builder_get_widget(state->gui, "max_button")),
			param->problem_type == GNM_SOLVER_MAXIMIZE);
	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (
		go_gtk_builder_get_widget(state->gui, "min_button")),
			param->problem_type == GNM_SOLVER_MINIMIZE);
	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (
		go_gtk_builder_get_widget(state->gui, "no_scenario")),
			! param->options.add_scenario);
	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (
		go_gtk_builder_get_widget(state->gui, "optimal_scenario")),
			param->options.add_scenario);

	state->scenario_name_entry = go_gtk_builder_get_widget
		(state->gui, "scenario_name_entry");
	gtk_entry_set_text (GTK_ENTRY (state->scenario_name_entry),
			    param->options.scenario_name);

	state->run.status_widget = go_gtk_builder_get_widget (state->gui, "solver_status_label");
	state->run.problem_status_widget = go_gtk_builder_get_widget (state->gui, "problem_status_label");
	state->run.objective_value_widget = go_gtk_builder_get_widget (state->gui, "objective_value_label");
	state->run.timer_widget = go_gtk_builder_get_widget (state->gui, "elapsed_time_label");
	state->run.spinner = go_gtk_builder_get_widget (state->gui, "run_spinner");


/* Done */
	gnm_expr_entry_grab_focus (state->target_entry, FALSE);
	wbcg_set_entry (state->wbcg, state->target_entry);

	dialog_set_main_button_sensitivity (NULL, state);
	dialog_set_sec_button_sensitivity (NULL, state);

/* dialog */
	wbc_gtk_attach_guru (state->wbcg, state->dialog);

	g_signal_connect_swapped (G_OBJECT (state->dialog),
				  "destroy",
				  G_CALLBACK (cb_dialog_solver_destroy),
				  state);
	g_object_set_data_full (G_OBJECT (state->dialog),
				"state", state,
				(GDestroyNotify)unref_state);

	return FALSE;
}
Esempio n. 3
0
static GString *
glpk_create_program (GnmSubSolver *ssol, GOIOContext *io_context, GError **err)
{
    GnmSolver *sol = GNM_SOLVER (ssol);
    GnmSolverParameters *sp = sol->params;
    GString *prg = NULL;
    GString *constraints = g_string_new (NULL);
    GString *bounds = g_string_new (NULL);
    GString *binaries = g_string_new (NULL);
    GString *integers = g_string_new (NULL);
    GString *objfunc = g_string_new (NULL);
    GSList *l;
    GnmCell *target_cell = gnm_solver_param_get_target_cell (sp);
    GPtrArray *input_cells = sol->input_cells;
    gsize progress;
    GPtrArray *old = NULL;
    gnm_float *x1 = NULL, *x2 = NULL;
    int cidx = 0;

    /* ---------------------------------------- */

    if (sp->options.model_type != GNM_SOLVER_LP) {
        g_set_error (err,
                     go_error_invalid (),
                     0,
                     _("Only linear programs are handled."));
        goto fail;
    }

    /* ---------------------------------------- */

    if (ssol) {
        unsigned ui;

        for (ui = 0; ui < input_cells->len; ui++) {
            GnmCell *cell = g_ptr_array_index (input_cells, ui);
            char *name = g_strdup_printf ("X_%u", ui + 1);
            gnm_sub_solver_name_cell (ssol, cell, name);
            g_free (name);
        }
    }

    /* ---------------------------------------- */

    progress = 3;
    /* assume_non_negative */ progress++;
    if (sp->options.assume_discrete) progress++;
    progress += g_slist_length (sp->constraints);

    go_io_count_progress_set (io_context, progress, 1);

    /* ---------------------------------------- */

    old = gnm_solver_save_vars (sol);

    gnm_solver_pick_lp_coords (sol, &x1, &x2);
    go_io_count_progress_update (io_context, 1);

    /* ---------------------------------------- */

    switch (sp->problem_type) {
    case GNM_SOLVER_MINIMIZE:
        g_string_append (objfunc, "Minimize\n");
        break;
    case GNM_SOLVER_MAXIMIZE:
        g_string_append (objfunc, "Maximize\n");
        break;
    default:
        g_assert_not_reached ();
    }
    go_io_count_progress_update (io_context, 1);

    g_string_append (objfunc, " obj: ");
    if (!glpk_affine_func (objfunc, target_cell, ssol, x1, x2,
                           TRUE, 0, err))
        goto fail;
    g_string_append (objfunc, "\n");
    go_io_count_progress_update (io_context, 1);

    /* ---------------------------------------- */

    {
        unsigned ui;
        for (ui = 0; ui < input_cells->len; ui++) {
            GnmCell *cell = g_ptr_array_index (input_cells, ui);
            const char *name = glpk_var_name (ssol, cell);
            if (sp->options.assume_non_negative)
                g_string_append_printf (bounds, " %s >= 0\n", name);
            else
                g_string_append_printf (bounds, " %s free\n", name);
        }
        go_io_count_progress_update (io_context, 1);
    }

    if (sp->options.assume_discrete) {
        unsigned ui;
        for (ui = 0; ui < input_cells->len; ui++) {
            GnmCell *cell = g_ptr_array_index (input_cells, ui);
            g_string_append_printf (integers, " %s\n",
                                    glpk_var_name (ssol, cell));
        }
        go_io_count_progress_update (io_context, 1);
    }

    for (l = sp->constraints; l; l = l->next) {
        GnmSolverConstraint *c = l->data;
        const char *op = NULL;
        int i;
        gnm_float cl, cr;
        GnmCell *lhs, *rhs;
        GString *type = NULL;

        switch (c->type) {
        case GNM_SOLVER_LE:
            op = "<=";
            break;
        case GNM_SOLVER_GE:
            op = ">=";
            break;
        case GNM_SOLVER_EQ:
            op = "=";
            break;
        case GNM_SOLVER_INTEGER:
            type = integers;
            break;
        case GNM_SOLVER_BOOLEAN:
            type = binaries;
            break;
        default:
            g_assert_not_reached ();
        }

        for (i = 0;
                gnm_solver_constraint_get_part (c, sp, i,
                                                &lhs, &cl,
                                                &rhs, &cr);
                i++, cidx++) {
            if (type) {
                g_string_append_printf
                (type, " %s\n",
                 glpk_var_name (ssol, lhs));
            } else {
                gboolean ok;
                char *name;

                g_string_append_c (constraints, ' ');

                name = g_strdup_printf ("C_%d", cidx);
                gnm_sub_solver_name_constraint (ssol, cidx, name);
                g_string_append (constraints, name);
                g_string_append (constraints, ": ");
                g_free (name);

                ok = glpk_affine_func
                     (constraints, lhs, ssol,
                      x1, x2,
                      FALSE, cl, err);
                if (!ok)
                    goto fail;

                g_string_append_c (constraints, ' ');
                g_string_append (constraints, op);
                g_string_append_c (constraints, ' ');

                ok = glpk_affine_func
                     (constraints, rhs, ssol,
                      x1, x2,
                      FALSE, cr, err);
                if (!ok)
                    goto fail;

                g_string_append (constraints, "\n");
            }
        }

        go_io_count_progress_update (io_context, 1);
    }

    /* ---------------------------------------- */

    prg = g_string_new (NULL);
    g_string_append_printf (prg,
                            "\\ Created by Gnumeric %s\n\n",
                            GNM_VERSION_FULL);
    go_string_append_gstring (prg, objfunc);

    g_string_append (prg, "\nSubject to\n");
    go_string_append_gstring (prg, constraints);

    g_string_append (prg, "\nBounds\n");
    go_string_append_gstring (prg, bounds);

    if (integers->len > 0) {
        g_string_append (prg, "\nGeneral\n");
        go_string_append_gstring (prg, integers);
    }
    if (binaries->len > 0) {
        g_string_append (prg, "\nBinary\n");
        go_string_append_gstring (prg, binaries);
    }
    g_string_append (prg, "\nEnd\n");

fail:
    g_string_free (objfunc, TRUE);
    g_string_free (constraints, TRUE);
    g_string_free (bounds, TRUE);
    g_string_free (integers, TRUE);
    g_string_free (binaries, TRUE);
    g_free (x1);
    g_free (x2);

    if (old)
        gnm_solver_restore_vars (sol, old);

    return prg;
}