iscc: add inverse operation
[barvinok/uuh.git] / iscc.c
blob61a3f56505d8dee4d3e57ec99e249e11211d068a
1 #include <assert.h>
2 #include <stdio.h>
3 #include <string.h>
4 #include <isl_obj.h>
5 #include <isl_stream.h>
6 #include <isl_obj_list.h>
7 #include <barvinok/barvinok.h>
9 #include "config.h"
10 #ifdef HAVE_GINAC
11 #include <barvinok/bernstein.h>
12 #endif
14 static int isl_bool_false = 0;
15 static int isl_bool_true = 1;
16 static int isl_bool_error = -1;
18 static void *isl_obj_bool_copy(void *v)
20 return v;
23 static void isl_obj_bool_free(void *v)
27 static void isl_obj_bool_print(void *v, FILE *out)
29 if (v == &isl_bool_true)
30 fprintf(out, "True");
31 else if (v == &isl_bool_false)
32 fprintf(out, "False");
33 else
34 fprintf(out, "Error");
37 static void *isl_obj_bool_add(void *v1, void *v2)
39 return v1;
42 struct isl_obj_vtable isl_obj_bool_vtable = {
43 isl_obj_bool_copy,
44 isl_obj_bool_add,
45 isl_obj_bool_print,
46 isl_obj_bool_free
48 #define isl_obj_bool (&isl_obj_bool_vtable)
50 extern struct isl_obj_vtable isl_obj_list_vtable;
51 #define isl_obj_list (&isl_obj_list_vtable)
53 typedef void *(*isc_bin_op_fn)(void *lhs, void *rhs);
54 struct isc_bin_op {
55 enum isl_token_type op;
56 isl_obj_type lhs;
57 isl_obj_type rhs;
58 isl_obj_type res;
59 isc_bin_op_fn fn;
62 struct iscc_at {
63 isl_pw_qpolynomial *pwqp;
64 isl_pw_qpolynomial *res;
67 static int eval_at(__isl_take isl_point *pnt, void *user)
69 struct iscc_at *at = (struct iscc_at *) user;
70 isl_qpolynomial *qp;
71 isl_set *set;
73 set = isl_set_from_point(isl_point_copy(pnt));
74 qp = isl_pw_qpolynomial_eval(isl_pw_qpolynomial_copy(at->pwqp), pnt);
76 at->res = isl_pw_qpolynomial_add_disjoint(at->res,
77 isl_pw_qpolynomial_alloc(set, qp));
79 return 0;
82 __isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_at(
83 __isl_take isl_pw_qpolynomial *pwqp, __isl_take isl_set *set)
85 struct iscc_at at;
87 at.pwqp = pwqp;
88 at.res = isl_pw_qpolynomial_zero(isl_set_get_dim(set));
90 isl_set_foreach_point(set, eval_at, &at);
92 isl_pw_qpolynomial_free(pwqp);
93 isl_set_free(set);
95 return at.res;
98 struct iscc_fold_at {
99 isl_pw_qpolynomial_fold *pwf;
100 isl_pw_qpolynomial *res;
103 static int eval_fold_at(__isl_take isl_point *pnt, void *user)
105 struct iscc_fold_at *at = (struct iscc_fold_at *) user;
106 isl_qpolynomial *qp;
107 isl_set *set;
109 set = isl_set_from_point(isl_point_copy(pnt));
110 qp = isl_pw_qpolynomial_fold_eval(isl_pw_qpolynomial_fold_copy(at->pwf),
111 pnt);
113 at->res = isl_pw_qpolynomial_add_disjoint(at->res,
114 isl_pw_qpolynomial_alloc(set, qp));
116 return 0;
119 __isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_fold_at(
120 __isl_take isl_pw_qpolynomial_fold *pwf, __isl_take isl_set *set)
122 struct iscc_fold_at at;
124 at.pwf = pwf;
125 at.res = isl_pw_qpolynomial_zero(isl_set_get_dim(set));
127 isl_set_foreach_point(set, eval_fold_at, &at);
129 isl_pw_qpolynomial_fold_free(pwf);
130 isl_set_free(set);
132 return at.res;
135 struct isc_bin_op bin_ops[] = {
136 { '+', isl_obj_set, isl_obj_set,
137 isl_obj_set,
138 (isc_bin_op_fn) &isl_set_union },
139 { '+', isl_obj_map, isl_obj_map,
140 isl_obj_map,
141 (isc_bin_op_fn) &isl_map_union },
142 { '-', isl_obj_set, isl_obj_set,
143 isl_obj_set,
144 (isc_bin_op_fn) &isl_set_subtract },
145 { '-', isl_obj_map, isl_obj_map,
146 isl_obj_map,
147 (isc_bin_op_fn) &isl_map_subtract },
148 { '*', isl_obj_set, isl_obj_set,
149 isl_obj_set,
150 (isc_bin_op_fn) &isl_set_intersect },
151 { '*', isl_obj_map, isl_obj_map,
152 isl_obj_map,
153 (isc_bin_op_fn) &isl_map_intersect },
154 { '*', isl_obj_map, isl_obj_set,
155 isl_obj_map,
156 (isc_bin_op_fn) &isl_map_intersect_domain },
157 { '.', isl_obj_map, isl_obj_map,
158 isl_obj_map,
159 (isc_bin_op_fn) &isl_map_apply_range },
160 { ISL_TOKEN_TO, isl_obj_set, isl_obj_set, isl_obj_map,
161 (isc_bin_op_fn) &isl_map_from_domain_and_range },
162 { '+', isl_obj_pw_qpolynomial, isl_obj_pw_qpolynomial,
163 isl_obj_pw_qpolynomial,
164 (isc_bin_op_fn) &isl_pw_qpolynomial_add },
165 { '-', isl_obj_pw_qpolynomial, isl_obj_pw_qpolynomial,
166 isl_obj_pw_qpolynomial,
167 (isc_bin_op_fn) &isl_pw_qpolynomial_sub },
168 { '*', isl_obj_pw_qpolynomial, isl_obj_pw_qpolynomial,
169 isl_obj_pw_qpolynomial,
170 (isc_bin_op_fn) &isl_pw_qpolynomial_mul },
171 { '*', isl_obj_pw_qpolynomial, isl_obj_set,
172 isl_obj_pw_qpolynomial,
173 (isc_bin_op_fn) &isl_pw_qpolynomial_intersect_domain },
174 { '*', isl_obj_pw_qpolynomial_fold, isl_obj_set,
175 isl_obj_pw_qpolynomial_fold,
176 (isc_bin_op_fn) &isl_pw_qpolynomial_fold_intersect_domain },
177 { '@', isl_obj_pw_qpolynomial, isl_obj_set,
178 isl_obj_pw_qpolynomial,
179 (isc_bin_op_fn) &isl_pw_qpolynomial_at },
180 { '@', isl_obj_pw_qpolynomial_fold, isl_obj_set,
181 isl_obj_pw_qpolynomial,
182 (isc_bin_op_fn) &isl_pw_qpolynomial_fold_at },
186 __isl_give isl_set *set_sample(__isl_take isl_set *set)
188 return isl_set_from_basic_set(isl_set_sample(set));
191 __isl_give isl_map *map_sample(__isl_take isl_map *map)
193 return isl_map_from_basic_map(isl_map_sample(map));
196 static __isl_give isl_set *set_affine_hull(__isl_take isl_set *set)
198 return isl_set_from_basic_set(isl_set_affine_hull(set));
201 static __isl_give isl_map *map_affine_hull(__isl_take isl_map *map)
203 return isl_map_from_basic_map(isl_map_affine_hull(map));
206 typedef void *(*isc_un_op_fn)(void *arg);
207 struct isc_un_op {
208 enum isl_token_type op;
209 isl_obj_type arg;
210 isl_obj_type res;
211 isc_un_op_fn fn;
213 struct isc_named_un_op {
214 char *name;
215 struct isc_un_op op;
217 struct isc_named_un_op named_un_ops[] = {
218 {"aff", { -1, isl_obj_map, isl_obj_map,
219 (isc_un_op_fn) &map_affine_hull } },
220 {"aff", { -1, isl_obj_set, isl_obj_set,
221 (isc_un_op_fn) &set_affine_hull } },
222 {"card", { -1, isl_obj_set, isl_obj_pw_qpolynomial,
223 (isc_un_op_fn) &isl_set_card } },
224 {"card", { -1, isl_obj_map, isl_obj_pw_qpolynomial,
225 (isc_un_op_fn) &isl_map_card } },
226 {"dom", { -1, isl_obj_map, isl_obj_set,
227 (isc_un_op_fn) &isl_map_domain } },
228 {"dom", { -1, isl_obj_pw_qpolynomial, isl_obj_set,
229 (isc_un_op_fn) &isl_pw_qpolynomial_domain } },
230 {"dom", { -1, isl_obj_pw_qpolynomial_fold, isl_obj_set,
231 (isc_un_op_fn) &isl_pw_qpolynomial_fold_domain } },
232 {"ran", { -1, isl_obj_map, isl_obj_set,
233 (isc_un_op_fn) &isl_map_range } },
234 {"lexmin", { -1, isl_obj_map, isl_obj_map,
235 (isc_un_op_fn) &isl_map_lexmin } },
236 {"lexmax", { -1, isl_obj_map, isl_obj_map,
237 (isc_un_op_fn) &isl_map_lexmax } },
238 {"lexmin", { -1, isl_obj_set, isl_obj_set,
239 (isc_un_op_fn) &isl_set_lexmin } },
240 {"lexmax", { -1, isl_obj_set, isl_obj_set,
241 (isc_un_op_fn) &isl_set_lexmax } },
242 {"sample", { -1, isl_obj_set, isl_obj_set,
243 (isc_un_op_fn) &set_sample } },
244 {"sample", { -1, isl_obj_map, isl_obj_map,
245 (isc_un_op_fn) &map_sample } },
246 {"sum", { -1, isl_obj_pw_qpolynomial, isl_obj_pw_qpolynomial,
247 (isc_un_op_fn) &isl_pw_qpolynomial_sum } },
248 #ifdef HAVE_GINAC
249 {"ub", { -1, isl_obj_pw_qpolynomial, isl_obj_pw_qpolynomial_fold,
250 (isc_un_op_fn) &isl_pw_qpolynomial_upper_bound } },
251 #endif
252 NULL
255 struct isl_named_obj {
256 char *name;
257 struct isl_obj obj;
260 static void free_obj(struct isl_obj obj)
262 obj.type->free(obj.v);
265 static int same_name(const void *entry, const void *val)
267 const struct isl_named_obj *named = (const struct isl_named_obj *)entry;
269 return !strcmp(named->name, val);
272 static int do_assign(struct isl_ctx *ctx, struct isl_hash_table *table,
273 char *name, struct isl_obj obj)
275 struct isl_hash_table_entry *entry;
276 uint32_t name_hash;
277 struct isl_named_obj *named;
279 name_hash = isl_hash_string(isl_hash_init(), name);
280 entry = isl_hash_table_find(ctx, table, name_hash, same_name, name, 1);
281 if (!entry)
282 goto error;
283 if (entry->data) {
284 named = entry->data;
285 free_obj(named->obj);
286 free(name);
287 } else {
288 named = isl_alloc_type(ctx, struct isl_named_obj);
289 if (!named)
290 goto error;
291 named->name = name;
292 entry->data = named;
294 named->obj = obj;
296 return 0;
297 error:
298 free_obj(obj);
299 free(name);
300 return -1;
303 static struct isl_obj stored_obj(struct isl_ctx *ctx,
304 struct isl_hash_table *table, char *name)
306 struct isl_obj obj = { isl_obj_none, NULL };
307 struct isl_hash_table_entry *entry;
308 uint32_t name_hash;
310 name_hash = isl_hash_string(isl_hash_init(), name);
311 entry = isl_hash_table_find(ctx, table, name_hash, same_name, name, 0);
312 if (entry) {
313 struct isl_named_obj *named;
314 named = entry->data;
315 obj = named->obj;
318 free(name);
319 obj.v = obj.type->copy(obj.v);
320 return obj;
323 static struct isc_bin_op *read_bin_op_if_available(struct isl_stream *s,
324 isl_obj_type lhs)
326 int i;
327 struct isl_token *tok;
329 tok = isl_stream_next_token(s);
330 if (!tok)
331 return NULL;
333 for (i = 0; ; ++i) {
334 if (!bin_ops[i].op)
335 break;
336 if (bin_ops[i].op != tok->type)
337 continue;
338 if (bin_ops[i].lhs != lhs)
339 continue;
341 isl_token_free(tok);
342 return &bin_ops[i];
345 isl_stream_push_token(s, tok);
347 return NULL;
350 static struct isc_un_op *read_prefix_un_op_if_available(struct isl_stream *s)
352 int i;
353 struct isl_token *tok;
355 tok = isl_stream_next_token(s);
356 if (!tok)
357 return NULL;
359 for (i = 0; ; ++i) {
360 if (!named_un_ops[i].op.op)
361 break;
362 if (named_un_ops[i].op.op != tok->type)
363 continue;
365 isl_token_free(tok);
366 return &named_un_ops[i].op;
369 isl_stream_push_token(s, tok);
371 return NULL;
374 static struct isc_un_op *find_matching_un_op(struct isc_un_op *like,
375 isl_obj_type arg)
377 int i;
379 for (i = 0; ; ++i) {
380 if (!named_un_ops[i].op.op)
381 break;
382 if (named_un_ops[i].op.op != like->op)
383 continue;
384 if (named_un_ops[i].op.arg != arg)
385 continue;
387 return &named_un_ops[i].op;
390 return NULL;
393 static int is_assign(struct isl_stream *s)
395 struct isl_token *tok;
396 struct isl_token *tok2;
397 int assign;
399 tok = isl_stream_next_token(s);
400 if (!tok)
401 return 0;
402 if (tok->type != ISL_TOKEN_IDENT) {
403 isl_stream_push_token(s, tok);
404 return 0;
407 tok2 = isl_stream_next_token(s);
408 if (!tok2) {
409 isl_stream_push_token(s, tok);
410 return 0;
412 assign = tok2->type == ISL_TOKEN_DEF;
413 isl_stream_push_token(s, tok2);
414 isl_stream_push_token(s, tok);
416 return assign;
419 static struct isl_obj read_obj(struct isl_stream *s,
420 struct isl_hash_table *table);
421 static struct isl_obj read_expr(struct isl_stream *s,
422 struct isl_hash_table *table);
424 static struct isl_obj read_un_op_expr(struct isl_stream *s,
425 struct isl_hash_table *table, struct isc_un_op *op)
427 struct isl_obj obj = { isl_obj_none, NULL };
429 obj = read_obj(s, table);
431 op = find_matching_un_op(op, obj.type);
433 isl_assert(s->ctx, op, goto error);
434 obj.v = op->fn(obj.v);
435 obj.type = op->res;
437 return obj;
438 error:
439 free_obj(obj);
440 obj.type = isl_obj_none;
441 obj.v = NULL;
442 return obj;
445 static struct isl_obj transitive_closure(struct isl_ctx *ctx, struct isl_obj obj)
447 struct isl_list *list;
448 int exact;
450 isl_assert(ctx, obj.type == isl_obj_map, goto error);
451 list = isl_list_alloc(ctx, 2);
452 if (!list)
453 goto error;
455 list->obj[0].type = isl_obj_map;
456 list->obj[0].v = isl_map_transitive_closure(obj.v, &exact);
457 list->obj[1].type = isl_obj_bool;
458 list->obj[1].v = exact ? &isl_bool_true : &isl_bool_false;
459 obj.v = list;
460 obj.type = isl_obj_list;
461 if (exact < 0 || !list->obj[0].v)
462 goto error;
464 return obj;
465 error:
466 free_obj(obj);
467 obj.type = isl_obj_none;
468 obj.v = NULL;
469 return obj;
472 static struct isl_obj obj_at_index(struct isl_stream *s, struct isl_obj obj)
474 struct isl_list *list = obj.v;
475 struct isl_token *tok;
476 int i;
478 tok = isl_stream_next_token(s);
479 if (!tok || tok->type != ISL_TOKEN_VALUE) {
480 isl_stream_error(s, tok, "expecting index");
481 if (tok)
482 isl_stream_push_token(s, tok);
483 goto error;
485 i = isl_int_get_si(tok->u.v);
486 isl_token_free(tok);
487 isl_assert(s, i < list->n, goto error);
488 if (isl_stream_eat(s, ']'))
489 goto error;
491 obj = list->obj[i];
492 obj.v = obj.type->copy(obj.v);
494 isl_list_free(list);
496 return obj;
497 error:
498 free_obj(obj);
499 obj.type = isl_obj_none;
500 obj.v = NULL;
501 return obj;
504 static struct isl_obj power(struct isl_stream *s, struct isl_obj obj)
506 struct isl_token *tok;
508 if (isl_stream_eat_if_available(s, '+'))
509 return transitive_closure(s->ctx, obj);
511 tok = isl_stream_next_token(s);
512 if (!tok || tok->type != ISL_TOKEN_VALUE || isl_int_cmp_si(tok->u.v, -1)) {
513 isl_stream_error(s, tok, "expecting -1");
514 if (tok)
515 isl_stream_push_token(s, tok);
516 goto error;
518 isl_token_free(tok);
519 isl_assert(s->ctx, obj.type == isl_obj_map, goto error);
521 obj.v = isl_map_reverse(obj.v);
522 if (!obj.v)
523 goto error;
525 return obj;
526 error:
527 free_obj(obj);
528 obj.type = isl_obj_none;
529 obj.v = NULL;
530 return obj;
533 static struct isl_obj read_obj(struct isl_stream *s,
534 struct isl_hash_table *table)
536 struct isl_obj obj = { isl_obj_none, NULL };
537 char *name = NULL;
538 struct isc_un_op *op = NULL;
540 if (isl_stream_eat_if_available(s, '(')) {
541 obj = read_expr(s, table);
542 if (isl_stream_eat(s, ')'))
543 goto error;
544 } else {
545 op = read_prefix_un_op_if_available(s);
546 if (op)
547 return read_un_op_expr(s, table, op);
549 name = isl_stream_read_ident_if_available(s);
550 if (name) {
551 obj = stored_obj(s->ctx, table, name);
552 } else {
553 obj = isl_stream_read_obj(s);
554 assert(obj.v);
558 if (isl_stream_eat_if_available(s, '^'))
559 obj = power(s, obj);
560 else if (obj.type == isl_obj_list && isl_stream_eat_if_available(s, '['))
561 obj = obj_at_index(s, obj);
563 return obj;
564 error:
565 free_obj(obj);
566 obj.type = isl_obj_none;
567 obj.v = NULL;
568 return obj;
571 static struct isc_bin_op *find_matching_bin_op(struct isc_bin_op *like,
572 isl_obj_type lhs, isl_obj_type rhs)
574 int i;
576 for (i = 0; ; ++i) {
577 if (!bin_ops[i].op)
578 break;
579 if (bin_ops[i].op != like->op)
580 continue;
581 if (bin_ops[i].lhs != lhs)
582 continue;
583 if (bin_ops[i].rhs != rhs)
584 continue;
586 return &bin_ops[i];
589 return NULL;
592 static struct isl_obj read_expr(struct isl_stream *s,
593 struct isl_hash_table *table)
595 struct isl_obj obj = { isl_obj_none, NULL };
596 struct isl_obj right_obj = { isl_obj_none, NULL };
598 obj = read_obj(s, table);
599 for (;;) {
600 struct isc_bin_op *op = NULL;
602 op = read_bin_op_if_available(s, obj.type);
603 if (!op)
604 break;
606 right_obj = read_obj(s, table);
608 op = find_matching_bin_op(op, obj.type, right_obj.type);
610 isl_assert(s->ctx, op, goto error);
611 obj.v = op->fn(obj.v, right_obj.v);
612 obj.type = op->res;
615 return obj;
616 error:
617 free_obj(right_obj);
618 free_obj(obj);
619 obj.type = isl_obj_none;
620 obj.v = NULL;
621 return obj;
624 static void read_line(struct isl_stream *s, struct isl_hash_table *table)
626 struct isl_obj obj = { isl_obj_none, NULL };
627 char *lhs = NULL;
628 int assign = 0;
629 struct isc_bin_op *op = NULL;
631 if (isl_stream_is_empty(s))
632 return;
634 assign = is_assign(s);
635 if (assign) {
636 lhs = isl_stream_read_ident_if_available(s);
637 if (isl_stream_eat(s, ISL_TOKEN_DEF))
638 goto error;
641 obj = read_expr(s, table);
642 if (obj.type == isl_obj_none || obj.v == NULL)
643 goto error;
644 if (isl_stream_eat(s, ';'))
645 goto error;
647 if (assign) {
648 if (do_assign(s->ctx, table, lhs, obj))
649 return;
650 } else {
651 obj.type->print(obj.v, stdout);
652 printf("\n");
653 free_obj(obj);
656 return;
657 error:
658 free(lhs);
659 free_obj(obj);
662 int free_cb(void *entry)
664 struct isl_named_obj *named = entry;
666 free_obj(named->obj);
667 free(named->name);
668 free(named);
670 return 0;
673 static void register_named_ops(struct isl_stream *s)
675 int i;
677 for (i = 0; ; ++i) {
678 if (!named_un_ops[i].name)
679 break;
680 named_un_ops[i].op.op = isl_stream_register_keyword(s,
681 named_un_ops[i].name);
682 assert(named_un_ops[i].op.op != ISL_TOKEN_ERROR);
686 int main(int argc, char **argv)
688 struct isl_ctx *ctx;
689 struct isl_stream *s;
690 struct isl_hash_table *table;
692 ctx = isl_ctx_alloc();
693 s = isl_stream_new_file(ctx, stdin);
694 assert(s);
695 table = isl_hash_table_alloc(ctx, 10);
696 assert(table);
698 register_named_ops(s);
700 while (!feof(stdin)) {
701 read_line(s, table);
704 isl_hash_table_foreach(ctx, table, free_cb);
705 isl_hash_table_free(ctx, table);
706 isl_stream_free(s);
707 isl_ctx_free(ctx);
709 return 0;