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; }
/** * 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; }
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; }