lpp: call the constraint types lpp_{less|greater}_equal because they are a {less...
[libfirm] / ir / lpp / lpp.c
1 /*
2  * Copyright (C) 2005-2011 University of Karlsruhe.  All right reserved.
3  *
4  * This file is part of libFirm.
5  *
6  * This file may be distributed and/or modified under the terms of the
7  * GNU General Public License version 2 as published by the Free Software
8  * Foundation and appearing in the file LICENSE.GPL included in the
9  * packaging of this file.
10  *
11  * Licensees holding valid libFirm Professional Edition licenses may use
12  * this file in accordance with the libFirm Commercial License.
13  * Agreement provided with the Software.
14  *
15  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
16  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE.
18  */
19
20 /**
21  * @file
22  * @author  Daniel Grund
23  */
24 #include "config.h"
25
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <string.h>
29
30 #include "assert.h"
31 #include "obst.h"
32 #include "hashptr.h"
33 #include "debug.h"
34 #include "set.h"
35
36 #include "sp_matrix.h"
37 #include "mps.h"
38 #include "lpp_t.h"
39 #include "lpp_comm.h"
40 #include "lpp_solvers.h"
41 #include "lpp_net.h"
42
43 #define HASH_NAME_T(n) HASH_STR((n)->name, strlen((n)->name))
44
45 static firm_dbg_module_t *dbg = NULL;
46
47 static inline char *obst_xstrdup(struct obstack *obst, const char *str)
48 {
49         return obstack_copy0(obst, str, strlen(str));
50 }
51
52 static int cmp_name_t(const void *x, const void *y, size_t size)
53 {
54         const lpp_name_t *n = x;
55         const lpp_name_t *m = y;
56         (void)size;
57         return strcmp(n->name, m->name);
58 }
59
60 /**
61  * Update statistic information about matrix usage.
62  */
63 static void update_stats(lpp_t *lpp)
64 {
65         lpp->n_elems    = matrix_get_entries(lpp->m);
66         lpp->matrix_mem = lpp->n_elems * matrix_get_elem_size();
67         lpp->density    = (double)lpp->n_elems / (double)(lpp->cst_next * lpp->var_next) * 100.0;
68 }
69
70 lpp_t *lpp_new(const char *name, lpp_opt_t opt_type)
71 {
72         return lpp_new_userdef(name, opt_type, 64, 64, 2.0);
73 }
74
75 lpp_t *lpp_new_userdef(const char *name, lpp_opt_t opt_type,
76                                    int estimated_vars, int estimated_csts,
77                                    double grow_factor)
78 {
79         lpp_t *lpp;
80         int   idx;
81
82         dbg = firm_dbg_register("lpp");
83         lpp = XMALLOCZ(lpp_t);
84         obstack_init(&lpp->obst);
85
86         lpp->name        = obst_xstrdup(&lpp->obst, name);
87         lpp->opt_type    = opt_type;
88         lpp->grow_factor = grow_factor;
89         lpp->cst2nr      = new_set(cmp_name_t, estimated_csts);
90         lpp->var2nr      = new_set(cmp_name_t, estimated_vars);
91         lpp->cst_size    = estimated_csts;
92         lpp->var_size    = estimated_vars;
93         lpp->csts        = XMALLOCNZ(lpp_name_t *, estimated_csts);
94         lpp->vars        = XMALLOCNZ(lpp_name_t *, estimated_vars);
95         lpp->m           = new_matrix(estimated_csts, estimated_vars);
96         lpp->emphasis    = lpp_balanced;
97         idx              = lpp_add_cst(lpp, "obj", lpp_objective, 0);
98         assert(idx == 0);
99         idx              = lpp_add_var(lpp, "rhs", lpp_rhs, 0);
100         assert(idx == 0);
101
102         return lpp;
103 }
104
105 void lpp_free_matrix(lpp_t *lpp)
106 {
107         del_matrix(lpp->m);
108         lpp->m = NULL;
109 }
110
111 void lpp_free(lpp_t *lpp)
112 {
113         obstack_free(&lpp->obst, NULL);
114
115         del_set(lpp->cst2nr);
116         del_set(lpp->var2nr);
117
118         /* matrix might have been already deleted */
119         if (lpp->m)
120                 del_matrix(lpp->m);
121
122         free(lpp->csts);
123         free(lpp->vars);
124
125         free(lpp);
126 }
127
128 double lpp_get_fix_costs(lpp_t *lpp)
129 {
130         return matrix_get(lpp->m, 0, 0);
131 }
132
133 void lpp_set_fix_costs(lpp_t *lpp, double value)
134 {
135         matrix_set(lpp->m, 0, 0, value);
136 }
137
138 static int name2nr(set *where, const char *name)
139 {
140         lpp_name_t find, *found;
141         find.name = name;
142         found = set_find(where, &find, sizeof(find), HASH_NAME_T(&find));
143         return (found ? found->nr : -1);
144 }
145
146 static int cst_nr(const lpp_t *lpp, const char *name)
147 {
148         return name2nr(lpp->cst2nr, name);
149 }
150
151 static int var_nr(const lpp_t *lpp, const char *name)
152 {
153         return name2nr(lpp->var2nr, name);
154 }
155
156 static inline char *get_next_name(lpp_t *lpp)
157 {
158         char *res = obstack_alloc(&lpp->obst, 12);
159         snprintf(res, 12, "_%u", lpp->next_name_number++);
160         return res;
161 }
162
163 int lpp_add_cst(lpp_t *lpp, const char *cst_name, lpp_cst_t cst_type, double rhs)
164 {
165         lpp_name_t n, *inner;
166
167         DBG((dbg, LEVEL_2, "%s %d %g\n", cst_name, cst_type, rhs));
168
169         if (cst_name && cst_name[0] == '_')
170                 return ERR_NAME_NOT_ALLOWED;
171
172         if (cst_name)
173                 n.name = obst_xstrdup(&lpp->obst, cst_name);
174         else
175                 n.name = get_next_name(lpp);
176
177         n.nr  = -1;
178         inner = set_insert(lpp->cst2nr, &n, sizeof(n), HASH_NAME_T(&n));
179         assert(inner);
180
181         if (inner->nr == -1) {
182                 inner->value_kind    = lpp_none;
183                 inner->value         = 0.0;
184                 inner->nr            = lpp->cst_next;
185                 inner->type.cst_type = cst_type;
186
187                 if (lpp->cst_next == lpp->cst_size) {
188                         lpp->cst_size = (int)((double)lpp->cst_size * lpp->grow_factor) + 1;
189                         lpp->csts     = XREALLOC(lpp->csts, lpp_name_t *, lpp->cst_size);
190                 }
191
192                 lpp->csts[lpp->cst_next] = inner;
193                 lpp->cst_next++;
194                 matrix_set(lpp->m, inner->nr, 0, rhs);
195         }
196
197         update_stats(lpp);
198         return inner->nr;
199 }
200
201 int lpp_add_cst_uniq(lpp_t *lpp, const char *cst_name, lpp_cst_t cst_type, double rhs)
202 {
203         if (cst_name) {
204                 lpp_name_t n;
205
206                 n.name = cst_name;
207                 n.nr   = -1;
208                 assert(!set_find(lpp->cst2nr, &n, sizeof(n), HASH_NAME_T(&n)) &&
209                     "constraint already exists");
210         }
211         return lpp_add_cst(lpp, cst_name, cst_type, rhs);
212 }
213
214 int lpp_get_cst_idx(lpp_t *lpp, const char *cst_name)
215 {
216         DBG((dbg, LEVEL_2, "%s --> %d\n", cst_name, cst_nr(lpp, cst_name)));
217         return cst_nr(lpp, cst_name);
218 }
219
220 void lpp_get_cst_name(lpp_t *lpp, int index, char *buf, size_t buf_size)
221 {
222         DBG((dbg, LEVEL_2, "%d --> %s\n", index, lpp->csts[index]->name));
223         strncpy(buf, lpp->csts[index]->name, buf_size);
224 }
225
226 int lpp_add_var_default(lpp_t *lpp, const char *var_name, lpp_var_t var_type, double obj, double startval)
227 {
228         int val;
229
230         val = lpp_add_var(lpp, var_name, var_type, obj);
231         lpp_set_start_value(lpp, val, startval);
232
233         return val;
234 }
235
236 int lpp_add_var(lpp_t *lpp, const char *var_name, lpp_var_t var_type, double obj)
237 {
238         lpp_name_t n, *inner;
239
240         DBG((dbg, LEVEL_2, "%s %d %g\n", var_name, var_type, obj));
241
242         assert(var_type != lpp_invalid && "invalid is for internal use only");
243
244         if (var_name && var_name[0] == '_')
245                 return ERR_NAME_NOT_ALLOWED;
246
247         if (var_name)
248                 n.name = obst_xstrdup(&lpp->obst, var_name);
249         else
250                 n.name = get_next_name(lpp);
251
252         n.nr  = -1;
253         inner = set_insert(lpp->var2nr, &n, sizeof(n), HASH_NAME_T(&n));
254         assert(inner);
255
256         if (inner->nr == -1) {
257                 inner->nr            = lpp->var_next;
258                 inner->value_kind    = 0;
259                 inner->value         = 0;
260                 inner->type.var_type = var_type;
261
262                 if (lpp->var_next == lpp->var_size) {
263                         lpp->var_size = (int)((double)lpp->var_size * lpp->grow_factor) + 1;
264                         lpp->vars     = XREALLOC(lpp->vars, lpp_name_t *, lpp->var_size);
265                 }
266
267                 lpp->vars[lpp->var_next] = inner;
268                 lpp->var_next++;
269                 matrix_set(lpp->m, 0, inner->nr, obj);
270         }
271
272         update_stats(lpp);
273         return inner->nr;
274 }
275
276 int lpp_get_var_idx(lpp_t *lpp, const char *var_name)
277 {
278         DBG((dbg, LEVEL_2, "%s --> %d\n", var_name, var_nr(lpp, var_name)));
279         return var_nr(lpp, var_name);
280 }
281
282 void lpp_get_var_name(lpp_t *lpp, int index, char *buf, size_t buf_size)
283 {
284         DBG((dbg, LEVEL_2, "%d --> %s\n", index, lpp->vars[index]->name));
285         strncpy(buf, lpp->vars[index]->name, buf_size);
286 }
287
288 int lpp_set_factor(lpp_t *lpp, const char *cst_name, const char *var_name, double value)
289 {
290         int cst, var;
291
292         cst = cst_nr(lpp, cst_name);
293         var = var_nr(lpp, var_name);
294         assert(cst != -1 && var != -1);
295         DBG((dbg, LEVEL_2, "%s[%d] %s[%d] %g\n", cst_name, cst, var_name, var, value));
296         matrix_set(lpp->m, cst, var, value);
297         update_stats(lpp);
298         return 0;
299 }
300
301 int lpp_set_factor_fast(lpp_t *lpp, int cst_idx, int var_idx, double value)
302 {
303         assert(cst_idx >= 0 && var_idx >= 0);
304         assert(cst_idx < lpp->cst_next && var_idx < lpp->var_next);
305         DBG((dbg, LEVEL_2, "%s[%d] %s[%d] %g\n", lpp->csts[cst_idx]->name, cst_idx, lpp->vars[var_idx]->name, var_idx, value));
306         matrix_set(lpp->m, cst_idx, var_idx, value);
307         update_stats(lpp);
308         return 0;
309 }
310
311 int lpp_set_factor_fast_bulk(lpp_t *lpp, int cst_idx, int *var_idx, int num_vars, double value)
312 {
313         assert(cst_idx >= 0 && cst_idx < lpp->cst_next);
314         assert(num_vars < lpp->var_next);
315         DBG((dbg, LEVEL_2, "row %s[%d] %d vars %g\n", lpp->csts[cst_idx]->name, cst_idx, num_vars, value));
316         matrix_set_row_bulk(lpp->m, cst_idx, var_idx, num_vars, value);
317         update_stats(lpp);
318         return 0;
319 }
320
321 void lpp_set_start_value(lpp_t *lpp, int var_idx, double value)
322 {
323         assert(var_idx > 0 && var_idx < lpp->var_next);
324         DBG((dbg, LEVEL_2, "%d %s %g\n", var_idx, lpp->vars[var_idx]->name, value));
325         lpp->vars[var_idx]->value = value;
326         lpp->vars[var_idx]->value_kind = lpp_value_start;
327 }
328
329 lpp_sol_state_t lpp_get_solution(lpp_t *lpp, double *values, int begin, int end)
330 {
331         int i;
332
333         if (lpp->sol_state < lpp_feasible)
334                 return lpp->sol_state;
335
336         /* here we are feasible or optimal */
337         for (i = 0; i < end - begin + 1; ++i)
338                 values[i] = lpp->vars[begin + i]->value;
339
340         return lpp->sol_state;
341 }
342
343 void lpp_check_startvals(lpp_t *lpp)
344 {
345         int cst_idx;
346
347         for (cst_idx = 1; cst_idx < lpp->cst_next; ++cst_idx) {
348                 double     sum     = 0.0;
349                 lpp_name_t *cst    = lpp->csts[cst_idx];
350                 double     cst_val = matrix_get(lpp->m, cst_idx, 0);
351                 int        var_idx;
352
353                 for (var_idx = 1; var_idx < lpp->var_next; ++var_idx) {
354                                 if (lpp->vars[var_idx]->value_kind != lpp_value_start)
355                                         goto next;
356
357                                 sum += lpp->vars[var_idx]->value *
358                                         matrix_get(lpp->m, cst_idx, var_idx);
359                 }
360                 switch(cst->type.cst_type) {
361                         case lpp_equal:
362                                 if(sum != cst_val) {
363                                         fprintf(stderr, "constraint %s unsatisfied: %g != %g\n", cst->name, sum, cst_val);
364                                 }
365                                 break;
366                         case lpp_less_equal:
367                                 if(sum > cst_val) {
368                                         fprintf(stderr, "constraint %s unsatisfied: %g >= %g\n", cst->name, sum, cst_val);
369                                 }
370                                 break;
371                         case lpp_greater_equal:
372                                 if(sum < cst_val) {
373                                         fprintf(stderr, "constraint %s unsatisfied: %g <= %g\n", cst->name, sum, cst_val);
374                                 }
375                                 break;
376                         default:
377                                 assert(0 && "unknown constraint type");
378                 }
379 next: ;
380         }
381 }
382
383 void lpp_dump(lpp_t *lpp, const char *filename)
384 {
385         FILE *out = fopen(filename, "wt");
386         mps_write_mps(lpp, s_mps_fixed, out);
387         fclose(out);
388 }
389
390 void lpp_set_log(lpp_t *lpp, FILE *log)
391 {
392         lpp->log = log;
393 }
394
395
396 static const char *lpp_cst_op_to_str(lpp_cst_t cst)
397 {
398         switch(cst) {
399         case lpp_equal:
400                 return "=";
401         case lpp_less_equal:
402                 return "<=";
403         case lpp_greater_equal:
404                 return ">=";
405         default:
406                 return "";
407         }
408 }
409
410 void lpp_dump_plain(lpp_t *lpp, FILE *f)
411 {
412         int i;
413
414         for(i = 0; i < lpp->cst_next; ++i) {
415                 const matrix_elem_t *elm;
416                 lpp_name_t *cst = lpp->csts[i];
417
418                 fprintf(f, "%16s: ", cst->name);
419                 matrix_foreach_in_row(lpp->m, cst->nr, elm) {
420                         lpp_name_t *var = lpp->vars[elm->col];
421                         /* TODO Perhaps better a define LPP_COL_RHS */
422                         if(elm->col > 0)
423                                 fprintf(f, "%+4.1f*%-16s ", elm->val, var->name);
424                 }
425
426                 fprintf(f, "%3s %+4.1f\n",
427                                 lpp_cst_op_to_str(cst->type.cst_type), matrix_get(lpp->m, cst->nr, 0));
428         }
429 }
430
431 /**
432  * Serialize a lpp to a file descriptor.
433  * @param comm The file descriptor.
434  * @param lpp The lpp.
435  */
436 void lpp_serialize(lpp_comm_t *comm, const lpp_t *lpp, int with_names)
437 {
438         int n, i;
439
440         lpp_writel(comm, with_names);
441         lpp_writel(comm, lpp->cst_next);
442         lpp_writel(comm, lpp->var_next);
443         lpp_writel(comm, lpp->opt_type);
444         lpp_writes(comm, lpp->name);
445
446         /* write options */
447         lpp_writel(comm, lpp->set_bound);
448         lpp_writed(comm, lpp->bound);
449         lpp_writed(comm, lpp->time_limit_secs);
450         lpp_writed(comm, lpp->emphasis);
451
452         for(i = 0; i < lpp->cst_next; ++i) {
453                 lpp_name_t *name = lpp->csts[i];
454                 lpp_writel(comm, name->nr);
455                 lpp_writel(comm, name->value_kind);
456                 lpp_writel(comm, name->type.cst_type);
457
458                 if(with_names)
459                         lpp_writes(comm, name->name);
460         }
461
462         for(i = 0; i < lpp->var_next; ++i) {
463                 lpp_name_t *name = lpp->vars[i];
464                 lpp_writel(comm, name->nr);
465                 lpp_writel(comm, name->value_kind);
466                 lpp_writel(comm, name->type.var_type);
467
468                 if(with_names)
469                         lpp_writes(comm, name->name);
470         }
471
472         {
473                 const matrix_elem_t *elm;
474                 n = 0;
475
476                 matrix_foreach(lpp->m, elm)
477                         n++;
478
479                 assert(n == matrix_get_entries(lpp->m));
480                 lpp_writel(comm, n);
481                 matrix_foreach(lpp->m, elm) {
482                         lpp_writel(comm, elm->row);
483                         lpp_writel(comm, elm->col);
484                         lpp_writed(comm, elm->val);
485                 }
486         }
487 }
488
489 /**
490  * Deserialize an lpp from a file descriptor.
491  * @param comm The file descriptor.
492  * @return The Problem.
493  */
494 lpp_t *lpp_deserialize(lpp_comm_t *comm)
495 {
496         int i, n;
497         int with_names;
498
499         lpp_t *lpp = XMALLOCZ(lpp_t);
500
501         /* read general settings */
502         with_names    = lpp_readl(comm);
503         lpp->cst_next = lpp_readl(comm);
504         lpp->var_next = lpp_readl(comm);
505         lpp->opt_type = lpp_readl(comm);
506         lpp->name     = lpp_reads(comm);
507
508         /* read options */
509         lpp->set_bound       = lpp_readl(comm);
510         lpp->bound           = lpp_readd(comm);
511         lpp->time_limit_secs = lpp_readd(comm);
512         lpp->emphasis        = lpp_readd(comm);
513
514         lpp->cst_size = lpp->cst_next;
515         lpp->var_size = lpp->var_next;
516
517         lpp->cst2nr   = new_set(cmp_name_t, lpp->cst_next);
518         lpp->var2nr   = new_set(cmp_name_t, lpp->var_next);
519
520         lpp->csts     = XMALLOCNZ(lpp_name_t*, lpp->cst_next);
521         lpp->vars     = XMALLOCNZ(lpp_name_t*, lpp->var_next);
522         lpp->m        = new_matrix(lpp->cst_next, lpp->var_next);
523
524         for(i = 0; i < lpp->cst_next; ++i) {
525                 lpp_name_t name, *res;
526
527                 name.nr            = lpp_readl(comm);
528                 name.value_kind    = lpp_readl(comm);
529                 name.type.cst_type = lpp_readl(comm);
530
531                 if(with_names) {
532                         name.name = lpp_reads(comm);
533                 } else {
534                         char* buf = XMALLOCN(char, 32);
535                         snprintf(buf, 32, "c%d\n", name.nr);
536                         name.name = buf;
537                 }
538
539                 res = set_insert(lpp->cst2nr, &name, sizeof(name), HASH_NAME_T(&name));
540                 lpp->csts[name.nr] = res;
541         }
542
543         for(i = 0; i < lpp->var_next; ++i) {
544                 lpp_name_t name, *res;
545
546                 name.nr            = lpp_readl(comm);
547                 name.value_kind    = lpp_readl(comm);
548                 name.type.var_type = lpp_readl(comm);
549
550                 if(with_names) {
551                         name.name = lpp_reads(comm);
552                 } else {
553                         char* buf = XMALLOCN(char, 32);
554                         snprintf(buf, 32, "v%d\n", name.nr);
555                         name.name = buf;
556                 }
557
558                 res = set_insert(lpp->var2nr, &name, sizeof(name), HASH_NAME_T(&name));
559                 lpp->vars[name.nr] = res;
560         }
561
562         n = lpp_readl(comm);
563         for(i = 0; i < n; ++i) {
564                 matrix_elem_t elm;
565                 elm.row = lpp_readl(comm);
566                 elm.col = lpp_readl(comm);
567                 elm.val = lpp_readd(comm);
568                 matrix_set(lpp->m, elm.row, elm.col, elm.val);
569         }
570
571         return lpp;
572 }
573
574 void lpp_serialize_values(lpp_comm_t *comm, const lpp_t *lpp, lpp_value_kind_t value_kind)
575 {
576         int i, n;
577
578         for(i = 0, n = 0; i < lpp->var_next; ++i)
579                 n += lpp->vars[i]->value_kind == value_kind;
580
581         /* Write the number of values to expect */
582         lpp_writel(comm, n);
583
584         /* send the values */
585         for(i = 0, n = lpp->var_next; i < n; ++i) {
586                 const lpp_name_t *name = lpp->vars[i];
587                 if(name->value_kind == value_kind) {
588                         lpp_writel(comm, name->nr);
589                         lpp_writed(comm, name->value);
590                 }
591         }
592 }
593
594 void lpp_deserialize_values(lpp_comm_t *comm, lpp_t *lpp, lpp_value_kind_t value_kind)
595 {
596         int i, n;
597
598         /* Get the number of values to read */
599         n = lpp_readl(comm);
600
601         for(i = 0; i < n; ++i) {
602                 int nr = lpp_readl(comm);
603                 lpp_name_t *name = lpp->vars[nr];
604
605                 name->value_kind = value_kind;
606                 name->value = lpp_readd(comm);
607         }
608 }
609
610 void lpp_serialize_stats(lpp_comm_t *comm, const lpp_t *lpp)
611 {
612         lpp_writel(comm, lpp->sol_state);
613         lpp_writel(comm, lpp->iterations);
614         lpp_writed(comm, lpp->sol_time);
615         lpp_writed(comm, lpp->objval);
616         lpp_writed(comm, lpp->best_bound);
617 }
618
619 void lpp_deserialize_stats(lpp_comm_t *comm, lpp_t *lpp)
620 {
621         lpp->sol_state  = lpp_readl(comm);
622         lpp->iterations = lpp_readl(comm);
623         lpp->sol_time   = lpp_readd(comm);
624         lpp->objval     = lpp_readd(comm);
625         lpp->best_bound = lpp_readd(comm);
626 }
627
628 void lpp_solve(lpp_t *lpp, const char* host, const char* solver)
629 {
630         if (host == NULL || strlen(host) == 0) {
631                 lpp_solver_func_t* f = lpp_find_solver(solver);
632                 if (f != NULL)
633                         f(lpp);
634         } else {
635                 lpp_solve_net(lpp, host, solver);
636         }
637 }
638