Update Spanish translation
[gnumeric.git] / plugins / lpsolve / lpsolve-write.c
blob39c0db4f190a3aa28c8142b10c4ee7480c4c2bb7
1 /*
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>
19 #include <boot.h>
20 #include <numbers.h>
21 #include <workbook-view.h>
22 #include <application.h>
23 #include <sheet.h>
24 #include <workbook.h>
25 #include <value.h>
26 #include <cell.h>
27 #include <expr.h>
28 #include <tools/gnm-solver.h>
29 #include <ranges.h>
30 #include <parse-util.h>
31 #include <gutils.h>
32 #include <goffice/goffice.h>
33 #include <glib/gi18n-lib.h>
35 #include <string.h>
38 static const char *
39 lpsolve_var_name (GnmSubSolver *ssol, GnmCell const *cell)
41 if (ssol) {
42 const char *old = gnm_sub_solver_get_cell_name (ssol, cell);
43 if (old)
44 return old;
45 return gnm_sub_solver_name_cell (ssol, cell, cell_name (cell));
47 return cell_name (cell);
50 static gboolean
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);
56 unsigned ui;
57 gboolean any = FALSE;
58 gnm_float y;
59 gboolean ok = TRUE;
60 GPtrArray *input_cells = sol->input_cells;
61 gnm_float *cs;
63 if (!target) {
64 gnm_string_add_number (dst, cst);
65 return TRUE;
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);
73 if (!cs)
74 goto fail;
76 /* Adjust constant for choice of x1. */
77 for (ui = 0; ui < input_cells->len; ui++)
78 y -= x1[ui] * cs[ui];
80 for (ui = 0; ui < input_cells->len; ui++) {
81 GnmCell *cell = g_ptr_array_index (input_cells, ui);
82 gnm_float x = cs[ui];
83 if (x == 0)
84 continue;
86 if (any) {
87 if (x < 0)
88 g_string_append (dst, " - ");
89 else
90 g_string_append (dst, " + ");
91 } else {
92 if (x < 0)
93 g_string_append_c (dst, '-');
95 x = gnm_abs (x);
97 if (x != 1) {
98 gnm_string_add_number (dst, x);
99 g_string_append_c (dst, ' ');
102 g_string_append (dst, lpsolve_var_name (ssol, cell));
104 any = TRUE;
107 if (!any || y) {
108 if (any) {
109 g_string_append_c (dst, ' ');
110 if (y > 0)
111 g_string_append_c (dst, '+');
113 gnm_string_add_number (dst, y);
116 fail:
117 g_free (cs);
119 return ok;
122 static GString *
123 lpsolve_create_program (GnmSubSolver *ssol, GOIOContext *io_context, GError **err)
125 GnmSolver *sol = GNM_SOLVER (ssol);
126 GnmSolverParameters *sp = sol->params;
127 GString *prg = NULL;
128 GString *constraints = g_string_new (NULL);
129 GString *declarations = g_string_new (NULL);
130 GString *objfunc = g_string_new (NULL);
131 GSList *l;
132 GnmCell *target_cell = gnm_solver_param_get_target_cell (sp);
133 GPtrArray *input_cells = sol->input_cells;
134 gsize progress;
135 GPtrArray *old = NULL;
136 gnm_float *x1 = NULL, *x2 = NULL;
138 /* ---------------------------------------- */
140 if (sp->options.model_type != GNM_SOLVER_LP) {
141 g_set_error (err,
142 go_error_invalid (),
144 _("Only linear programs are handled."));
145 goto fail;
148 /* ---------------------------------------- */
150 progress = 3;
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: ");
169 break;
170 case GNM_SOLVER_MAXIMIZE:
171 g_string_append (objfunc, "max: ");
172 break;
173 default:
174 g_assert_not_reached ();
176 go_io_count_progress_update (io_context, 1);
178 if (!lpsolve_affine_func (objfunc, target_cell, ssol,
179 x1, x2,
180 0, err))
181 goto fail;
182 g_string_append (objfunc, ";\n");
183 go_io_count_progress_update (io_context, 1);
185 /* ---------------------------------------- */
187 if (sp->options.assume_non_negative) {
188 unsigned ui;
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) {
199 unsigned ui;
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;
214 int i;
215 int cidx = 0;
216 gnm_float cl, cr;
217 GnmCell *lhs, *rhs;
219 switch (c->type) {
220 case GNM_SOLVER_LE:
221 op = "<=";
222 break;
223 case GNM_SOLVER_GE:
224 op = ">=";
225 break;
226 case GNM_SOLVER_EQ:
227 op = "=";
228 break;
229 case GNM_SOLVER_INTEGER:
230 type = "int";
231 break;
232 case GNM_SOLVER_BOOLEAN:
233 type = "binary";
234 break;
235 default:
236 g_assert_not_reached ();
239 for (i = 0;
240 gnm_solver_constraint_get_part (c, sp, i,
241 &lhs, &cl,
242 &rhs, &cr);
243 i++, cidx++) {
244 if (type) {
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");
249 } else {
250 gboolean ok;
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);
256 g_free (name);
258 ok = lpsolve_affine_func
259 (constraints, lhs, ssol,
260 x1, x2,
261 cl, err);
262 if (!ok)
263 goto fail;
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,
271 x1, x2,
272 cr, err);
273 if (!ok)
274 goto fail;
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",
288 GNM_VERSION_FULL);
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");
297 fail:
298 g_string_free (objfunc, TRUE);
299 g_string_free (constraints, TRUE);
300 g_string_free (declarations, TRUE);
301 g_free (x1);
302 g_free (x2);
304 if (old)
305 gnm_solver_restore_vars (sol, old);
307 return prg;
310 void
311 lpsolve_file_save (GOFileSaver const *fs, GOIOContext *io_context,
312 WorkbookView const *wb_view, GsfOutput *output)
314 GError *err = NULL;
315 GString *prg;
316 GnmLocale *locale;
317 GnmSolver *sol = NULL;
318 GnmSubSolver *ssol = g_object_get_data (G_OBJECT (fs), "solver");
320 if (!ssol) {
321 // Create a temporary solver just functional enough to
322 // write the program
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);
335 gnm_app_recalc ();
337 if (!prg) {
338 go_cmd_context_error_import (GO_CMD_CONTEXT (io_context),
339 err ? err->message : "?");
340 goto fail;
343 gsf_output_write (output, prg->len, prg->str);
344 g_string_free (prg, TRUE);
346 fail:
347 go_io_progress_unset (io_context);
348 if (err)
349 g_error_free (err);
351 if (sol)
352 g_object_unref (sol);