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