2 * Copyright (C) 2009 Morten Welinder (terra@gnome.org)
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see <https://www.gnu.org/licenses/>.
18 #include <gnumeric-config.h>
21 #include <workbook-view.h>
22 #include <application.h>
28 #include <tools/gnm-solver.h>
30 #include <parse-util.h>
32 #include <goffice/goffice.h>
33 #include <glib/gi18n-lib.h>
39 lpsolve_var_name (GnmSubSolver
*ssol
, GnmCell
const *cell
)
42 const char *old
= gnm_sub_solver_get_cell_name (ssol
, cell
);
45 return gnm_sub_solver_name_cell (ssol
, cell
, cell_name (cell
));
47 return cell_name (cell
);
51 lpsolve_affine_func (GString
*dst
, GnmCell
*target
, GnmSubSolver
*ssol
,
52 gnm_float
const *x1
, gnm_float
const *x2
,
53 gnm_float cst
, GError
**err
)
55 GnmSolver
*sol
= GNM_SOLVER (ssol
);
60 GPtrArray
*input_cells
= sol
->input_cells
;
64 gnm_string_add_number (dst
, cst
);
68 gnm_solver_set_vars (sol
, x1
);
69 gnm_cell_eval (target
);
70 y
= cst
+ value_get_as_float (target
->value
);
72 cs
= gnm_solver_get_lp_coeffs (sol
, target
, x1
, x2
, err
);
76 /* Adjust constant for choice of x1. */
77 for (ui
= 0; ui
< input_cells
->len
; ui
++)
80 for (ui
= 0; ui
< input_cells
->len
; ui
++) {
81 GnmCell
*cell
= g_ptr_array_index (input_cells
, ui
);
88 g_string_append (dst
, " - ");
90 g_string_append (dst
, " + ");
93 g_string_append_c (dst
, '-');
98 gnm_string_add_number (dst
, x
);
99 g_string_append_c (dst
, ' ');
102 g_string_append (dst
, lpsolve_var_name (ssol
, cell
));
109 g_string_append_c (dst
, ' ');
111 g_string_append_c (dst
, '+');
113 gnm_string_add_number (dst
, y
);
123 lpsolve_create_program (GnmSubSolver
*ssol
, GOIOContext
*io_context
, GError
**err
)
125 GnmSolver
*sol
= GNM_SOLVER (ssol
);
126 GnmSolverParameters
*sp
= sol
->params
;
128 GString
*constraints
= g_string_new (NULL
);
129 GString
*declarations
= g_string_new (NULL
);
130 GString
*objfunc
= g_string_new (NULL
);
132 GnmCell
*target_cell
= gnm_solver_param_get_target_cell (sp
);
133 GPtrArray
*input_cells
= sol
->input_cells
;
135 GPtrArray
*old
= NULL
;
136 gnm_float
*x1
= NULL
, *x2
= NULL
;
138 /* ---------------------------------------- */
140 if (sp
->options
.model_type
!= GNM_SOLVER_LP
) {
144 _("Only linear programs are handled."));
148 /* ---------------------------------------- */
151 if (sp
->options
.assume_non_negative
) progress
++;
152 if (sp
->options
.assume_discrete
) progress
++;
153 progress
+= g_slist_length (sp
->constraints
);
155 go_io_count_progress_set (io_context
, progress
, 1);
157 /* ---------------------------------------- */
159 old
= gnm_solver_save_vars (sol
);
161 gnm_solver_pick_lp_coords (sol
, &x1
, &x2
);
162 go_io_count_progress_update (io_context
, 1);
164 /* ---------------------------------------- */
166 switch (sp
->problem_type
) {
167 case GNM_SOLVER_MINIMIZE
:
168 g_string_append (objfunc
, "min: ");
170 case GNM_SOLVER_MAXIMIZE
:
171 g_string_append (objfunc
, "max: ");
174 g_assert_not_reached ();
176 go_io_count_progress_update (io_context
, 1);
178 if (!lpsolve_affine_func (objfunc
, target_cell
, ssol
,
182 g_string_append (objfunc
, ";\n");
183 go_io_count_progress_update (io_context
, 1);
185 /* ---------------------------------------- */
187 if (sp
->options
.assume_non_negative
) {
189 for (ui
= 0; ui
< input_cells
->len
; ui
++) {
190 GnmCell
*cell
= g_ptr_array_index (input_cells
, ui
);
191 g_string_append (constraints
,
192 lpsolve_var_name (ssol
, cell
));
193 g_string_append (constraints
, " >= 0;\n");
195 go_io_count_progress_update (io_context
, 1);
198 if (sp
->options
.assume_discrete
) {
200 for (ui
= 0; ui
< input_cells
->len
; ui
++) {
201 GnmCell
*cell
= g_ptr_array_index (input_cells
, ui
);
202 g_string_append (declarations
, "int ");
203 g_string_append (declarations
,
204 lpsolve_var_name (ssol
, cell
));
205 g_string_append (declarations
, ";\n");
207 go_io_count_progress_update (io_context
, 1);
210 for (l
= sp
->constraints
; l
; l
= l
->next
) {
211 GnmSolverConstraint
*c
= l
->data
;
212 const char *op
= NULL
;
213 const char *type
= NULL
;
229 case GNM_SOLVER_INTEGER
:
232 case GNM_SOLVER_BOOLEAN
:
236 g_assert_not_reached ();
240 gnm_solver_constraint_get_part (c
, sp
, i
,
245 g_string_append (declarations
, type
);
246 g_string_append_c (declarations
, ' ');
247 g_string_append (declarations
, lpsolve_var_name (ssol
, lhs
));
248 g_string_append (declarations
, ";\n");
252 char *name
= g_strdup_printf ("CONSTR_%d", cidx
);
253 g_string_append (constraints
, name
);
254 g_string_append (constraints
, ": ");
255 gnm_sub_solver_name_constraint (ssol
, cidx
, name
);
258 ok
= lpsolve_affine_func
259 (constraints
, lhs
, ssol
,
265 g_string_append_c (constraints
, ' ');
266 g_string_append (constraints
, op
);
267 g_string_append_c (constraints
, ' ');
269 ok
= lpsolve_affine_func
270 (constraints
, rhs
, ssol
,
276 g_string_append (constraints
, ";\n");
280 go_io_count_progress_update (io_context
, 1);
283 /* ---------------------------------------- */
285 prg
= g_string_new (NULL
);
286 g_string_append_printf (prg
,
287 "/* Created by Gnumeric %s */\n",
289 g_string_append (prg
, "\n/* Object function */\n");
290 go_string_append_gstring (prg
, objfunc
);
291 g_string_append (prg
, "\n/* Constraints */\n");
292 go_string_append_gstring (prg
, constraints
);
293 g_string_append (prg
, "\n/* Declarations */\n");
294 go_string_append_gstring (prg
, declarations
);
295 g_string_append (prg
, "\n/* The End */\n");
298 g_string_free (objfunc
, TRUE
);
299 g_string_free (constraints
, TRUE
);
300 g_string_free (declarations
, TRUE
);
305 gnm_solver_restore_vars (sol
, old
);
311 lpsolve_file_save (GOFileSaver
const *fs
, GOIOContext
*io_context
,
312 WorkbookView
const *wb_view
, GsfOutput
*output
)
317 GnmSolver
*sol
= NULL
;
318 GnmSubSolver
*ssol
= g_object_get_data (G_OBJECT (fs
), "solver");
321 // Create a temporary solver just functional enough to
323 Sheet
*sheet
= wb_view_cur_sheet (wb_view
);
324 sol
= lpsolve_solver_create (sheet
->solver_parameters
);
325 ssol
= GNM_SUB_SOLVER (sol
);
328 go_io_progress_message (io_context
,
329 _("Writing lpsolve file..."));
331 locale
= gnm_push_C_locale ();
332 prg
= lpsolve_create_program (ssol
, io_context
, &err
);
333 gnm_pop_C_locale (locale
);
338 go_cmd_context_error_import (GO_CMD_CONTEXT (io_context
),
339 err
? err
->message
: "?");
343 gsf_output_write (output
, prg
->len
, prg
->str
);
344 g_string_free (prg
, TRUE
);
347 go_io_progress_unset (io_context
);
352 g_object_unref (sol
);