| 1 | /* |
| 2 | * Copyright 2008-2009 Katholieke Universiteit Leuven |
| 3 | * Copyright 2010 INRIA Saclay |
| 4 | * Copyright 2012-2013 Ecole Normale Superieure |
| 5 | * Copyright 2019 Cerebras Systems |
| 6 | * |
| 7 | * Use of this software is governed by the MIT license |
| 8 | * |
| 9 | * Written by Sven Verdoolaege, K.U.Leuven, Departement |
| 10 | * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium |
| 11 | * and INRIA Saclay - Ile-de-France, Parc Club Orsay Universite, |
| 12 | * ZAC des vignes, 4 rue Jacques Monod, 91893 Orsay, France |
| 13 | * and Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France |
| 14 | * and Cerebras Systems, 175 S San Antonio Rd, Los Altos, CA, USA |
| 15 | */ |
| 16 | |
| 17 | #include <stdlib.h> |
| 18 | #include <string.h> |
| 19 | #include <isl_ctx_private.h> |
| 20 | #include <isl_map_private.h> |
| 21 | #include <isl/set.h> |
| 22 | #include <isl_seq.h> |
| 23 | #include <isl_polynomial_private.h> |
| 24 | #include <isl_printer_private.h> |
| 25 | #include <isl_space_private.h> |
| 26 | #include <isl_mat_private.h> |
| 27 | #include <isl_vec_private.h> |
| 28 | #include <isl/union_set.h> |
| 29 | #include <isl/union_map.h> |
| 30 | #include <isl/constraint.h> |
| 31 | #include <isl_local.h> |
| 32 | #include <isl_local_space_private.h> |
| 33 | #include <isl_aff_private.h> |
| 34 | #include <isl_id_private.h> |
| 35 | #include <isl_val_private.h> |
| 36 | #include <isl_constraint_private.h> |
| 37 | #include <isl/ast_build.h> |
| 38 | #include <isl_sort.h> |
| 39 | #include <isl_output_private.h> |
| 40 | |
| 41 | #include <bset_to_bmap.c> |
| 42 | #include <set_to_map.c> |
| 43 | #include <uset_to_umap.c> |
| 44 | |
| 45 | static const char *s_to[2] = { " -> " , " \\to " }; |
| 46 | static const char *s_and[2] = { " and " , " \\wedge " }; |
| 47 | static const char *s_or[2] = { " or " , " \\vee " }; |
| 48 | static const char *s_le[2] = { "<=" , "\\le" }; |
| 49 | static const char *s_ge[2] = { ">=" , "\\ge" }; |
| 50 | static const char *s_open_set[2] = { "{ " , "\\{\\, " }; |
| 51 | static const char *s_close_set[2] = { " }" , " \\,\\}" }; |
| 52 | static const char *s_open_list[2] = { "[" , "(" }; |
| 53 | static const char *s_close_list[2] = { "]" , ")" }; |
| 54 | static const char *s_such_that[2] = { " : " , " \\mid " }; |
| 55 | static const char *s_open_exists[2] = { "exists (" , "\\exists \\, " }; |
| 56 | static const char *s_close_exists[2] = { ")" , "" }; |
| 57 | static const char *s_div_prefix[2] = { "e" , "\\alpha_" }; |
| 58 | static const char *s_mod[2] = { "mod" , "\\bmod" }; |
| 59 | static const char *s_param_prefix[2] = { "p" , "p_" }; |
| 60 | static const char *s_input_prefix[2] = { "i" , "i_" }; |
| 61 | static const char *s_output_prefix[2] = { "o" , "o_" }; |
| 62 | |
| 63 | static __isl_give isl_printer *print_constraint_polylib( |
| 64 | struct isl_basic_map *bmap, int ineq, int n, __isl_take isl_printer *p) |
| 65 | { |
| 66 | int i; |
| 67 | isl_size n_in = isl_basic_map_dim(bmap, type: isl_dim_in); |
| 68 | isl_size n_out = isl_basic_map_dim(bmap, type: isl_dim_out); |
| 69 | isl_size nparam = isl_basic_map_dim(bmap, type: isl_dim_param); |
| 70 | isl_int *c = ineq ? bmap->ineq[n] : bmap->eq[n]; |
| 71 | |
| 72 | if (n_in < 0 || n_out < 0 || nparam < 0) |
| 73 | return isl_printer_free(printer: p); |
| 74 | |
| 75 | p = isl_printer_start_line(p); |
| 76 | p = isl_printer_print_int(p, i: ineq); |
| 77 | for (i = 0; i < n_out; ++i) { |
| 78 | p = isl_printer_print_str(p, s: " " ); |
| 79 | p = isl_printer_print_isl_int(p, i: c[1+nparam+n_in+i]); |
| 80 | } |
| 81 | for (i = 0; i < n_in; ++i) { |
| 82 | p = isl_printer_print_str(p, s: " " ); |
| 83 | p = isl_printer_print_isl_int(p, i: c[1+nparam+i]); |
| 84 | } |
| 85 | for (i = 0; i < bmap->n_div; ++i) { |
| 86 | p = isl_printer_print_str(p, s: " " ); |
| 87 | p = isl_printer_print_isl_int(p, i: c[1+nparam+n_in+n_out+i]); |
| 88 | } |
| 89 | for (i = 0; i < nparam; ++i) { |
| 90 | p = isl_printer_print_str(p, s: " " ); |
| 91 | p = isl_printer_print_isl_int(p, i: c[1+i]); |
| 92 | } |
| 93 | p = isl_printer_print_str(p, s: " " ); |
| 94 | p = isl_printer_print_isl_int(p, i: c[0]); |
| 95 | p = isl_printer_end_line(p); |
| 96 | return p; |
| 97 | } |
| 98 | |
| 99 | static __isl_give isl_printer *print_constraints_polylib( |
| 100 | struct isl_basic_map *bmap, __isl_take isl_printer *p) |
| 101 | { |
| 102 | int i; |
| 103 | |
| 104 | p = isl_printer_set_isl_int_width(p, width: 5); |
| 105 | |
| 106 | for (i = 0; i < bmap->n_eq; ++i) |
| 107 | p = print_constraint_polylib(bmap, ineq: 0, n: i, p); |
| 108 | for (i = 0; i < bmap->n_ineq; ++i) |
| 109 | p = print_constraint_polylib(bmap, ineq: 1, n: i, p); |
| 110 | |
| 111 | return p; |
| 112 | } |
| 113 | |
| 114 | static __isl_give isl_printer *bset_print_constraints_polylib( |
| 115 | struct isl_basic_set *bset, __isl_take isl_printer *p) |
| 116 | { |
| 117 | return print_constraints_polylib(bmap: bset_to_bmap(bset), p); |
| 118 | } |
| 119 | |
| 120 | static __isl_give isl_printer *isl_basic_map_print_polylib( |
| 121 | __isl_keep isl_basic_map *bmap, __isl_take isl_printer *p, int ext) |
| 122 | { |
| 123 | isl_size total; |
| 124 | |
| 125 | total = isl_basic_map_dim(bmap, type: isl_dim_all); |
| 126 | if (total < 0) |
| 127 | return isl_printer_free(printer: p); |
| 128 | p = isl_printer_start_line(p); |
| 129 | p = isl_printer_print_int(p, i: bmap->n_eq + bmap->n_ineq); |
| 130 | p = isl_printer_print_str(p, s: " " ); |
| 131 | p = isl_printer_print_int(p, i: 1 + total + 1); |
| 132 | if (ext) { |
| 133 | isl_size n_in = isl_basic_map_dim(bmap, type: isl_dim_in); |
| 134 | isl_size n_out = isl_basic_map_dim(bmap, type: isl_dim_out); |
| 135 | isl_size n_div = isl_basic_map_dim(bmap, type: isl_dim_div); |
| 136 | isl_size nparam = isl_basic_map_dim(bmap, type: isl_dim_param); |
| 137 | |
| 138 | if (n_in < 0 || n_out < 0 || n_div < 0 || nparam < 0) |
| 139 | return isl_printer_free(printer: p); |
| 140 | |
| 141 | p = isl_printer_print_str(p, s: " " ); |
| 142 | p = isl_printer_print_int(p, i: n_out); |
| 143 | p = isl_printer_print_str(p, s: " " ); |
| 144 | p = isl_printer_print_int(p, i: n_in); |
| 145 | p = isl_printer_print_str(p, s: " " ); |
| 146 | p = isl_printer_print_int(p, i: n_div); |
| 147 | p = isl_printer_print_str(p, s: " " ); |
| 148 | p = isl_printer_print_int(p, i: nparam); |
| 149 | } |
| 150 | p = isl_printer_end_line(p); |
| 151 | return print_constraints_polylib(bmap, p); |
| 152 | } |
| 153 | |
| 154 | static __isl_give isl_printer *isl_basic_set_print_polylib( |
| 155 | __isl_keep isl_basic_set *bset, __isl_take isl_printer *p, int ext) |
| 156 | { |
| 157 | return isl_basic_map_print_polylib(bmap: bset_to_bmap(bset), p, ext); |
| 158 | } |
| 159 | |
| 160 | static __isl_give isl_printer *isl_map_print_polylib(__isl_keep isl_map *map, |
| 161 | __isl_take isl_printer *p, int ext) |
| 162 | { |
| 163 | int i; |
| 164 | |
| 165 | p = isl_printer_start_line(p); |
| 166 | p = isl_printer_print_int(p, i: map->n); |
| 167 | p = isl_printer_end_line(p); |
| 168 | for (i = 0; i < map->n; ++i) { |
| 169 | p = isl_printer_start_line(p); |
| 170 | p = isl_printer_end_line(p); |
| 171 | p = isl_basic_map_print_polylib(bmap: map->p[i], p, ext); |
| 172 | } |
| 173 | return p; |
| 174 | } |
| 175 | |
| 176 | static __isl_give isl_printer *isl_set_print_polylib(__isl_keep isl_set *set, |
| 177 | __isl_take isl_printer *p, int ext) |
| 178 | { |
| 179 | return isl_map_print_polylib(map: set_to_map(set), p, ext); |
| 180 | } |
| 181 | |
| 182 | static isl_size count_same_name(__isl_keep isl_space *space, |
| 183 | enum isl_dim_type type, unsigned pos, const char *name) |
| 184 | { |
| 185 | enum isl_dim_type t; |
| 186 | int p; |
| 187 | isl_size s; |
| 188 | int count = 0; |
| 189 | |
| 190 | for (t = isl_dim_param; t <= type && t <= isl_dim_out; ++t) { |
| 191 | s = t == type ? pos : isl_space_dim(space, type: t); |
| 192 | if (s < 0) |
| 193 | return isl_size_error; |
| 194 | for (p = 0; p < s; ++p) { |
| 195 | const char *n = isl_space_get_dim_name(space, type: t, pos: p); |
| 196 | if (n && !strcmp(s1: n, s2: name)) |
| 197 | count++; |
| 198 | } |
| 199 | } |
| 200 | return count; |
| 201 | } |
| 202 | |
| 203 | /* Print the name of the variable of type "type" and position "pos" |
| 204 | * in "space" to "p". |
| 205 | */ |
| 206 | static __isl_give isl_printer *print_name(__isl_keep isl_space *space, |
| 207 | __isl_take isl_printer *p, enum isl_dim_type type, unsigned pos, |
| 208 | int latex) |
| 209 | { |
| 210 | const char *name; |
| 211 | char buffer[20]; |
| 212 | isl_size primes; |
| 213 | |
| 214 | name = type == isl_dim_div ? NULL |
| 215 | : isl_space_get_dim_name(space, type, pos); |
| 216 | |
| 217 | if (!name) { |
| 218 | const char *prefix; |
| 219 | if (type == isl_dim_param) |
| 220 | prefix = s_param_prefix[latex]; |
| 221 | else if (type == isl_dim_div) |
| 222 | prefix = s_div_prefix[latex]; |
| 223 | else if (isl_space_is_set(space) || type == isl_dim_in) |
| 224 | prefix = s_input_prefix[latex]; |
| 225 | else |
| 226 | prefix = s_output_prefix[latex]; |
| 227 | snprintf(s: buffer, maxlen: sizeof(buffer), format: "%s%d" , prefix, pos); |
| 228 | name = buffer; |
| 229 | } |
| 230 | primes = count_same_name(space, type: name == buffer ? isl_dim_div : type, |
| 231 | pos, name); |
| 232 | if (primes < 0) |
| 233 | return isl_printer_free(printer: p); |
| 234 | p = isl_printer_print_str(p, s: name); |
| 235 | while (primes-- > 0) |
| 236 | p = isl_printer_print_str(p, s: "'" ); |
| 237 | return p; |
| 238 | } |
| 239 | |
| 240 | static isl_stat pos2type(__isl_keep isl_space *space, |
| 241 | enum isl_dim_type *type, unsigned *pos) |
| 242 | { |
| 243 | isl_size n_in = isl_space_dim(space, type: isl_dim_in); |
| 244 | isl_size n_out = isl_space_dim(space, type: isl_dim_out); |
| 245 | isl_size nparam = isl_space_dim(space, type: isl_dim_param); |
| 246 | |
| 247 | if (n_in < 0 || n_out < 0 || nparam < 0) |
| 248 | return isl_stat_error; |
| 249 | |
| 250 | if (*pos < 1 + nparam) { |
| 251 | *type = isl_dim_param; |
| 252 | *pos -= 1; |
| 253 | } else if (*pos < 1 + nparam + n_in) { |
| 254 | *type = isl_dim_in; |
| 255 | *pos -= 1 + nparam; |
| 256 | } else if (*pos < 1 + nparam + n_in + n_out) { |
| 257 | *type = isl_dim_out; |
| 258 | *pos -= 1 + nparam + n_in; |
| 259 | } else { |
| 260 | *type = isl_dim_div; |
| 261 | *pos -= 1 + nparam + n_in + n_out; |
| 262 | } |
| 263 | |
| 264 | return isl_stat_ok; |
| 265 | } |
| 266 | |
| 267 | /* Can the div expression of the integer division at position "row" of "div" |
| 268 | * be printed? |
| 269 | * In particular, are the div expressions available and does the selected |
| 270 | * variable have a known explicit representation? |
| 271 | * Furthermore, the Omega format does not allow any div expressions |
| 272 | * to be printed. |
| 273 | */ |
| 274 | static isl_bool can_print_div_expr(__isl_keep isl_printer *p, |
| 275 | __isl_keep isl_mat *div, int pos) |
| 276 | { |
| 277 | if (p->output_format == ISL_FORMAT_OMEGA) |
| 278 | return isl_bool_false; |
| 279 | if (!div) |
| 280 | return isl_bool_false; |
| 281 | return isl_bool_not(b: isl_local_div_is_marked_unknown(local: div, pos)); |
| 282 | } |
| 283 | |
| 284 | static __isl_give isl_printer *print_div(__isl_keep isl_space *space, |
| 285 | __isl_keep isl_mat *div, int pos, __isl_take isl_printer *p); |
| 286 | |
| 287 | static __isl_give isl_printer *print_term(__isl_keep isl_space *space, |
| 288 | __isl_keep isl_mat *div, |
| 289 | isl_int c, unsigned pos, __isl_take isl_printer *p, int latex) |
| 290 | { |
| 291 | enum isl_dim_type type; |
| 292 | int print_div_def; |
| 293 | |
| 294 | if (!p || !space) |
| 295 | return isl_printer_free(printer: p); |
| 296 | |
| 297 | if (pos == 0) |
| 298 | return isl_printer_print_isl_int(p, i: c); |
| 299 | |
| 300 | if (pos2type(space, type: &type, pos: &pos) < 0) |
| 301 | return isl_printer_free(printer: p); |
| 302 | print_div_def = type == isl_dim_div && can_print_div_expr(p, div, pos); |
| 303 | |
| 304 | if (isl_int_is_one(c)) |
| 305 | ; |
| 306 | else if (isl_int_is_negone(c)) |
| 307 | p = isl_printer_print_str(p, s: "-" ); |
| 308 | else { |
| 309 | p = isl_printer_print_isl_int(p, i: c); |
| 310 | if (p->output_format == ISL_FORMAT_C || print_div_def) |
| 311 | p = isl_printer_print_str(p, s: "*" ); |
| 312 | } |
| 313 | if (print_div_def) |
| 314 | p = print_div(space, div, pos, p); |
| 315 | else |
| 316 | p = print_name(space, p, type, pos, latex); |
| 317 | return p; |
| 318 | } |
| 319 | |
| 320 | static __isl_give isl_printer *print_affine_of_len(__isl_keep isl_space *space, |
| 321 | __isl_keep isl_mat *div, |
| 322 | __isl_take isl_printer *p, isl_int *c, int len) |
| 323 | { |
| 324 | int i; |
| 325 | int first; |
| 326 | |
| 327 | for (i = 0, first = 1; i < len; ++i) { |
| 328 | int flip = 0; |
| 329 | if (isl_int_is_zero(c[i])) |
| 330 | continue; |
| 331 | if (!first) { |
| 332 | if (isl_int_is_neg(c[i])) { |
| 333 | flip = 1; |
| 334 | isl_int_neg(c[i], c[i]); |
| 335 | p = isl_printer_print_str(p, s: " - " ); |
| 336 | } else |
| 337 | p = isl_printer_print_str(p, s: " + " ); |
| 338 | } |
| 339 | first = 0; |
| 340 | p = print_term(space, div, c: c[i], pos: i, p, latex: 0); |
| 341 | if (flip) |
| 342 | isl_int_neg(c[i], c[i]); |
| 343 | } |
| 344 | if (first) |
| 345 | p = isl_printer_print_str(p, s: "0" ); |
| 346 | return p; |
| 347 | } |
| 348 | |
| 349 | /* Print an affine expression "c" |
| 350 | * to "p", with the variable names taken from "space" and |
| 351 | * the integer division definitions taken from "div". |
| 352 | */ |
| 353 | static __isl_give isl_printer *print_affine(__isl_take isl_printer *p, |
| 354 | __isl_keep isl_space *space, __isl_keep isl_mat *div, isl_int *c) |
| 355 | { |
| 356 | isl_size n_div, total; |
| 357 | unsigned len; |
| 358 | |
| 359 | total = isl_space_dim(space, type: isl_dim_all); |
| 360 | n_div = isl_mat_rows(mat: div); |
| 361 | if (total < 0 || n_div < 0) |
| 362 | return isl_printer_free(printer: p); |
| 363 | len = 1 + total + n_div; |
| 364 | return print_affine_of_len(space, div, p, c, len); |
| 365 | } |
| 366 | |
| 367 | /* offset is the offset of local_space inside data->type of data->space. |
| 368 | */ |
| 369 | static __isl_give isl_printer *print_nested_var_list(__isl_take isl_printer *p, |
| 370 | __isl_keep isl_space *local_space, enum isl_dim_type local_type, |
| 371 | struct isl_print_space_data *data, int offset) |
| 372 | { |
| 373 | int i; |
| 374 | isl_size dim; |
| 375 | |
| 376 | if (data->space != local_space && local_type == isl_dim_out) |
| 377 | offset += local_space->n_in; |
| 378 | |
| 379 | dim = isl_space_dim(space: local_space, type: local_type); |
| 380 | if (dim < 0) |
| 381 | return isl_printer_free(printer: p); |
| 382 | for (i = 0; i < dim; ++i) { |
| 383 | if (i) |
| 384 | p = isl_printer_print_str(p, s: ", " ); |
| 385 | if (data->print_dim) |
| 386 | p = data->print_dim(p, data, offset + i); |
| 387 | else |
| 388 | p = print_name(space: data->space, p, type: data->type, pos: offset + i, |
| 389 | latex: data->latex); |
| 390 | } |
| 391 | return p; |
| 392 | } |
| 393 | |
| 394 | static __isl_give isl_printer *print_var_list(__isl_take isl_printer *p, |
| 395 | __isl_keep isl_space *space, enum isl_dim_type type) |
| 396 | { |
| 397 | struct isl_print_space_data data = { .space = space, .type = type }; |
| 398 | |
| 399 | return print_nested_var_list(p, local_space: space, local_type: type, data: &data, offset: 0); |
| 400 | } |
| 401 | |
| 402 | static __isl_give isl_printer *print_nested_map_dim(__isl_take isl_printer *p, |
| 403 | __isl_keep isl_space *local_dim, |
| 404 | struct isl_print_space_data *data, int offset); |
| 405 | |
| 406 | static __isl_give isl_printer *print_nested_tuple(__isl_take isl_printer *p, |
| 407 | __isl_keep isl_space *local_space, enum isl_dim_type local_type, |
| 408 | struct isl_print_space_data *data, int offset) |
| 409 | { |
| 410 | const char *name = NULL; |
| 411 | isl_size n = isl_space_dim(space: local_space, type: local_type); |
| 412 | |
| 413 | if (n < 0) |
| 414 | return isl_printer_free(printer: p); |
| 415 | if ((local_type == isl_dim_in || local_type == isl_dim_out)) { |
| 416 | name = isl_space_get_tuple_name(space: local_space, type: local_type); |
| 417 | if (name) { |
| 418 | if (data->latex) |
| 419 | p = isl_printer_print_str(p, s: "\\mathrm{" ); |
| 420 | p = isl_printer_print_str(p, s: name); |
| 421 | if (data->latex) |
| 422 | p = isl_printer_print_str(p, s: "}" ); |
| 423 | } |
| 424 | } |
| 425 | if (!data->latex || n != 1 || name) |
| 426 | p = isl_printer_print_str(p, s: s_open_list[data->latex]); |
| 427 | if ((local_type == isl_dim_in || local_type == isl_dim_out) && |
| 428 | local_space->nested[local_type - isl_dim_in]) { |
| 429 | if (data->space != local_space && local_type == isl_dim_out) |
| 430 | offset += local_space->n_in; |
| 431 | p = print_nested_map_dim(p, |
| 432 | local_dim: local_space->nested[local_type - isl_dim_in], |
| 433 | data, offset); |
| 434 | } else |
| 435 | p = print_nested_var_list(p, local_space, local_type, data, |
| 436 | offset); |
| 437 | if (!data->latex || n != 1 || name) |
| 438 | p = isl_printer_print_str(p, s: s_close_list[data->latex]); |
| 439 | return p; |
| 440 | } |
| 441 | |
| 442 | static __isl_give isl_printer *print_tuple(__isl_keep isl_space *space, |
| 443 | __isl_take isl_printer *p, enum isl_dim_type type, |
| 444 | struct isl_print_space_data *data) |
| 445 | { |
| 446 | data->space = space; |
| 447 | data->type = type; |
| 448 | return print_nested_tuple(p, local_space: space, local_type: type, data, offset: 0); |
| 449 | } |
| 450 | |
| 451 | static __isl_give isl_printer *print_nested_map_dim(__isl_take isl_printer *p, |
| 452 | __isl_keep isl_space *local_dim, |
| 453 | struct isl_print_space_data *data, int offset) |
| 454 | { |
| 455 | p = print_nested_tuple(p, local_space: local_dim, local_type: isl_dim_in, data, offset); |
| 456 | p = isl_printer_print_str(p, s: s_to[data->latex]); |
| 457 | p = print_nested_tuple(p, local_space: local_dim, local_type: isl_dim_out, data, offset); |
| 458 | |
| 459 | return p; |
| 460 | } |
| 461 | |
| 462 | __isl_give isl_printer *isl_print_space(__isl_keep isl_space *space, |
| 463 | __isl_take isl_printer *p, int rational, |
| 464 | struct isl_print_space_data *data) |
| 465 | { |
| 466 | if (rational && !data->latex) |
| 467 | p = isl_printer_print_str(p, s: "rat: " ); |
| 468 | if (isl_space_is_params(space)) |
| 469 | ; |
| 470 | else if (isl_space_is_set(space)) |
| 471 | p = print_tuple(space, p, type: isl_dim_set, data); |
| 472 | else { |
| 473 | p = print_tuple(space, p, type: isl_dim_in, data); |
| 474 | p = isl_printer_print_str(p, s: s_to[data->latex]); |
| 475 | p = print_tuple(space, p, type: isl_dim_out, data); |
| 476 | } |
| 477 | |
| 478 | return p; |
| 479 | } |
| 480 | |
| 481 | static __isl_give isl_printer *print_omega_parameters( |
| 482 | __isl_keep isl_space *space, __isl_take isl_printer *p) |
| 483 | { |
| 484 | isl_size nparam = isl_space_dim(space, type: isl_dim_param); |
| 485 | |
| 486 | if (nparam < 0) |
| 487 | return isl_printer_free(printer: p); |
| 488 | if (nparam == 0) |
| 489 | return p; |
| 490 | |
| 491 | p = isl_printer_start_line(p); |
| 492 | p = isl_printer_print_str(p, s: "symbolic " ); |
| 493 | p = print_var_list(p, space, type: isl_dim_param); |
| 494 | p = isl_printer_print_str(p, s: ";" ); |
| 495 | p = isl_printer_end_line(p); |
| 496 | return p; |
| 497 | } |
| 498 | |
| 499 | /* Does the inequality constraint following "i" in "bmap" |
| 500 | * have an opposite value for the same last coefficient? |
| 501 | * "last" is the position of the last coefficient of inequality "i". |
| 502 | * If the next constraint is a div constraint, then it is ignored |
| 503 | * since div constraints are not printed. |
| 504 | */ |
| 505 | static isl_bool next_is_opposite(__isl_keep isl_basic_map *bmap, int i, |
| 506 | int last) |
| 507 | { |
| 508 | int r; |
| 509 | isl_size total = isl_basic_map_dim(bmap, type: isl_dim_all); |
| 510 | unsigned o_div = isl_basic_map_offset(bmap, type: isl_dim_div); |
| 511 | |
| 512 | if (total < 0) |
| 513 | return isl_bool_error; |
| 514 | if (i + 1 >= bmap->n_ineq) |
| 515 | return isl_bool_false; |
| 516 | if (isl_seq_last_non_zero(p: bmap->ineq[i + 1], len: 1 + total) != last) |
| 517 | return isl_bool_false; |
| 518 | if (last >= o_div) { |
| 519 | isl_bool is_div; |
| 520 | is_div = isl_basic_map_is_div_constraint(bmap, |
| 521 | constraint: bmap->ineq[i + 1], div: last - o_div); |
| 522 | if (is_div < 0) |
| 523 | return isl_bool_error; |
| 524 | if (is_div) |
| 525 | return isl_bool_false; |
| 526 | } |
| 527 | r = isl_int_abs_eq(bmap->ineq[i][last], bmap->ineq[i + 1][last]) && |
| 528 | !isl_int_eq(bmap->ineq[i][last], bmap->ineq[i + 1][last]); |
| 529 | return isl_bool_ok(b: r); |
| 530 | } |
| 531 | |
| 532 | /* Return a string representation of the operator used when |
| 533 | * printing a constraint where the LHS is greater than or equal to the LHS |
| 534 | * (sign > 0) or smaller than or equal to the LHS (sign < 0). |
| 535 | * If "strict" is set, then return the strict version of the comparison |
| 536 | * operator. |
| 537 | */ |
| 538 | static const char *constraint_op(int sign, int strict, int latex) |
| 539 | { |
| 540 | if (strict) |
| 541 | return sign < 0 ? "<" : ">" ; |
| 542 | if (sign < 0) |
| 543 | return s_le[latex]; |
| 544 | else |
| 545 | return s_ge[latex]; |
| 546 | } |
| 547 | |
| 548 | /* Print one side of a constraint "c" to "p", with |
| 549 | * the variable names taken from "space" and the integer division definitions |
| 550 | * taken from "div". |
| 551 | * "last" is the position of the last non-zero coefficient. |
| 552 | * Let c' be the result of zeroing out this coefficient, then |
| 553 | * the partial constraint |
| 554 | * |
| 555 | * c' op |
| 556 | * |
| 557 | * is printed. |
| 558 | */ |
| 559 | static __isl_give isl_printer *print_half_constraint(__isl_take isl_printer *p, |
| 560 | __isl_keep isl_space *space, __isl_keep isl_mat *div, |
| 561 | isl_int *c, int last, const char *op, int latex) |
| 562 | { |
| 563 | isl_int_set_si(c[last], 0); |
| 564 | p = print_affine(p, space, div, c); |
| 565 | |
| 566 | p = isl_printer_print_str(p, s: " " ); |
| 567 | p = isl_printer_print_str(p, s: op); |
| 568 | p = isl_printer_print_str(p, s: " " ); |
| 569 | |
| 570 | return p; |
| 571 | } |
| 572 | |
| 573 | /* Print a constraint "c" to "p", with the variable names |
| 574 | * taken from "space" and the integer division definitions taken from "div". |
| 575 | * "last" is the position of the last non-zero coefficient, which is |
| 576 | * moreover assumed to be negative. |
| 577 | * Let c' be the result of zeroing out this coefficient, then |
| 578 | * the constraint is printed in the form |
| 579 | * |
| 580 | * -c[last] op c' |
| 581 | */ |
| 582 | static __isl_give isl_printer *print_constraint(__isl_take isl_printer *p, |
| 583 | __isl_keep isl_space *space, __isl_keep isl_mat *div, |
| 584 | isl_int *c, int last, const char *op, int latex) |
| 585 | { |
| 586 | isl_int_abs(c[last], c[last]); |
| 587 | |
| 588 | p = print_term(space, div, c: c[last], pos: last, p, latex); |
| 589 | |
| 590 | p = isl_printer_print_str(p, s: " " ); |
| 591 | p = isl_printer_print_str(p, s: op); |
| 592 | p = isl_printer_print_str(p, s: " " ); |
| 593 | |
| 594 | isl_int_set_si(c[last], 0); |
| 595 | p = print_affine(p, space, div, c); |
| 596 | |
| 597 | return p; |
| 598 | } |
| 599 | |
| 600 | /* Given an integer division |
| 601 | * |
| 602 | * floor(f/m) |
| 603 | * |
| 604 | * at position "pos" in "div", print the corresponding modulo expression |
| 605 | * |
| 606 | * (f) mod m |
| 607 | * |
| 608 | * to "p". The variable names are taken from "space", while any |
| 609 | * nested integer division definitions are taken from "div". |
| 610 | */ |
| 611 | static __isl_give isl_printer *print_mod(__isl_take isl_printer *p, |
| 612 | __isl_keep isl_space *space, __isl_keep isl_mat *div, int pos, |
| 613 | int latex) |
| 614 | { |
| 615 | if (!p || !div) |
| 616 | return isl_printer_free(printer: p); |
| 617 | |
| 618 | p = isl_printer_print_str(p, s: "(" ); |
| 619 | p = print_affine_of_len(space, div, p, |
| 620 | c: div->row[pos] + 1, len: div->n_col - 1); |
| 621 | p = isl_printer_print_str(p, s: ") " ); |
| 622 | p = isl_printer_print_str(p, s: s_mod[latex]); |
| 623 | p = isl_printer_print_str(p, s: " " ); |
| 624 | p = isl_printer_print_isl_int(p, i: div->row[pos][0]); |
| 625 | return p; |
| 626 | } |
| 627 | |
| 628 | /* Given an equality constraint with a non-zero coefficient "c" |
| 629 | * in position "pos", is this term of the form |
| 630 | * |
| 631 | * a m floor(g/m), |
| 632 | * |
| 633 | * with c = a m? |
| 634 | * Return the position of the corresponding integer division if so. |
| 635 | * Return the number of integer divisions if not. |
| 636 | * Return isl_size_error on error. |
| 637 | * |
| 638 | * Modulo constraints are currently not printed in C format. |
| 639 | * Other than that, "pos" needs to correspond to an integer division |
| 640 | * with explicit representation and "c" needs to be a multiple |
| 641 | * of the denominator of the integer division. |
| 642 | */ |
| 643 | static isl_size print_as_modulo_pos(__isl_keep isl_printer *p, |
| 644 | __isl_keep isl_space *space, __isl_keep isl_mat *div, unsigned pos, |
| 645 | isl_int c) |
| 646 | { |
| 647 | isl_bool can_print; |
| 648 | isl_size n_div; |
| 649 | enum isl_dim_type type; |
| 650 | |
| 651 | n_div = isl_mat_rows(mat: div); |
| 652 | if (!p || !space || n_div < 0) |
| 653 | return isl_size_error; |
| 654 | if (p->output_format == ISL_FORMAT_C) |
| 655 | return n_div; |
| 656 | if (pos2type(space, type: &type, pos: &pos) < 0) |
| 657 | return isl_size_error; |
| 658 | if (type != isl_dim_div) |
| 659 | return n_div; |
| 660 | can_print = can_print_div_expr(p, div, pos); |
| 661 | if (can_print < 0) |
| 662 | return isl_size_error; |
| 663 | if (!can_print) |
| 664 | return n_div; |
| 665 | if (!isl_int_is_divisible_by(c, div->row[pos][0])) |
| 666 | return n_div; |
| 667 | return pos; |
| 668 | } |
| 669 | |
| 670 | /* Print equality constraint "c" to "p" as a modulo constraint, |
| 671 | * with the variable names taken from "space" and |
| 672 | * the integer division definitions taken from "div". |
| 673 | * "last" is the position of the last non-zero coefficient, which is |
| 674 | * moreover assumed to be negative and a multiple of the denominator |
| 675 | * of the corresponding integer division. "div_pos" is the corresponding |
| 676 | * position in the sequence of integer divisions. |
| 677 | * |
| 678 | * The equality is of the form |
| 679 | * |
| 680 | * f - a m floor(g/m) = 0. |
| 681 | * |
| 682 | * Print it as |
| 683 | * |
| 684 | * a (g mod m) = -f + a g |
| 685 | */ |
| 686 | static __isl_give isl_printer *print_eq_mod_constraint( |
| 687 | __isl_take isl_printer *p, __isl_keep isl_space *space, |
| 688 | __isl_keep isl_mat *div, unsigned div_pos, |
| 689 | isl_int *c, int last, int latex) |
| 690 | { |
| 691 | isl_ctx *ctx; |
| 692 | int multiple; |
| 693 | |
| 694 | ctx = isl_printer_get_ctx(printer: p); |
| 695 | isl_int_divexact(c[last], c[last], div->row[div_pos][0]); |
| 696 | isl_int_abs(c[last], c[last]); |
| 697 | multiple = !isl_int_is_one(c[last]); |
| 698 | if (multiple) { |
| 699 | p = isl_printer_print_isl_int(p, i: c[last]); |
| 700 | p = isl_printer_print_str(p, s: "*(" ); |
| 701 | } |
| 702 | p = print_mod(p, space, div, pos: div_pos, latex); |
| 703 | if (multiple) |
| 704 | p = isl_printer_print_str(p, s: ")" ); |
| 705 | p = isl_printer_print_str(p, s: " = " ); |
| 706 | isl_seq_combine(dst: c, m1: ctx->negone, src1: c, |
| 707 | m2: c[last], src2: div->row[div_pos] + 1, len: last); |
| 708 | isl_int_set_si(c[last], 0); |
| 709 | p = print_affine(p, space, div, c); |
| 710 | return p; |
| 711 | } |
| 712 | |
| 713 | /* Print equality constraint "c" to "p", with the variable names |
| 714 | * taken from "space" and the integer division definitions taken from "div". |
| 715 | * "last" is the position of the last non-zero coefficient, which is |
| 716 | * moreover assumed to be negative. |
| 717 | * |
| 718 | * If possible, print the equality constraint as a modulo constraint. |
| 719 | */ |
| 720 | static __isl_give isl_printer *print_eq_constraint(__isl_take isl_printer *p, |
| 721 | __isl_keep isl_space *space, __isl_keep isl_mat *div, isl_int *c, |
| 722 | int last, int latex) |
| 723 | { |
| 724 | isl_size n_div; |
| 725 | isl_size div_pos; |
| 726 | |
| 727 | n_div = isl_mat_rows(mat: div); |
| 728 | div_pos = print_as_modulo_pos(p, space, div, pos: last, c: c[last]); |
| 729 | if (n_div < 0 || div_pos < 0) |
| 730 | return isl_printer_free(printer: p); |
| 731 | if (div_pos < n_div) |
| 732 | return print_eq_mod_constraint(p, space, div, div_pos, |
| 733 | c, last, latex); |
| 734 | return print_constraint(p, space, div, c, last, op: "=" , latex); |
| 735 | } |
| 736 | |
| 737 | /* Print the constraints of "bmap" to "p". |
| 738 | * The names of the variables are taken from "space" and |
| 739 | * the integer division definitions are taken from "div". |
| 740 | * Div constraints are only printed in "dump" mode. |
| 741 | * The constraints are sorted prior to printing (except in "dump" mode). |
| 742 | * |
| 743 | * If x is the last variable with a non-zero coefficient, |
| 744 | * then a lower bound |
| 745 | * |
| 746 | * f - a x >= 0 |
| 747 | * |
| 748 | * is printed as |
| 749 | * |
| 750 | * a x <= f |
| 751 | * |
| 752 | * while an upper bound |
| 753 | * |
| 754 | * f + a x >= 0 |
| 755 | * |
| 756 | * is printed as |
| 757 | * |
| 758 | * a x >= -f |
| 759 | * |
| 760 | * If the next constraint has an opposite sign for the same last coefficient, |
| 761 | * then it is printed as |
| 762 | * |
| 763 | * f >= a x |
| 764 | * |
| 765 | * or |
| 766 | * |
| 767 | * -f <= a x |
| 768 | * |
| 769 | * instead. In fact, the "a x" part is not printed explicitly, but |
| 770 | * reused from the next constraint, which is therefore treated as |
| 771 | * a first constraint in the conjunction. |
| 772 | * |
| 773 | * If the constant term of "f" is -1, then "f" is replaced by "f + 1" and |
| 774 | * the comparison operator is replaced by the strict variant. |
| 775 | * Essentially, ">= 1" is replaced by "> 0". |
| 776 | */ |
| 777 | static __isl_give isl_printer *print_constraints(__isl_keep isl_basic_map *bmap, |
| 778 | __isl_keep isl_space *space, __isl_keep isl_mat *div, |
| 779 | __isl_take isl_printer *p, int latex) |
| 780 | { |
| 781 | int i; |
| 782 | isl_vec *c = NULL; |
| 783 | int rational = ISL_F_ISSET(bmap, ISL_BASIC_MAP_RATIONAL); |
| 784 | isl_size total = isl_basic_map_dim(bmap, type: isl_dim_all); |
| 785 | unsigned o_div = isl_basic_map_offset(bmap, type: isl_dim_div); |
| 786 | int first = 1; |
| 787 | int dump; |
| 788 | |
| 789 | if (total < 0 || !p) |
| 790 | return isl_printer_free(printer: p); |
| 791 | bmap = isl_basic_map_copy(bmap); |
| 792 | dump = p->dump; |
| 793 | if (!dump) |
| 794 | bmap = isl_basic_map_sort_constraints(bmap); |
| 795 | if (!bmap) |
| 796 | goto error; |
| 797 | |
| 798 | c = isl_vec_alloc(ctx: bmap->ctx, size: 1 + total); |
| 799 | if (!c) |
| 800 | goto error; |
| 801 | |
| 802 | for (i = bmap->n_eq - 1; i >= 0; --i) { |
| 803 | int l = isl_seq_last_non_zero(p: bmap->eq[i], len: 1 + total); |
| 804 | if (l < 0) { |
| 805 | if (i != bmap->n_eq - 1) |
| 806 | p = isl_printer_print_str(p, s: s_and[latex]); |
| 807 | p = isl_printer_print_str(p, s: "0 = 0" ); |
| 808 | continue; |
| 809 | } |
| 810 | if (!first) |
| 811 | p = isl_printer_print_str(p, s: s_and[latex]); |
| 812 | if (isl_int_is_neg(bmap->eq[i][l])) |
| 813 | isl_seq_cpy(dst: c->el, src: bmap->eq[i], len: 1 + total); |
| 814 | else |
| 815 | isl_seq_neg(dst: c->el, src: bmap->eq[i], len: 1 + total); |
| 816 | p = print_eq_constraint(p, space, div, c: c->el, last: l, latex); |
| 817 | first = 0; |
| 818 | } |
| 819 | for (i = 0; i < bmap->n_ineq; ++i) { |
| 820 | isl_bool combine; |
| 821 | int l = isl_seq_last_non_zero(p: bmap->ineq[i], len: 1 + total); |
| 822 | int strict; |
| 823 | int s; |
| 824 | const char *op; |
| 825 | if (l < 0) |
| 826 | continue; |
| 827 | if (!dump && l >= o_div && |
| 828 | can_print_div_expr(p, div, pos: l - o_div)) { |
| 829 | isl_bool is_div; |
| 830 | is_div = isl_basic_map_is_div_constraint(bmap, |
| 831 | constraint: bmap->ineq[i], div: l - o_div); |
| 832 | if (is_div < 0) |
| 833 | goto error; |
| 834 | if (is_div) |
| 835 | continue; |
| 836 | } |
| 837 | if (!first) |
| 838 | p = isl_printer_print_str(p, s: s_and[latex]); |
| 839 | s = isl_int_sgn(bmap->ineq[i][l]); |
| 840 | strict = !rational && isl_int_is_negone(bmap->ineq[i][0]); |
| 841 | if (s < 0) |
| 842 | isl_seq_cpy(dst: c->el, src: bmap->ineq[i], len: 1 + total); |
| 843 | else |
| 844 | isl_seq_neg(dst: c->el, src: bmap->ineq[i], len: 1 + total); |
| 845 | if (strict) |
| 846 | isl_int_set_si(c->el[0], 0); |
| 847 | combine = dump ? isl_bool_false : next_is_opposite(bmap, i, last: l); |
| 848 | if (combine < 0) |
| 849 | goto error; |
| 850 | if (combine) { |
| 851 | op = constraint_op(sign: -s, strict, latex); |
| 852 | p = print_half_constraint(p, space, div, c: c->el, last: l, |
| 853 | op, latex); |
| 854 | first = 1; |
| 855 | } else { |
| 856 | op = constraint_op(sign: s, strict, latex); |
| 857 | p = print_constraint(p, space, div, c: c->el, last: l, |
| 858 | op, latex); |
| 859 | first = 0; |
| 860 | } |
| 861 | } |
| 862 | |
| 863 | isl_basic_map_free(bmap); |
| 864 | isl_vec_free(vec: c); |
| 865 | |
| 866 | return p; |
| 867 | error: |
| 868 | isl_basic_map_free(bmap); |
| 869 | isl_vec_free(vec: c); |
| 870 | isl_printer_free(printer: p); |
| 871 | return NULL; |
| 872 | } |
| 873 | |
| 874 | static __isl_give isl_printer *print_div(__isl_keep isl_space *space, |
| 875 | __isl_keep isl_mat *div, int pos, __isl_take isl_printer *p) |
| 876 | { |
| 877 | int c; |
| 878 | |
| 879 | if (!p || !div) |
| 880 | return isl_printer_free(printer: p); |
| 881 | |
| 882 | c = p->output_format == ISL_FORMAT_C; |
| 883 | p = isl_printer_print_str(p, s: c ? "floord(" : "floor((" ); |
| 884 | p = print_affine_of_len(space, div, p, |
| 885 | c: div->row[pos] + 1, len: div->n_col - 1); |
| 886 | p = isl_printer_print_str(p, s: c ? ", " : ")/" ); |
| 887 | p = isl_printer_print_isl_int(p, i: div->row[pos][0]); |
| 888 | p = isl_printer_print_str(p, s: ")" ); |
| 889 | return p; |
| 890 | } |
| 891 | |
| 892 | /* Print a comma separated list of div names, except those that have |
| 893 | * a definition that can be printed. |
| 894 | * If "print_defined_divs" is set, then those div names are printed |
| 895 | * as well, along with their definitions. |
| 896 | */ |
| 897 | static __isl_give isl_printer *print_div_list(__isl_take isl_printer *p, |
| 898 | __isl_keep isl_space *space, __isl_keep isl_mat *div, int latex, |
| 899 | int print_defined_divs) |
| 900 | { |
| 901 | int i; |
| 902 | int first = 1; |
| 903 | isl_size n_div; |
| 904 | |
| 905 | n_div = isl_mat_rows(mat: div); |
| 906 | if (!p || !space || n_div < 0) |
| 907 | return isl_printer_free(printer: p); |
| 908 | |
| 909 | for (i = 0; i < n_div; ++i) { |
| 910 | if (!print_defined_divs && can_print_div_expr(p, div, pos: i)) |
| 911 | continue; |
| 912 | if (!first) |
| 913 | p = isl_printer_print_str(p, s: ", " ); |
| 914 | p = print_name(space, p, type: isl_dim_div, pos: i, latex); |
| 915 | first = 0; |
| 916 | if (!can_print_div_expr(p, div, pos: i)) |
| 917 | continue; |
| 918 | p = isl_printer_print_str(p, s: " = " ); |
| 919 | p = print_div(space, div, pos: i, p); |
| 920 | } |
| 921 | |
| 922 | return p; |
| 923 | } |
| 924 | |
| 925 | /* Does printing an object with local variables described by "div" |
| 926 | * require an "exists" clause? |
| 927 | * That is, are there any local variables without an explicit representation? |
| 928 | * An exists clause is also needed in "dump" mode because |
| 929 | * explicit div representations are not printed inline in that case. |
| 930 | */ |
| 931 | static isl_bool need_exists(__isl_keep isl_printer *p, __isl_keep isl_mat *div) |
| 932 | { |
| 933 | int i; |
| 934 | isl_size n; |
| 935 | |
| 936 | n = isl_mat_rows(mat: div); |
| 937 | if (!p || n < 0) |
| 938 | return isl_bool_error; |
| 939 | if (n == 0) |
| 940 | return isl_bool_false; |
| 941 | if (p->dump) |
| 942 | return isl_bool_true; |
| 943 | for (i = 0; i < n; ++i) |
| 944 | if (!can_print_div_expr(p, div, pos: i)) |
| 945 | return isl_bool_true; |
| 946 | return isl_bool_false; |
| 947 | } |
| 948 | |
| 949 | /* Print the start of an exists clause, i.e., |
| 950 | * |
| 951 | * (exists variables: |
| 952 | * |
| 953 | * In dump mode, local variables with an explicit definition are printed |
| 954 | * as well because they will not be printed inline. |
| 955 | */ |
| 956 | static __isl_give isl_printer *open_exists(__isl_take isl_printer *p, |
| 957 | __isl_keep isl_space *space, __isl_keep isl_mat *div, int latex) |
| 958 | { |
| 959 | int dump; |
| 960 | |
| 961 | if (!p) |
| 962 | return NULL; |
| 963 | |
| 964 | dump = p->dump; |
| 965 | p = isl_printer_print_str(p, s: s_open_exists[latex]); |
| 966 | p = print_div_list(p, space, div, latex, print_defined_divs: dump); |
| 967 | p = isl_printer_print_str(p, s: ": " ); |
| 968 | |
| 969 | return p; |
| 970 | } |
| 971 | |
| 972 | /* Remove the explicit representations of all local variables in "div". |
| 973 | */ |
| 974 | static __isl_give isl_mat *mark_all_unknown(__isl_take isl_mat *div) |
| 975 | { |
| 976 | int i; |
| 977 | isl_size n_div; |
| 978 | |
| 979 | n_div = isl_mat_rows(mat: div); |
| 980 | if (n_div < 0) |
| 981 | return isl_mat_free(mat: div); |
| 982 | |
| 983 | for (i = 0; i < n_div; ++i) |
| 984 | div = isl_mat_set_element_si(mat: div, row: i, col: 0, v: 0); |
| 985 | return div; |
| 986 | } |
| 987 | |
| 988 | /* Print the constraints of "bmap" to "p". |
| 989 | * The names of the variables are taken from "space". |
| 990 | * "latex" is set if the constraints should be printed in LaTeX format. |
| 991 | * Do not print inline explicit div representations in "dump" mode. |
| 992 | */ |
| 993 | static __isl_give isl_printer *print_disjunct(__isl_keep isl_basic_map *bmap, |
| 994 | __isl_keep isl_space *space, __isl_take isl_printer *p, int latex) |
| 995 | { |
| 996 | int dump; |
| 997 | isl_mat *div; |
| 998 | isl_bool exists; |
| 999 | |
| 1000 | if (!p) |
| 1001 | return NULL; |
| 1002 | dump = p->dump; |
| 1003 | div = isl_basic_map_get_divs(bmap); |
| 1004 | exists = need_exists(p, div); |
| 1005 | if (exists >= 0 && exists) |
| 1006 | p = open_exists(p, space, div, latex); |
| 1007 | |
| 1008 | if (dump) |
| 1009 | div = mark_all_unknown(div); |
| 1010 | p = print_constraints(bmap, space, div, p, latex); |
| 1011 | isl_mat_free(mat: div); |
| 1012 | |
| 1013 | if (exists >= 0 && exists) |
| 1014 | p = isl_printer_print_str(p, s: s_close_exists[latex]); |
| 1015 | return p; |
| 1016 | } |
| 1017 | |
| 1018 | /* Print a colon followed by the constraints of "bmap" |
| 1019 | * to "p", provided there are any constraints. |
| 1020 | * The names of the variables are taken from "space". |
| 1021 | * "latex" is set if the constraints should be printed in LaTeX format. |
| 1022 | */ |
| 1023 | static __isl_give isl_printer *print_optional_disjunct( |
| 1024 | __isl_keep isl_basic_map *bmap, __isl_keep isl_space *space, |
| 1025 | __isl_take isl_printer *p, int latex) |
| 1026 | { |
| 1027 | if (isl_basic_map_plain_is_universe(bmap)) |
| 1028 | return p; |
| 1029 | |
| 1030 | p = isl_printer_print_str(p, s: ": " ); |
| 1031 | p = print_disjunct(bmap, space, p, latex); |
| 1032 | |
| 1033 | return p; |
| 1034 | } |
| 1035 | |
| 1036 | static __isl_give isl_printer *basic_map_print_omega( |
| 1037 | __isl_keep isl_basic_map *bmap, __isl_take isl_printer *p) |
| 1038 | { |
| 1039 | p = isl_printer_print_str(p, s: "{ [" ); |
| 1040 | p = print_var_list(p, space: bmap->dim, type: isl_dim_in); |
| 1041 | p = isl_printer_print_str(p, s: "] -> [" ); |
| 1042 | p = print_var_list(p, space: bmap->dim, type: isl_dim_out); |
| 1043 | p = isl_printer_print_str(p, s: "] " ); |
| 1044 | p = print_optional_disjunct(bmap, space: bmap->dim, p, latex: 0); |
| 1045 | p = isl_printer_print_str(p, s: " }" ); |
| 1046 | return p; |
| 1047 | } |
| 1048 | |
| 1049 | static __isl_give isl_printer *basic_set_print_omega( |
| 1050 | __isl_keep isl_basic_set *bset, __isl_take isl_printer *p) |
| 1051 | { |
| 1052 | p = isl_printer_print_str(p, s: "{ [" ); |
| 1053 | p = print_var_list(p, space: bset->dim, type: isl_dim_set); |
| 1054 | p = isl_printer_print_str(p, s: "] " ); |
| 1055 | p = print_optional_disjunct(bmap: bset, space: bset->dim, p, latex: 0); |
| 1056 | p = isl_printer_print_str(p, s: " }" ); |
| 1057 | return p; |
| 1058 | } |
| 1059 | |
| 1060 | static __isl_give isl_printer *isl_map_print_omega(__isl_keep isl_map *map, |
| 1061 | __isl_take isl_printer *p) |
| 1062 | { |
| 1063 | int i; |
| 1064 | |
| 1065 | for (i = 0; i < map->n; ++i) { |
| 1066 | if (i) |
| 1067 | p = isl_printer_print_str(p, s: " union " ); |
| 1068 | p = basic_map_print_omega(bmap: map->p[i], p); |
| 1069 | } |
| 1070 | return p; |
| 1071 | } |
| 1072 | |
| 1073 | static __isl_give isl_printer *isl_set_print_omega(__isl_keep isl_set *set, |
| 1074 | __isl_take isl_printer *p) |
| 1075 | { |
| 1076 | int i; |
| 1077 | |
| 1078 | for (i = 0; i < set->n; ++i) { |
| 1079 | if (i) |
| 1080 | p = isl_printer_print_str(p, s: " union " ); |
| 1081 | p = basic_set_print_omega(bset: set->p[i], p); |
| 1082 | } |
| 1083 | return p; |
| 1084 | } |
| 1085 | |
| 1086 | /* Print the list of parameters in "space", followed by an arrow, to "p", |
| 1087 | * if there are any parameters. |
| 1088 | */ |
| 1089 | static __isl_give isl_printer *print_param_tuple(__isl_take isl_printer *p, |
| 1090 | __isl_keep isl_space *space, struct isl_print_space_data *data) |
| 1091 | { |
| 1092 | isl_size nparam; |
| 1093 | |
| 1094 | nparam = isl_space_dim(space, type: isl_dim_param); |
| 1095 | if (!p || nparam < 0) |
| 1096 | return isl_printer_free(printer: p); |
| 1097 | if (nparam == 0) |
| 1098 | return p; |
| 1099 | |
| 1100 | p = print_tuple(space, p, type: isl_dim_param, data); |
| 1101 | p = isl_printer_print_str(p, s: s_to[data->latex]); |
| 1102 | |
| 1103 | return p; |
| 1104 | } |
| 1105 | |
| 1106 | static __isl_give isl_printer *isl_basic_map_print_isl( |
| 1107 | __isl_keep isl_basic_map *bmap, __isl_take isl_printer *p, |
| 1108 | int latex) |
| 1109 | { |
| 1110 | struct isl_print_space_data data = { .latex = latex }; |
| 1111 | int rational = ISL_F_ISSET(bmap, ISL_BASIC_MAP_RATIONAL); |
| 1112 | |
| 1113 | p = print_param_tuple(p, space: bmap->dim, data: &data); |
| 1114 | p = isl_printer_print_str(p, s: "{ " ); |
| 1115 | p = isl_print_space(space: bmap->dim, p, rational, data: &data); |
| 1116 | p = isl_printer_print_str(p, s: " : " ); |
| 1117 | p = print_disjunct(bmap, space: bmap->dim, p, latex); |
| 1118 | p = isl_printer_print_str(p, s: " }" ); |
| 1119 | return p; |
| 1120 | } |
| 1121 | |
| 1122 | /* Print the disjuncts of a map (or set) "map" to "p". |
| 1123 | * The names of the variables are taken from "space". |
| 1124 | * "latex" is set if the constraints should be printed in LaTeX format. |
| 1125 | */ |
| 1126 | static __isl_give isl_printer *print_disjuncts_core(__isl_keep isl_map *map, |
| 1127 | __isl_keep isl_space *space, __isl_take isl_printer *p, int latex) |
| 1128 | { |
| 1129 | int i; |
| 1130 | |
| 1131 | if (map->n == 0) |
| 1132 | p = isl_printer_print_str(p, s: "false" ); |
| 1133 | for (i = 0; i < map->n; ++i) { |
| 1134 | if (i) |
| 1135 | p = isl_printer_print_str(p, s: s_or[latex]); |
| 1136 | if (map->n > 1 && map->p[i]->n_eq + map->p[i]->n_ineq > 1) |
| 1137 | p = isl_printer_print_str(p, s: "(" ); |
| 1138 | p = print_disjunct(bmap: map->p[i], space, p, latex); |
| 1139 | if (map->n > 1 && map->p[i]->n_eq + map->p[i]->n_ineq > 1) |
| 1140 | p = isl_printer_print_str(p, s: ")" ); |
| 1141 | } |
| 1142 | return p; |
| 1143 | } |
| 1144 | |
| 1145 | /* Print the disjuncts of a map (or set) "map" to "p". |
| 1146 | * The names of the variables are taken from "space". |
| 1147 | * "hull" describes constraints shared by all disjuncts of "map". |
| 1148 | * "latex" is set if the constraints should be printed in LaTeX format. |
| 1149 | * |
| 1150 | * Print the disjuncts as a conjunction of "hull" and |
| 1151 | * the result of removing the constraints of "hull" from "map". |
| 1152 | * If this result turns out to be the universe, then simply print "hull". |
| 1153 | */ |
| 1154 | static __isl_give isl_printer *print_disjuncts_in_hull(__isl_keep isl_map *map, |
| 1155 | __isl_keep isl_space *space, __isl_take isl_basic_map *hull, |
| 1156 | __isl_take isl_printer *p, int latex) |
| 1157 | { |
| 1158 | isl_bool is_universe; |
| 1159 | |
| 1160 | p = print_disjunct(bmap: hull, space, p, latex); |
| 1161 | map = isl_map_plain_gist_basic_map(map: isl_map_copy(map), context: hull); |
| 1162 | is_universe = isl_map_plain_is_universe(map); |
| 1163 | if (is_universe < 0) |
| 1164 | goto error; |
| 1165 | if (!is_universe) { |
| 1166 | p = isl_printer_print_str(p, s: s_and[latex]); |
| 1167 | p = isl_printer_print_str(p, s: "(" ); |
| 1168 | p = print_disjuncts_core(map, space, p, latex); |
| 1169 | p = isl_printer_print_str(p, s: ")" ); |
| 1170 | } |
| 1171 | isl_map_free(map); |
| 1172 | |
| 1173 | return p; |
| 1174 | error: |
| 1175 | isl_map_free(map); |
| 1176 | isl_printer_free(printer: p); |
| 1177 | return NULL; |
| 1178 | } |
| 1179 | |
| 1180 | /* Print the disjuncts of a map (or set) "map" to "p". |
| 1181 | * The names of the variables are taken from "space". |
| 1182 | * "latex" is set if the constraints should be printed in LaTeX format. |
| 1183 | * |
| 1184 | * If there are at least two disjuncts and "dump" mode is not turned out, |
| 1185 | * check for any shared constraints among all disjuncts. |
| 1186 | * If there are any, then print them separately in print_disjuncts_in_hull. |
| 1187 | */ |
| 1188 | static __isl_give isl_printer *print_disjuncts(__isl_keep isl_map *map, |
| 1189 | __isl_keep isl_space *space, __isl_take isl_printer *p, int latex) |
| 1190 | { |
| 1191 | if (isl_map_plain_is_universe(map)) |
| 1192 | return p; |
| 1193 | |
| 1194 | p = isl_printer_print_str(p, s: s_such_that[latex]); |
| 1195 | if (!p) |
| 1196 | return NULL; |
| 1197 | |
| 1198 | if (!p->dump && map->n >= 2) { |
| 1199 | isl_basic_map *hull; |
| 1200 | isl_bool is_universe; |
| 1201 | |
| 1202 | hull = isl_map_plain_unshifted_simple_hull(map: isl_map_copy(map)); |
| 1203 | is_universe = isl_basic_map_plain_is_universe(bmap: hull); |
| 1204 | if (is_universe < 0) |
| 1205 | p = isl_printer_free(printer: p); |
| 1206 | else if (!is_universe) |
| 1207 | return print_disjuncts_in_hull(map, space, hull, |
| 1208 | p, latex); |
| 1209 | isl_basic_map_free(bmap: hull); |
| 1210 | } |
| 1211 | |
| 1212 | return print_disjuncts_core(map, space, p, latex); |
| 1213 | } |
| 1214 | |
| 1215 | /* Print the disjuncts of a map (or set). |
| 1216 | * The names of the variables are taken from "space". |
| 1217 | * "latex" is set if the constraints should be printed in LaTeX format. |
| 1218 | * |
| 1219 | * If the map turns out to be a universal parameter domain, then |
| 1220 | * we need to print the colon. Otherwise, the output looks identical |
| 1221 | * to the empty set. |
| 1222 | */ |
| 1223 | static __isl_give isl_printer *print_disjuncts_map(__isl_keep isl_map *map, |
| 1224 | __isl_keep isl_space *space, __isl_take isl_printer *p, int latex) |
| 1225 | { |
| 1226 | if (isl_map_plain_is_universe(map) && isl_space_is_params(space: map->dim)) |
| 1227 | return isl_printer_print_str(p, s: s_such_that[latex]); |
| 1228 | else |
| 1229 | return print_disjuncts(map, space, p, latex); |
| 1230 | } |
| 1231 | |
| 1232 | /* Print the disjuncts of a set. |
| 1233 | * The names of the variables are taken from "space". |
| 1234 | * "latex" is set if the constraints should be printed in LaTeX format. |
| 1235 | */ |
| 1236 | static __isl_give isl_printer *print_disjuncts_set(__isl_keep isl_set *set, |
| 1237 | __isl_keep isl_space *space, __isl_take isl_printer *p, int latex) |
| 1238 | { |
| 1239 | return print_disjuncts_map(map: set_to_map(set), space, p, latex); |
| 1240 | } |
| 1241 | |
| 1242 | struct isl_aff_split { |
| 1243 | isl_basic_map *aff; |
| 1244 | isl_map *map; |
| 1245 | }; |
| 1246 | |
| 1247 | static void free_split(__isl_take struct isl_aff_split *split, int n) |
| 1248 | { |
| 1249 | int i; |
| 1250 | |
| 1251 | if (!split) |
| 1252 | return; |
| 1253 | |
| 1254 | for (i = 0; i < n; ++i) { |
| 1255 | isl_basic_map_free(bmap: split[i].aff); |
| 1256 | isl_map_free(map: split[i].map); |
| 1257 | } |
| 1258 | |
| 1259 | free(ptr: split); |
| 1260 | } |
| 1261 | |
| 1262 | static __isl_give isl_basic_map *get_aff(__isl_take isl_basic_map *bmap) |
| 1263 | { |
| 1264 | int i, j; |
| 1265 | isl_size nparam, n_in, n_out, total; |
| 1266 | |
| 1267 | bmap = isl_basic_map_cow(bmap); |
| 1268 | if (!bmap) |
| 1269 | return NULL; |
| 1270 | bmap = isl_basic_map_free_inequality(bmap, n: bmap->n_ineq); |
| 1271 | |
| 1272 | nparam = isl_basic_map_dim(bmap, type: isl_dim_param); |
| 1273 | n_in = isl_basic_map_dim(bmap, type: isl_dim_in); |
| 1274 | n_out = isl_basic_map_dim(bmap, type: isl_dim_out); |
| 1275 | total = isl_basic_map_dim(bmap, type: isl_dim_all); |
| 1276 | if (n_in < 0 || n_out < 0 || nparam < 0 || total < 0) |
| 1277 | return isl_basic_map_free(bmap); |
| 1278 | |
| 1279 | for (i = bmap->n_eq - 1; i >= 0; --i) { |
| 1280 | j = isl_seq_last_non_zero(p: bmap->eq[i] + 1, len: total); |
| 1281 | if (j >= nparam && j < nparam + n_in + n_out && |
| 1282 | (isl_int_is_one(bmap->eq[i][1 + j]) || |
| 1283 | isl_int_is_negone(bmap->eq[i][1 + j]))) |
| 1284 | continue; |
| 1285 | if (isl_basic_map_drop_equality(bmap, pos: i) < 0) |
| 1286 | goto error; |
| 1287 | } |
| 1288 | |
| 1289 | bmap = isl_basic_map_finalize(bmap); |
| 1290 | |
| 1291 | return bmap; |
| 1292 | error: |
| 1293 | isl_basic_map_free(bmap); |
| 1294 | return NULL; |
| 1295 | } |
| 1296 | |
| 1297 | static int aff_split_cmp(const void *p1, const void *p2, void *user) |
| 1298 | { |
| 1299 | const struct isl_aff_split *s1, *s2; |
| 1300 | s1 = (const struct isl_aff_split *) p1; |
| 1301 | s2 = (const struct isl_aff_split *) p2; |
| 1302 | |
| 1303 | return isl_basic_map_plain_cmp(bmap1: s1->aff, bmap2: s2->aff); |
| 1304 | } |
| 1305 | |
| 1306 | static __isl_give isl_basic_map *drop_aff(__isl_take isl_basic_map *bmap, |
| 1307 | __isl_keep isl_basic_map *aff) |
| 1308 | { |
| 1309 | int i, j; |
| 1310 | isl_size v_div; |
| 1311 | |
| 1312 | v_div = isl_basic_map_var_offset(bmap, type: isl_dim_div); |
| 1313 | if (v_div < 0 || !aff) |
| 1314 | goto error; |
| 1315 | |
| 1316 | for (i = bmap->n_eq - 1; i >= 0; --i) { |
| 1317 | if (isl_seq_first_non_zero(p: bmap->eq[i] + 1 + v_div, |
| 1318 | len: bmap->n_div) != -1) |
| 1319 | continue; |
| 1320 | for (j = 0; j < aff->n_eq; ++j) { |
| 1321 | if (!isl_seq_eq(p1: bmap->eq[i], p2: aff->eq[j], len: 1 + v_div) && |
| 1322 | !isl_seq_is_neg(p1: bmap->eq[i], p2: aff->eq[j], len: 1 + v_div)) |
| 1323 | continue; |
| 1324 | if (isl_basic_map_drop_equality(bmap, pos: i) < 0) |
| 1325 | goto error; |
| 1326 | break; |
| 1327 | } |
| 1328 | } |
| 1329 | |
| 1330 | return bmap; |
| 1331 | error: |
| 1332 | isl_basic_map_free(bmap); |
| 1333 | return NULL; |
| 1334 | } |
| 1335 | |
| 1336 | static __isl_give struct isl_aff_split *split_aff(__isl_keep isl_map *map) |
| 1337 | { |
| 1338 | int i, n; |
| 1339 | struct isl_aff_split *split; |
| 1340 | isl_ctx *ctx; |
| 1341 | |
| 1342 | ctx = isl_map_get_ctx(map); |
| 1343 | split = isl_calloc_array(ctx, struct isl_aff_split, map->n); |
| 1344 | if (!split) |
| 1345 | return NULL; |
| 1346 | |
| 1347 | for (i = 0; i < map->n; ++i) { |
| 1348 | isl_basic_map *bmap; |
| 1349 | split[i].aff = get_aff(bmap: isl_basic_map_copy(bmap: map->p[i])); |
| 1350 | bmap = isl_basic_map_copy(bmap: map->p[i]); |
| 1351 | bmap = isl_basic_map_cow(bmap); |
| 1352 | bmap = drop_aff(bmap, aff: split[i].aff); |
| 1353 | split[i].map = isl_map_from_basic_map(bmap); |
| 1354 | if (!split[i].aff || !split[i].map) |
| 1355 | goto error; |
| 1356 | } |
| 1357 | |
| 1358 | if (isl_sort(pbase: split, total_elems: map->n, size: sizeof(struct isl_aff_split), |
| 1359 | cmp: &aff_split_cmp, NULL) < 0) |
| 1360 | goto error; |
| 1361 | |
| 1362 | n = map->n; |
| 1363 | for (i = n - 1; i >= 1; --i) { |
| 1364 | if (!isl_basic_map_plain_is_equal(bmap1: split[i - 1].aff, |
| 1365 | bmap2: split[i].aff)) |
| 1366 | continue; |
| 1367 | isl_basic_map_free(bmap: split[i].aff); |
| 1368 | split[i - 1].map = isl_map_union(map1: split[i - 1].map, |
| 1369 | map2: split[i].map); |
| 1370 | if (i != n - 1) |
| 1371 | split[i] = split[n - 1]; |
| 1372 | split[n - 1].aff = NULL; |
| 1373 | split[n - 1].map = NULL; |
| 1374 | --n; |
| 1375 | } |
| 1376 | |
| 1377 | return split; |
| 1378 | error: |
| 1379 | free_split(split, n: map->n); |
| 1380 | return NULL; |
| 1381 | } |
| 1382 | |
| 1383 | static int defining_equality(__isl_keep isl_basic_map *eq, |
| 1384 | __isl_keep isl_space *space, enum isl_dim_type type, int pos) |
| 1385 | { |
| 1386 | int i; |
| 1387 | isl_size total; |
| 1388 | |
| 1389 | total = isl_basic_map_dim(bmap: eq, type: isl_dim_all); |
| 1390 | if (total < 0) |
| 1391 | return -1; |
| 1392 | |
| 1393 | pos += isl_space_offset(space, type); |
| 1394 | |
| 1395 | for (i = 0; i < eq->n_eq; ++i) { |
| 1396 | if (isl_seq_last_non_zero(p: eq->eq[i] + 1, len: total) != pos) |
| 1397 | continue; |
| 1398 | if (isl_int_is_one(eq->eq[i][1 + pos])) |
| 1399 | isl_seq_neg(dst: eq->eq[i], src: eq->eq[i], len: 1 + total); |
| 1400 | return i; |
| 1401 | } |
| 1402 | |
| 1403 | return -1; |
| 1404 | } |
| 1405 | |
| 1406 | /* Print dimension "pos" of data->space to "p". |
| 1407 | * |
| 1408 | * data->user is assumed to be an isl_basic_map keeping track of equalities. |
| 1409 | * |
| 1410 | * If the current dimension is defined by these equalities, then print |
| 1411 | * the corresponding expression, assigned to the name of the dimension |
| 1412 | * if there is any. Otherwise, print the name of the dimension. |
| 1413 | */ |
| 1414 | static __isl_give isl_printer *print_dim_eq(__isl_take isl_printer *p, |
| 1415 | struct isl_print_space_data *data, unsigned pos) |
| 1416 | { |
| 1417 | isl_basic_map *eq = data->user; |
| 1418 | int j; |
| 1419 | |
| 1420 | j = defining_equality(eq, space: data->space, type: data->type, pos); |
| 1421 | if (j >= 0) { |
| 1422 | if (isl_space_has_dim_name(space: data->space, type: data->type, pos)) { |
| 1423 | p = print_name(space: data->space, p, type: data->type, pos, |
| 1424 | latex: data->latex); |
| 1425 | p = isl_printer_print_str(p, s: " = " ); |
| 1426 | } |
| 1427 | pos += 1 + isl_space_offset(space: data->space, type: data->type); |
| 1428 | p = print_affine_of_len(space: data->space, NULL, p, c: eq->eq[j], len: pos); |
| 1429 | } else { |
| 1430 | p = print_name(space: data->space, p, type: data->type, pos, latex: data->latex); |
| 1431 | } |
| 1432 | |
| 1433 | return p; |
| 1434 | } |
| 1435 | |
| 1436 | static __isl_give isl_printer *print_split_map(__isl_take isl_printer *p, |
| 1437 | struct isl_aff_split *split, int n, __isl_keep isl_space *space) |
| 1438 | { |
| 1439 | struct isl_print_space_data data = { 0 }; |
| 1440 | int i; |
| 1441 | int rational; |
| 1442 | |
| 1443 | data.print_dim = &print_dim_eq; |
| 1444 | for (i = 0; i < n; ++i) { |
| 1445 | if (!split[i].map) |
| 1446 | break; |
| 1447 | rational = split[i].map->n > 0 && |
| 1448 | ISL_F_ISSET(split[i].map->p[0], ISL_BASIC_MAP_RATIONAL); |
| 1449 | if (i) |
| 1450 | p = isl_printer_print_str(p, s: "; " ); |
| 1451 | data.user = split[i].aff; |
| 1452 | p = isl_print_space(space, p, rational, data: &data); |
| 1453 | p = print_disjuncts_map(map: split[i].map, space, p, latex: 0); |
| 1454 | } |
| 1455 | |
| 1456 | return p; |
| 1457 | } |
| 1458 | |
| 1459 | static __isl_give isl_printer *print_body_map(__isl_take isl_printer *p, |
| 1460 | __isl_keep isl_map *map) |
| 1461 | { |
| 1462 | struct isl_print_space_data data = { 0 }; |
| 1463 | struct isl_aff_split *split = NULL; |
| 1464 | int rational; |
| 1465 | |
| 1466 | if (!p || !map) |
| 1467 | return isl_printer_free(printer: p); |
| 1468 | if (!p->dump && map->n > 0) |
| 1469 | split = split_aff(map); |
| 1470 | if (split) { |
| 1471 | p = print_split_map(p, split, n: map->n, space: map->dim); |
| 1472 | } else { |
| 1473 | rational = map->n > 0 && |
| 1474 | ISL_F_ISSET(map->p[0], ISL_BASIC_MAP_RATIONAL); |
| 1475 | p = isl_print_space(space: map->dim, p, rational, data: &data); |
| 1476 | p = print_disjuncts_map(map, space: map->dim, p, latex: 0); |
| 1477 | } |
| 1478 | free_split(split, n: map->n); |
| 1479 | return p; |
| 1480 | } |
| 1481 | |
| 1482 | static __isl_give isl_printer *isl_map_print_isl(__isl_keep isl_map *map, |
| 1483 | __isl_take isl_printer *p) |
| 1484 | { |
| 1485 | struct isl_print_space_data data = { 0 }; |
| 1486 | |
| 1487 | p = print_param_tuple(p, space: map->dim, data: &data); |
| 1488 | p = isl_printer_print_str(p, s: s_open_set[0]); |
| 1489 | p = print_body_map(p, map); |
| 1490 | p = isl_printer_print_str(p, s: s_close_set[0]); |
| 1491 | return p; |
| 1492 | } |
| 1493 | |
| 1494 | static __isl_give isl_printer *print_latex_map(__isl_keep isl_map *map, |
| 1495 | __isl_take isl_printer *p, __isl_keep isl_basic_map *aff) |
| 1496 | { |
| 1497 | struct isl_print_space_data data = { 0 }; |
| 1498 | |
| 1499 | data.latex = 1; |
| 1500 | p = print_param_tuple(p, space: map->dim, data: &data); |
| 1501 | p = isl_printer_print_str(p, s: s_open_set[1]); |
| 1502 | data.print_dim = &print_dim_eq; |
| 1503 | data.user = aff; |
| 1504 | p = isl_print_space(space: map->dim, p, rational: 0, data: &data); |
| 1505 | p = print_disjuncts_map(map, space: map->dim, p, latex: 1); |
| 1506 | p = isl_printer_print_str(p, s: s_close_set[1]); |
| 1507 | |
| 1508 | return p; |
| 1509 | } |
| 1510 | |
| 1511 | static __isl_give isl_printer *isl_map_print_latex(__isl_keep isl_map *map, |
| 1512 | __isl_take isl_printer *p) |
| 1513 | { |
| 1514 | int i; |
| 1515 | struct isl_aff_split *split = NULL; |
| 1516 | |
| 1517 | if (map->n > 0) |
| 1518 | split = split_aff(map); |
| 1519 | |
| 1520 | if (!split) |
| 1521 | return print_latex_map(map, p, NULL); |
| 1522 | |
| 1523 | for (i = 0; i < map->n; ++i) { |
| 1524 | if (!split[i].map) |
| 1525 | break; |
| 1526 | if (i) |
| 1527 | p = isl_printer_print_str(p, s: " \\cup " ); |
| 1528 | p = print_latex_map(map: split[i].map, p, aff: split[i].aff); |
| 1529 | } |
| 1530 | |
| 1531 | free_split(split, n: map->n); |
| 1532 | return p; |
| 1533 | } |
| 1534 | |
| 1535 | __isl_give isl_printer *isl_printer_print_basic_map(__isl_take isl_printer *p, |
| 1536 | __isl_keep isl_basic_map *bmap) |
| 1537 | { |
| 1538 | if (!p || !bmap) |
| 1539 | goto error; |
| 1540 | if (p->output_format == ISL_FORMAT_ISL) |
| 1541 | return isl_basic_map_print_isl(bmap, p, latex: 0); |
| 1542 | else if (p->output_format == ISL_FORMAT_OMEGA) |
| 1543 | return basic_map_print_omega(bmap, p); |
| 1544 | isl_assert(bmap->ctx, 0, goto error); |
| 1545 | error: |
| 1546 | isl_printer_free(printer: p); |
| 1547 | return NULL; |
| 1548 | } |
| 1549 | |
| 1550 | __isl_give isl_printer *isl_printer_print_basic_set(__isl_take isl_printer *p, |
| 1551 | __isl_keep isl_basic_set *bset) |
| 1552 | { |
| 1553 | if (!p || !bset) |
| 1554 | goto error; |
| 1555 | |
| 1556 | if (p->output_format == ISL_FORMAT_ISL) |
| 1557 | return isl_basic_map_print_isl(bmap: bset, p, latex: 0); |
| 1558 | else if (p->output_format == ISL_FORMAT_POLYLIB) |
| 1559 | return isl_basic_set_print_polylib(bset, p, ext: 0); |
| 1560 | else if (p->output_format == ISL_FORMAT_EXT_POLYLIB) |
| 1561 | return isl_basic_set_print_polylib(bset, p, ext: 1); |
| 1562 | else if (p->output_format == ISL_FORMAT_POLYLIB_CONSTRAINTS) |
| 1563 | return bset_print_constraints_polylib(bset, p); |
| 1564 | else if (p->output_format == ISL_FORMAT_OMEGA) |
| 1565 | return basic_set_print_omega(bset, p); |
| 1566 | isl_assert(p->ctx, 0, goto error); |
| 1567 | error: |
| 1568 | isl_printer_free(printer: p); |
| 1569 | return NULL; |
| 1570 | } |
| 1571 | |
| 1572 | __isl_give isl_printer *isl_printer_print_set(__isl_take isl_printer *p, |
| 1573 | __isl_keep isl_set *set) |
| 1574 | { |
| 1575 | if (!p || !set) |
| 1576 | goto error; |
| 1577 | if (p->output_format == ISL_FORMAT_ISL) |
| 1578 | return isl_map_print_isl(map: set_to_map(set), p); |
| 1579 | else if (p->output_format == ISL_FORMAT_POLYLIB) |
| 1580 | return isl_set_print_polylib(set, p, ext: 0); |
| 1581 | else if (p->output_format == ISL_FORMAT_EXT_POLYLIB) |
| 1582 | return isl_set_print_polylib(set, p, ext: 1); |
| 1583 | else if (p->output_format == ISL_FORMAT_OMEGA) |
| 1584 | return isl_set_print_omega(set, p); |
| 1585 | else if (p->output_format == ISL_FORMAT_LATEX) |
| 1586 | return isl_map_print_latex(map: set_to_map(set), p); |
| 1587 | isl_assert(set->ctx, 0, goto error); |
| 1588 | error: |
| 1589 | isl_printer_free(printer: p); |
| 1590 | return NULL; |
| 1591 | } |
| 1592 | |
| 1593 | __isl_give isl_printer *isl_printer_print_map(__isl_take isl_printer *p, |
| 1594 | __isl_keep isl_map *map) |
| 1595 | { |
| 1596 | if (!p || !map) |
| 1597 | goto error; |
| 1598 | |
| 1599 | if (p->output_format == ISL_FORMAT_ISL) |
| 1600 | return isl_map_print_isl(map, p); |
| 1601 | else if (p->output_format == ISL_FORMAT_POLYLIB) |
| 1602 | return isl_map_print_polylib(map, p, ext: 0); |
| 1603 | else if (p->output_format == ISL_FORMAT_EXT_POLYLIB) |
| 1604 | return isl_map_print_polylib(map, p, ext: 1); |
| 1605 | else if (p->output_format == ISL_FORMAT_OMEGA) |
| 1606 | return isl_map_print_omega(map, p); |
| 1607 | else if (p->output_format == ISL_FORMAT_LATEX) |
| 1608 | return isl_map_print_latex(map, p); |
| 1609 | isl_assert(map->ctx, 0, goto error); |
| 1610 | error: |
| 1611 | isl_printer_free(printer: p); |
| 1612 | return NULL; |
| 1613 | } |
| 1614 | |
| 1615 | struct isl_union_print_data { |
| 1616 | isl_printer *p; |
| 1617 | int first; |
| 1618 | }; |
| 1619 | |
| 1620 | #undef BASE |
| 1621 | #define BASE map |
| 1622 | #include "isl_union_print_templ.c" |
| 1623 | |
| 1624 | /* Print the body of "uset" (everything except the parameter declarations) |
| 1625 | * to "p" in isl format. |
| 1626 | */ |
| 1627 | static __isl_give isl_printer *isl_printer_print_union_set_isl_body( |
| 1628 | __isl_take isl_printer *p, __isl_keep isl_union_set *uset) |
| 1629 | { |
| 1630 | return print_body_union_map(p, u: uset_to_umap(uset)); |
| 1631 | } |
| 1632 | |
| 1633 | static isl_stat print_latex_map_body(__isl_take isl_map *map, void *user) |
| 1634 | { |
| 1635 | struct isl_union_print_data *data; |
| 1636 | data = (struct isl_union_print_data *)user; |
| 1637 | |
| 1638 | if (!data->first) |
| 1639 | data->p = isl_printer_print_str(p: data->p, s: " \\cup " ); |
| 1640 | data->first = 0; |
| 1641 | |
| 1642 | data->p = isl_map_print_latex(map, p: data->p); |
| 1643 | isl_map_free(map); |
| 1644 | |
| 1645 | return isl_stat_ok; |
| 1646 | } |
| 1647 | |
| 1648 | static __isl_give isl_printer *isl_union_map_print_latex( |
| 1649 | __isl_keep isl_union_map *umap, __isl_take isl_printer *p) |
| 1650 | { |
| 1651 | struct isl_union_print_data data = { p, 1 }; |
| 1652 | isl_union_map_foreach_map(umap, fn: &print_latex_map_body, user: &data); |
| 1653 | p = data.p; |
| 1654 | return p; |
| 1655 | } |
| 1656 | |
| 1657 | __isl_give isl_printer *isl_printer_print_union_map(__isl_take isl_printer *p, |
| 1658 | __isl_keep isl_union_map *umap) |
| 1659 | { |
| 1660 | if (!p || !umap) |
| 1661 | goto error; |
| 1662 | |
| 1663 | if (p->output_format == ISL_FORMAT_ISL) |
| 1664 | return print_union_map_isl(p, u: umap); |
| 1665 | if (p->output_format == ISL_FORMAT_LATEX) |
| 1666 | return isl_union_map_print_latex(umap, p); |
| 1667 | |
| 1668 | isl_die(p->ctx, isl_error_invalid, |
| 1669 | "invalid output format for isl_union_map" , goto error); |
| 1670 | error: |
| 1671 | isl_printer_free(printer: p); |
| 1672 | return NULL; |
| 1673 | } |
| 1674 | |
| 1675 | __isl_give isl_printer *isl_printer_print_union_set(__isl_take isl_printer *p, |
| 1676 | __isl_keep isl_union_set *uset) |
| 1677 | { |
| 1678 | if (!p || !uset) |
| 1679 | goto error; |
| 1680 | |
| 1681 | if (p->output_format == ISL_FORMAT_ISL) |
| 1682 | return print_union_map_isl(p, u: uset_to_umap(uset)); |
| 1683 | if (p->output_format == ISL_FORMAT_LATEX) |
| 1684 | return isl_union_map_print_latex(umap: uset_to_umap(uset), p); |
| 1685 | |
| 1686 | isl_die(p->ctx, isl_error_invalid, |
| 1687 | "invalid output format for isl_union_set" , goto error); |
| 1688 | error: |
| 1689 | isl_printer_free(printer: p); |
| 1690 | return NULL; |
| 1691 | } |
| 1692 | |
| 1693 | static isl_size poly_rec_n_non_zero(__isl_keep isl_poly_rec *rec) |
| 1694 | { |
| 1695 | int i; |
| 1696 | int n; |
| 1697 | |
| 1698 | if (!rec) |
| 1699 | return isl_size_error; |
| 1700 | |
| 1701 | for (i = 0, n = 0; i < rec->n; ++i) { |
| 1702 | isl_bool is_zero = isl_poly_is_zero(poly: rec->p[i]); |
| 1703 | |
| 1704 | if (is_zero < 0) |
| 1705 | return isl_size_error; |
| 1706 | if (!is_zero) |
| 1707 | ++n; |
| 1708 | } |
| 1709 | |
| 1710 | return n; |
| 1711 | } |
| 1712 | |
| 1713 | static __isl_give isl_printer *poly_print_cst(__isl_keep isl_poly *poly, |
| 1714 | __isl_take isl_printer *p, int first) |
| 1715 | { |
| 1716 | isl_poly_cst *cst; |
| 1717 | int neg; |
| 1718 | |
| 1719 | cst = isl_poly_as_cst(poly); |
| 1720 | if (!cst) |
| 1721 | goto error; |
| 1722 | neg = !first && isl_int_is_neg(cst->n); |
| 1723 | if (!first) |
| 1724 | p = isl_printer_print_str(p, s: neg ? " - " : " + " ); |
| 1725 | if (neg) |
| 1726 | isl_int_neg(cst->n, cst->n); |
| 1727 | if (isl_int_is_zero(cst->d)) { |
| 1728 | int sgn = isl_int_sgn(cst->n); |
| 1729 | p = isl_printer_print_str(p, s: sgn < 0 ? "-infty" : |
| 1730 | sgn == 0 ? "NaN" : "infty" ); |
| 1731 | } else |
| 1732 | p = isl_printer_print_isl_int(p, i: cst->n); |
| 1733 | if (neg) |
| 1734 | isl_int_neg(cst->n, cst->n); |
| 1735 | if (!isl_int_is_zero(cst->d) && !isl_int_is_one(cst->d)) { |
| 1736 | p = isl_printer_print_str(p, s: "/" ); |
| 1737 | p = isl_printer_print_isl_int(p, i: cst->d); |
| 1738 | } |
| 1739 | return p; |
| 1740 | error: |
| 1741 | isl_printer_free(printer: p); |
| 1742 | return NULL; |
| 1743 | } |
| 1744 | |
| 1745 | static __isl_give isl_printer *print_base(__isl_take isl_printer *p, |
| 1746 | __isl_keep isl_space *space, __isl_keep isl_mat *div, int var) |
| 1747 | { |
| 1748 | isl_size total; |
| 1749 | |
| 1750 | total = isl_space_dim(space, type: isl_dim_all); |
| 1751 | if (total < 0) |
| 1752 | return isl_printer_free(printer: p); |
| 1753 | if (var < total) |
| 1754 | p = print_term(space, NULL, c: space->ctx->one, pos: 1 + var, p, latex: 0); |
| 1755 | else |
| 1756 | p = print_div(space, div, pos: var - total, p); |
| 1757 | return p; |
| 1758 | } |
| 1759 | |
| 1760 | static __isl_give isl_printer *print_pow(__isl_take isl_printer *p, |
| 1761 | __isl_keep isl_space *space, __isl_keep isl_mat *div, int var, int exp) |
| 1762 | { |
| 1763 | p = print_base(p, space, div, var); |
| 1764 | if (exp == 1) |
| 1765 | return p; |
| 1766 | if (p->output_format == ISL_FORMAT_C) { |
| 1767 | int i; |
| 1768 | for (i = 1; i < exp; ++i) { |
| 1769 | p = isl_printer_print_str(p, s: "*" ); |
| 1770 | p = print_base(p, space, div, var); |
| 1771 | } |
| 1772 | } else { |
| 1773 | p = isl_printer_print_str(p, s: "^" ); |
| 1774 | p = isl_printer_print_int(p, i: exp); |
| 1775 | } |
| 1776 | return p; |
| 1777 | } |
| 1778 | |
| 1779 | /* Print the polynomial "poly" defined over the domain space "space" and |
| 1780 | * local variables defined by "div" to "p". |
| 1781 | */ |
| 1782 | static __isl_give isl_printer *poly_print(__isl_keep isl_poly *poly, |
| 1783 | __isl_keep isl_space *space, __isl_keep isl_mat *div, |
| 1784 | __isl_take isl_printer *p) |
| 1785 | { |
| 1786 | int i, first, print_parens; |
| 1787 | isl_size n; |
| 1788 | isl_bool is_cst; |
| 1789 | isl_poly_rec *rec; |
| 1790 | |
| 1791 | is_cst = isl_poly_is_cst(poly); |
| 1792 | if (!p || is_cst < 0 || !space || !div) |
| 1793 | goto error; |
| 1794 | |
| 1795 | if (is_cst) |
| 1796 | return poly_print_cst(poly, p, first: 1); |
| 1797 | |
| 1798 | rec = isl_poly_as_rec(poly); |
| 1799 | n = poly_rec_n_non_zero(rec); |
| 1800 | if (n < 0) |
| 1801 | return isl_printer_free(printer: p); |
| 1802 | print_parens = n > 1; |
| 1803 | if (print_parens) |
| 1804 | p = isl_printer_print_str(p, s: "(" ); |
| 1805 | for (i = 0, first = 1; i < rec->n; ++i) { |
| 1806 | isl_bool is_zero = isl_poly_is_zero(poly: rec->p[i]); |
| 1807 | isl_bool is_one = isl_poly_is_one(poly: rec->p[i]); |
| 1808 | isl_bool is_negone = isl_poly_is_negone(poly: rec->p[i]); |
| 1809 | isl_bool is_cst = isl_poly_is_cst(poly: rec->p[i]); |
| 1810 | |
| 1811 | if (is_zero < 0 || is_one < 0 || is_negone < 0) |
| 1812 | return isl_printer_free(printer: p); |
| 1813 | if (is_zero) |
| 1814 | continue; |
| 1815 | if (is_negone) { |
| 1816 | if (!i) |
| 1817 | p = isl_printer_print_str(p, s: "-1" ); |
| 1818 | else if (first) |
| 1819 | p = isl_printer_print_str(p, s: "-" ); |
| 1820 | else |
| 1821 | p = isl_printer_print_str(p, s: " - " ); |
| 1822 | } else if (is_cst && !is_one) |
| 1823 | p = poly_print_cst(poly: rec->p[i], p, first); |
| 1824 | else { |
| 1825 | if (!first) |
| 1826 | p = isl_printer_print_str(p, s: " + " ); |
| 1827 | if (i == 0 || !is_one) |
| 1828 | p = poly_print(poly: rec->p[i], space, div, p); |
| 1829 | } |
| 1830 | first = 0; |
| 1831 | if (i == 0) |
| 1832 | continue; |
| 1833 | if (!is_one && !is_negone) |
| 1834 | p = isl_printer_print_str(p, s: " * " ); |
| 1835 | p = print_pow(p, space, div, var: rec->poly.var, exp: i); |
| 1836 | } |
| 1837 | if (print_parens) |
| 1838 | p = isl_printer_print_str(p, s: ")" ); |
| 1839 | return p; |
| 1840 | error: |
| 1841 | isl_printer_free(printer: p); |
| 1842 | return NULL; |
| 1843 | } |
| 1844 | |
| 1845 | static __isl_give isl_printer *print_qpolynomial(__isl_take isl_printer *p, |
| 1846 | __isl_keep isl_qpolynomial *qp) |
| 1847 | { |
| 1848 | if (!p || !qp) |
| 1849 | goto error; |
| 1850 | p = poly_print(poly: qp->poly, space: qp->dim, div: qp->div, p); |
| 1851 | return p; |
| 1852 | error: |
| 1853 | isl_printer_free(printer: p); |
| 1854 | return NULL; |
| 1855 | } |
| 1856 | |
| 1857 | static __isl_give isl_printer *print_qpolynomial_isl(__isl_take isl_printer *p, |
| 1858 | __isl_keep isl_qpolynomial *qp) |
| 1859 | { |
| 1860 | struct isl_print_space_data data = { 0 }; |
| 1861 | |
| 1862 | if (!p || !qp) |
| 1863 | goto error; |
| 1864 | |
| 1865 | p = print_param_tuple(p, space: qp->dim, data: &data); |
| 1866 | p = isl_printer_print_str(p, s: "{ " ); |
| 1867 | if (!isl_space_is_params(space: qp->dim)) { |
| 1868 | p = isl_print_space(space: qp->dim, p, rational: 0, data: &data); |
| 1869 | p = isl_printer_print_str(p, s: " -> " ); |
| 1870 | } |
| 1871 | p = print_qpolynomial(p, qp); |
| 1872 | p = isl_printer_print_str(p, s: " }" ); |
| 1873 | return p; |
| 1874 | error: |
| 1875 | isl_printer_free(printer: p); |
| 1876 | return NULL; |
| 1877 | } |
| 1878 | |
| 1879 | /* Print the quasi-polynomial "qp" to "p" in C format, with the variable names |
| 1880 | * taken from the domain space "space". |
| 1881 | */ |
| 1882 | static __isl_give isl_printer *print_qpolynomial_c(__isl_take isl_printer *p, |
| 1883 | __isl_keep isl_space *space, __isl_keep isl_qpolynomial *qp) |
| 1884 | { |
| 1885 | isl_bool is_one; |
| 1886 | isl_val *den; |
| 1887 | |
| 1888 | den = isl_qpolynomial_get_den(qp); |
| 1889 | qp = isl_qpolynomial_copy(qp); |
| 1890 | qp = isl_qpolynomial_scale_val(qp, v: isl_val_copy(v: den)); |
| 1891 | is_one = isl_val_is_one(v: den); |
| 1892 | if (is_one < 0) |
| 1893 | p = isl_printer_free(printer: p); |
| 1894 | if (!is_one) |
| 1895 | p = isl_printer_print_str(p, s: "(" ); |
| 1896 | if (qp) |
| 1897 | p = poly_print(poly: qp->poly, space, div: qp->div, p); |
| 1898 | else |
| 1899 | p = isl_printer_free(printer: p); |
| 1900 | if (!is_one) { |
| 1901 | p = isl_printer_print_str(p, s: ")/" ); |
| 1902 | p = isl_printer_print_val(p, v: den); |
| 1903 | } |
| 1904 | isl_qpolynomial_free(qp); |
| 1905 | isl_val_free(v: den); |
| 1906 | return p; |
| 1907 | } |
| 1908 | |
| 1909 | __isl_give isl_printer *isl_printer_print_qpolynomial( |
| 1910 | __isl_take isl_printer *p, __isl_keep isl_qpolynomial *qp) |
| 1911 | { |
| 1912 | if (!p || !qp) |
| 1913 | goto error; |
| 1914 | |
| 1915 | if (p->output_format == ISL_FORMAT_ISL) |
| 1916 | return print_qpolynomial_isl(p, qp); |
| 1917 | else if (p->output_format == ISL_FORMAT_C) |
| 1918 | return print_qpolynomial_c(p, space: qp->dim, qp); |
| 1919 | else |
| 1920 | isl_die(qp->dim->ctx, isl_error_unsupported, |
| 1921 | "output format not supported for isl_qpolynomials" , |
| 1922 | goto error); |
| 1923 | error: |
| 1924 | isl_printer_free(printer: p); |
| 1925 | return NULL; |
| 1926 | } |
| 1927 | |
| 1928 | void isl_qpolynomial_print(__isl_keep isl_qpolynomial *qp, FILE *out, |
| 1929 | unsigned output_format) |
| 1930 | { |
| 1931 | isl_printer *p; |
| 1932 | |
| 1933 | if (!qp) |
| 1934 | return; |
| 1935 | |
| 1936 | isl_assert(qp->dim->ctx, output_format == ISL_FORMAT_ISL, return); |
| 1937 | p = isl_printer_to_file(ctx: qp->dim->ctx, file: out); |
| 1938 | p = isl_printer_print_qpolynomial(p, qp); |
| 1939 | isl_printer_free(printer: p); |
| 1940 | } |
| 1941 | |
| 1942 | static __isl_give isl_printer *qpolynomial_fold_print( |
| 1943 | __isl_keep isl_qpolynomial_fold *fold, __isl_take isl_printer *p) |
| 1944 | { |
| 1945 | int i; |
| 1946 | isl_qpolynomial_list *list; |
| 1947 | isl_size n; |
| 1948 | |
| 1949 | list = isl_qpolynomial_fold_peek_list(fold); |
| 1950 | n = isl_qpolynomial_list_size(list); |
| 1951 | if (n < 0) |
| 1952 | return isl_printer_free(printer: p); |
| 1953 | if (fold->type == isl_fold_min) |
| 1954 | p = isl_printer_print_str(p, s: "min" ); |
| 1955 | else if (fold->type == isl_fold_max) |
| 1956 | p = isl_printer_print_str(p, s: "max" ); |
| 1957 | p = isl_printer_print_str(p, s: "(" ); |
| 1958 | for (i = 0; i < n; ++i) { |
| 1959 | isl_qpolynomial *qp; |
| 1960 | |
| 1961 | if (i) |
| 1962 | p = isl_printer_print_str(p, s: ", " ); |
| 1963 | qp = isl_qpolynomial_list_peek(list, index: i); |
| 1964 | p = print_qpolynomial(p, qp); |
| 1965 | } |
| 1966 | p = isl_printer_print_str(p, s: ")" ); |
| 1967 | return p; |
| 1968 | } |
| 1969 | |
| 1970 | void isl_qpolynomial_fold_print(__isl_keep isl_qpolynomial_fold *fold, |
| 1971 | FILE *out, unsigned output_format) |
| 1972 | { |
| 1973 | isl_printer *p; |
| 1974 | |
| 1975 | if (!fold) |
| 1976 | return; |
| 1977 | |
| 1978 | isl_assert(fold->dim->ctx, output_format == ISL_FORMAT_ISL, return); |
| 1979 | |
| 1980 | p = isl_printer_to_file(ctx: fold->dim->ctx, file: out); |
| 1981 | p = isl_printer_print_qpolynomial_fold(p, fold); |
| 1982 | |
| 1983 | isl_printer_free(printer: p); |
| 1984 | } |
| 1985 | |
| 1986 | static __isl_give isl_printer *print_body_pw_qpolynomial( |
| 1987 | __isl_take isl_printer *p, __isl_keep isl_pw_qpolynomial *pwqp) |
| 1988 | { |
| 1989 | struct isl_print_space_data data = { 0 }; |
| 1990 | int i = 0; |
| 1991 | |
| 1992 | for (i = 0; i < pwqp->n; ++i) { |
| 1993 | isl_space *space; |
| 1994 | |
| 1995 | if (i) |
| 1996 | p = isl_printer_print_str(p, s: "; " ); |
| 1997 | space = isl_qpolynomial_get_domain_space(qp: pwqp->p[i].qp); |
| 1998 | if (!isl_space_is_params(space)) { |
| 1999 | p = isl_print_space(space, p, rational: 0, data: &data); |
| 2000 | p = isl_printer_print_str(p, s: " -> " ); |
| 2001 | } |
| 2002 | p = print_qpolynomial(p, qp: pwqp->p[i].qp); |
| 2003 | p = print_disjuncts(map: set_to_map(pwqp->p[i].set), space, p, latex: 0); |
| 2004 | isl_space_free(space); |
| 2005 | } |
| 2006 | |
| 2007 | return p; |
| 2008 | } |
| 2009 | |
| 2010 | static __isl_give isl_printer *print_pw_qpolynomial_isl( |
| 2011 | __isl_take isl_printer *p, __isl_keep isl_pw_qpolynomial *pwqp) |
| 2012 | { |
| 2013 | struct isl_print_space_data data = { 0 }; |
| 2014 | |
| 2015 | if (!p || !pwqp) |
| 2016 | goto error; |
| 2017 | |
| 2018 | p = print_param_tuple(p, space: pwqp->dim, data: &data); |
| 2019 | p = isl_printer_print_str(p, s: "{ " ); |
| 2020 | if (pwqp->n == 0) { |
| 2021 | if (!isl_space_is_set(space: pwqp->dim)) { |
| 2022 | p = print_tuple(space: pwqp->dim, p, type: isl_dim_in, data: &data); |
| 2023 | p = isl_printer_print_str(p, s: " -> " ); |
| 2024 | } |
| 2025 | p = isl_printer_print_str(p, s: "0" ); |
| 2026 | } |
| 2027 | p = print_body_pw_qpolynomial(p, pwqp); |
| 2028 | p = isl_printer_print_str(p, s: " }" ); |
| 2029 | return p; |
| 2030 | error: |
| 2031 | isl_printer_free(printer: p); |
| 2032 | return NULL; |
| 2033 | } |
| 2034 | |
| 2035 | void isl_pw_qpolynomial_print(__isl_keep isl_pw_qpolynomial *pwqp, FILE *out, |
| 2036 | unsigned output_format) |
| 2037 | { |
| 2038 | isl_printer *p; |
| 2039 | |
| 2040 | if (!pwqp) |
| 2041 | return; |
| 2042 | |
| 2043 | p = isl_printer_to_file(ctx: pwqp->dim->ctx, file: out); |
| 2044 | p = isl_printer_set_output_format(p, output_format); |
| 2045 | p = isl_printer_print_pw_qpolynomial(p, pwqp); |
| 2046 | |
| 2047 | isl_printer_free(printer: p); |
| 2048 | } |
| 2049 | |
| 2050 | static __isl_give isl_printer *print_body_pw_qpolynomial_fold( |
| 2051 | __isl_take isl_printer *p, __isl_keep isl_pw_qpolynomial_fold *pwf) |
| 2052 | { |
| 2053 | struct isl_print_space_data data = { 0 }; |
| 2054 | int i = 0; |
| 2055 | |
| 2056 | for (i = 0; i < pwf->n; ++i) { |
| 2057 | isl_space *space; |
| 2058 | |
| 2059 | if (i) |
| 2060 | p = isl_printer_print_str(p, s: "; " ); |
| 2061 | space = isl_qpolynomial_fold_get_domain_space(fold: pwf->p[i].fold); |
| 2062 | if (!isl_space_is_params(space)) { |
| 2063 | p = isl_print_space(space, p, rational: 0, data: &data); |
| 2064 | p = isl_printer_print_str(p, s: " -> " ); |
| 2065 | } |
| 2066 | p = qpolynomial_fold_print(fold: pwf->p[i].fold, p); |
| 2067 | p = print_disjuncts(map: set_to_map(pwf->p[i].set), space, p, latex: 0); |
| 2068 | isl_space_free(space); |
| 2069 | } |
| 2070 | |
| 2071 | return p; |
| 2072 | } |
| 2073 | |
| 2074 | static __isl_give isl_printer *print_pw_qpolynomial_fold_isl( |
| 2075 | __isl_take isl_printer *p, __isl_keep isl_pw_qpolynomial_fold *pwf) |
| 2076 | { |
| 2077 | struct isl_print_space_data data = { 0 }; |
| 2078 | |
| 2079 | p = print_param_tuple(p, space: pwf->dim, data: &data); |
| 2080 | p = isl_printer_print_str(p, s: "{ " ); |
| 2081 | if (pwf->n == 0) { |
| 2082 | if (!isl_space_is_set(space: pwf->dim)) { |
| 2083 | p = print_tuple(space: pwf->dim, p, type: isl_dim_in, data: &data); |
| 2084 | p = isl_printer_print_str(p, s: " -> " ); |
| 2085 | } |
| 2086 | p = isl_printer_print_str(p, s: "0" ); |
| 2087 | } |
| 2088 | p = print_body_pw_qpolynomial_fold(p, pwf); |
| 2089 | p = isl_printer_print_str(p, s: " }" ); |
| 2090 | return p; |
| 2091 | } |
| 2092 | |
| 2093 | static __isl_give isl_printer *print_ls_affine_c(__isl_take isl_printer *p, |
| 2094 | __isl_keep isl_local_space *ls, isl_int *c); |
| 2095 | |
| 2096 | /* We skip the constraint if it is implied by the div expression. |
| 2097 | * |
| 2098 | * *first indicates whether this is the first constraint in the conjunction and |
| 2099 | * is updated if the constraint is actually printed. |
| 2100 | */ |
| 2101 | static __isl_give isl_printer *print_constraint_c(__isl_take isl_printer *p, |
| 2102 | __isl_keep isl_local_space *ls, isl_int *c, const char *op, int *first) |
| 2103 | { |
| 2104 | unsigned o_div; |
| 2105 | isl_size n_div; |
| 2106 | int div; |
| 2107 | |
| 2108 | o_div = isl_local_space_offset(ls, type: isl_dim_div); |
| 2109 | n_div = isl_local_space_dim(ls, type: isl_dim_div); |
| 2110 | if (n_div < 0) |
| 2111 | return isl_printer_free(printer: p); |
| 2112 | div = isl_seq_last_non_zero(p: c + o_div, len: n_div); |
| 2113 | if (div >= 0) { |
| 2114 | isl_bool is_div = isl_local_space_is_div_constraint(ls, constraint: c, div); |
| 2115 | if (is_div < 0) |
| 2116 | return isl_printer_free(printer: p); |
| 2117 | if (is_div) |
| 2118 | return p; |
| 2119 | } |
| 2120 | |
| 2121 | if (!*first) |
| 2122 | p = isl_printer_print_str(p, s: " && " ); |
| 2123 | |
| 2124 | p = print_ls_affine_c(p, ls, c); |
| 2125 | p = isl_printer_print_str(p, s: " " ); |
| 2126 | p = isl_printer_print_str(p, s: op); |
| 2127 | p = isl_printer_print_str(p, s: " 0" ); |
| 2128 | |
| 2129 | *first = 0; |
| 2130 | |
| 2131 | return p; |
| 2132 | } |
| 2133 | |
| 2134 | static __isl_give isl_printer *print_ls_partial_affine_c( |
| 2135 | __isl_take isl_printer *p, __isl_keep isl_local_space *ls, |
| 2136 | isl_int *c, unsigned len); |
| 2137 | |
| 2138 | static __isl_give isl_printer *print_basic_set_c(__isl_take isl_printer *p, |
| 2139 | __isl_keep isl_space *space, __isl_keep isl_basic_set *bset) |
| 2140 | { |
| 2141 | int i, j; |
| 2142 | int first = 1; |
| 2143 | isl_size n_div = isl_basic_set_dim(bset, type: isl_dim_div); |
| 2144 | isl_size total = isl_basic_set_dim(bset, type: isl_dim_all); |
| 2145 | isl_mat *div; |
| 2146 | isl_local_space *ls; |
| 2147 | |
| 2148 | if (n_div < 0 || total < 0) |
| 2149 | return isl_printer_free(printer: p); |
| 2150 | |
| 2151 | total -= n_div; |
| 2152 | div = isl_basic_set_get_divs(bset); |
| 2153 | ls = isl_local_space_alloc_div(space: isl_space_copy(space), div); |
| 2154 | for (i = 0; i < bset->n_eq; ++i) { |
| 2155 | j = isl_seq_last_non_zero(p: bset->eq[i] + 1 + total, len: n_div); |
| 2156 | if (j < 0) |
| 2157 | p = print_constraint_c(p, ls, |
| 2158 | c: bset->eq[i], op: "==" , first: &first); |
| 2159 | else { |
| 2160 | if (i) |
| 2161 | p = isl_printer_print_str(p, s: " && " ); |
| 2162 | p = isl_printer_print_str(p, s: "(" ); |
| 2163 | p = print_ls_partial_affine_c(p, ls, c: bset->eq[i], |
| 2164 | len: 1 + total + j); |
| 2165 | p = isl_printer_print_str(p, s: ") % " ); |
| 2166 | p = isl_printer_print_isl_int(p, |
| 2167 | i: bset->eq[i][1 + total + j]); |
| 2168 | p = isl_printer_print_str(p, s: " == 0" ); |
| 2169 | first = 0; |
| 2170 | } |
| 2171 | } |
| 2172 | for (i = 0; i < bset->n_ineq; ++i) |
| 2173 | p = print_constraint_c(p, ls, c: bset->ineq[i], op: ">=" , first: &first); |
| 2174 | isl_local_space_free(ls); |
| 2175 | return p; |
| 2176 | } |
| 2177 | |
| 2178 | static __isl_give isl_printer *print_set_c(__isl_take isl_printer *p, |
| 2179 | __isl_keep isl_space *space, __isl_keep isl_set *set) |
| 2180 | { |
| 2181 | int i; |
| 2182 | |
| 2183 | if (!set) |
| 2184 | return isl_printer_free(printer: p); |
| 2185 | |
| 2186 | if (set->n == 0) |
| 2187 | p = isl_printer_print_str(p, s: "0" ); |
| 2188 | |
| 2189 | for (i = 0; i < set->n; ++i) { |
| 2190 | if (i) |
| 2191 | p = isl_printer_print_str(p, s: " || " ); |
| 2192 | if (set->n > 1) |
| 2193 | p = isl_printer_print_str(p, s: "(" ); |
| 2194 | p = print_basic_set_c(p, space, bset: set->p[i]); |
| 2195 | if (set->n > 1) |
| 2196 | p = isl_printer_print_str(p, s: ")" ); |
| 2197 | } |
| 2198 | return p; |
| 2199 | } |
| 2200 | |
| 2201 | /* Print the piecewise quasi-polynomial "pwqp" to "p" in C format. |
| 2202 | */ |
| 2203 | static __isl_give isl_printer *print_pw_qpolynomial_c( |
| 2204 | __isl_take isl_printer *p, __isl_keep isl_pw_qpolynomial *pwqp) |
| 2205 | { |
| 2206 | int i; |
| 2207 | isl_space *space; |
| 2208 | |
| 2209 | space = isl_pw_qpolynomial_get_domain_space(pwqp); |
| 2210 | if (pwqp->n == 1 && isl_set_plain_is_universe(set: pwqp->p[0].set)) { |
| 2211 | p = print_qpolynomial_c(p, space, qp: pwqp->p[0].qp); |
| 2212 | isl_space_free(space); |
| 2213 | return p; |
| 2214 | } |
| 2215 | |
| 2216 | for (i = 0; i < pwqp->n; ++i) { |
| 2217 | p = isl_printer_print_str(p, s: "(" ); |
| 2218 | p = print_set_c(p, space, set: pwqp->p[i].set); |
| 2219 | p = isl_printer_print_str(p, s: ") ? (" ); |
| 2220 | p = print_qpolynomial_c(p, space, qp: pwqp->p[i].qp); |
| 2221 | p = isl_printer_print_str(p, s: ") : " ); |
| 2222 | } |
| 2223 | |
| 2224 | isl_space_free(space); |
| 2225 | p = isl_printer_print_str(p, s: "0" ); |
| 2226 | return p; |
| 2227 | } |
| 2228 | |
| 2229 | __isl_give isl_printer *isl_printer_print_pw_qpolynomial( |
| 2230 | __isl_take isl_printer *p, __isl_keep isl_pw_qpolynomial *pwqp) |
| 2231 | { |
| 2232 | if (!p || !pwqp) |
| 2233 | goto error; |
| 2234 | |
| 2235 | if (p->output_format == ISL_FORMAT_ISL) |
| 2236 | return print_pw_qpolynomial_isl(p, pwqp); |
| 2237 | else if (p->output_format == ISL_FORMAT_C) |
| 2238 | return print_pw_qpolynomial_c(p, pwqp); |
| 2239 | isl_assert(p->ctx, 0, goto error); |
| 2240 | error: |
| 2241 | isl_printer_free(printer: p); |
| 2242 | return NULL; |
| 2243 | } |
| 2244 | |
| 2245 | #undef BASE |
| 2246 | #define BASE pw_qpolynomial |
| 2247 | #include "isl_union_print_templ.c" |
| 2248 | |
| 2249 | __isl_give isl_printer *isl_printer_print_union_pw_qpolynomial( |
| 2250 | __isl_take isl_printer *p, __isl_keep isl_union_pw_qpolynomial *upwqp) |
| 2251 | { |
| 2252 | if (!p || !upwqp) |
| 2253 | goto error; |
| 2254 | |
| 2255 | if (p->output_format == ISL_FORMAT_ISL) |
| 2256 | return print_union_pw_qpolynomial_isl(p, u: upwqp); |
| 2257 | isl_die(p->ctx, isl_error_invalid, |
| 2258 | "invalid output format for isl_union_pw_qpolynomial" , |
| 2259 | goto error); |
| 2260 | error: |
| 2261 | isl_printer_free(printer: p); |
| 2262 | return NULL; |
| 2263 | } |
| 2264 | |
| 2265 | /* Print the quasi-polynomial reduction "fold" to "p" in C format, |
| 2266 | * with the variable names taken from the domain space "space". |
| 2267 | */ |
| 2268 | static __isl_give isl_printer *print_qpolynomial_fold_c( |
| 2269 | __isl_take isl_printer *p, __isl_keep isl_space *space, |
| 2270 | __isl_keep isl_qpolynomial_fold *fold) |
| 2271 | { |
| 2272 | int i; |
| 2273 | isl_qpolynomial_list *list; |
| 2274 | isl_size n; |
| 2275 | |
| 2276 | list = isl_qpolynomial_fold_peek_list(fold); |
| 2277 | n = isl_qpolynomial_list_size(list); |
| 2278 | if (n < 0) |
| 2279 | return isl_printer_free(printer: p); |
| 2280 | for (i = 0; i < n - 1; ++i) |
| 2281 | if (fold->type == isl_fold_min) |
| 2282 | p = isl_printer_print_str(p, s: "min(" ); |
| 2283 | else if (fold->type == isl_fold_max) |
| 2284 | p = isl_printer_print_str(p, s: "max(" ); |
| 2285 | |
| 2286 | for (i = 0; i < n; ++i) { |
| 2287 | isl_qpolynomial *qp; |
| 2288 | |
| 2289 | if (i) |
| 2290 | p = isl_printer_print_str(p, s: ", " ); |
| 2291 | qp = isl_qpolynomial_list_peek(list, index: i); |
| 2292 | p = print_qpolynomial_c(p, space, qp); |
| 2293 | if (i) |
| 2294 | p = isl_printer_print_str(p, s: ")" ); |
| 2295 | } |
| 2296 | return p; |
| 2297 | } |
| 2298 | |
| 2299 | __isl_give isl_printer *isl_printer_print_qpolynomial_fold( |
| 2300 | __isl_take isl_printer *p, __isl_keep isl_qpolynomial_fold *fold) |
| 2301 | { |
| 2302 | if (!p || !fold) |
| 2303 | goto error; |
| 2304 | if (p->output_format == ISL_FORMAT_ISL) |
| 2305 | return qpolynomial_fold_print(fold, p); |
| 2306 | else if (p->output_format == ISL_FORMAT_C) |
| 2307 | return print_qpolynomial_fold_c(p, space: fold->dim, fold); |
| 2308 | isl_die(p->ctx, isl_error_unsupported, "unsupported output format" , |
| 2309 | goto error); |
| 2310 | error: |
| 2311 | isl_printer_free(printer: p); |
| 2312 | return NULL; |
| 2313 | } |
| 2314 | |
| 2315 | /* Print the piecewise quasi-polynomial reduction "pwf" to "p" in C format. |
| 2316 | */ |
| 2317 | static __isl_give isl_printer *print_pw_qpolynomial_fold_c( |
| 2318 | __isl_take isl_printer *p, __isl_keep isl_pw_qpolynomial_fold *pwf) |
| 2319 | { |
| 2320 | int i; |
| 2321 | isl_space *space; |
| 2322 | |
| 2323 | space = isl_pw_qpolynomial_fold_get_domain_space(pwf); |
| 2324 | if (pwf->n == 1 && isl_set_plain_is_universe(set: pwf->p[0].set)) { |
| 2325 | p = print_qpolynomial_fold_c(p, space, fold: pwf->p[0].fold); |
| 2326 | isl_space_free(space); |
| 2327 | return p; |
| 2328 | } |
| 2329 | |
| 2330 | for (i = 0; i < pwf->n; ++i) { |
| 2331 | p = isl_printer_print_str(p, s: "(" ); |
| 2332 | p = print_set_c(p, space, set: pwf->p[i].set); |
| 2333 | p = isl_printer_print_str(p, s: ") ? (" ); |
| 2334 | p = print_qpolynomial_fold_c(p, space, fold: pwf->p[i].fold); |
| 2335 | p = isl_printer_print_str(p, s: ") : " ); |
| 2336 | } |
| 2337 | |
| 2338 | isl_space_free(space); |
| 2339 | p = isl_printer_print_str(p, s: "0" ); |
| 2340 | return p; |
| 2341 | } |
| 2342 | |
| 2343 | __isl_give isl_printer *isl_printer_print_pw_qpolynomial_fold( |
| 2344 | __isl_take isl_printer *p, __isl_keep isl_pw_qpolynomial_fold *pwf) |
| 2345 | { |
| 2346 | if (!p || !pwf) |
| 2347 | goto error; |
| 2348 | |
| 2349 | if (p->output_format == ISL_FORMAT_ISL) |
| 2350 | return print_pw_qpolynomial_fold_isl(p, pwf); |
| 2351 | else if (p->output_format == ISL_FORMAT_C) |
| 2352 | return print_pw_qpolynomial_fold_c(p, pwf); |
| 2353 | isl_assert(p->ctx, 0, goto error); |
| 2354 | error: |
| 2355 | isl_printer_free(printer: p); |
| 2356 | return NULL; |
| 2357 | } |
| 2358 | |
| 2359 | void isl_pw_qpolynomial_fold_print(__isl_keep isl_pw_qpolynomial_fold *pwf, |
| 2360 | FILE *out, unsigned output_format) |
| 2361 | { |
| 2362 | isl_printer *p; |
| 2363 | |
| 2364 | if (!pwf) |
| 2365 | return; |
| 2366 | |
| 2367 | p = isl_printer_to_file(ctx: pwf->dim->ctx, file: out); |
| 2368 | p = isl_printer_set_output_format(p, output_format); |
| 2369 | p = isl_printer_print_pw_qpolynomial_fold(p, pwf); |
| 2370 | |
| 2371 | isl_printer_free(printer: p); |
| 2372 | } |
| 2373 | |
| 2374 | #undef BASE |
| 2375 | #define BASE pw_qpolynomial_fold |
| 2376 | #include "isl_union_print_templ.c" |
| 2377 | |
| 2378 | __isl_give isl_printer *isl_printer_print_union_pw_qpolynomial_fold( |
| 2379 | __isl_take isl_printer *p, |
| 2380 | __isl_keep isl_union_pw_qpolynomial_fold *upwf) |
| 2381 | { |
| 2382 | if (!p || !upwf) |
| 2383 | goto error; |
| 2384 | |
| 2385 | if (p->output_format == ISL_FORMAT_ISL) |
| 2386 | return print_union_pw_qpolynomial_fold_isl(p, u: upwf); |
| 2387 | isl_die(p->ctx, isl_error_invalid, |
| 2388 | "invalid output format for isl_union_pw_qpolynomial_fold" , |
| 2389 | goto error); |
| 2390 | error: |
| 2391 | isl_printer_free(printer: p); |
| 2392 | return NULL; |
| 2393 | } |
| 2394 | |
| 2395 | /* Print the isl_constraint "c" to "p". |
| 2396 | */ |
| 2397 | __isl_give isl_printer *isl_printer_print_constraint(__isl_take isl_printer *p, |
| 2398 | __isl_keep isl_constraint *c) |
| 2399 | { |
| 2400 | struct isl_print_space_data data = { 0 }; |
| 2401 | isl_local_space *ls; |
| 2402 | isl_space *space; |
| 2403 | isl_bool exists; |
| 2404 | |
| 2405 | if (!p || !c) |
| 2406 | goto error; |
| 2407 | |
| 2408 | ls = isl_constraint_get_local_space(constraint: c); |
| 2409 | if (!ls) |
| 2410 | return isl_printer_free(printer: p); |
| 2411 | space = isl_local_space_get_space(ls); |
| 2412 | p = print_param_tuple(p, space, data: &data); |
| 2413 | p = isl_printer_print_str(p, s: "{ " ); |
| 2414 | p = isl_print_space(space, p, rational: 0, data: &data); |
| 2415 | p = isl_printer_print_str(p, s: " : " ); |
| 2416 | exists = need_exists(p, div: ls->div); |
| 2417 | if (exists < 0) |
| 2418 | p = isl_printer_free(printer: p); |
| 2419 | if (exists >= 0 && exists) |
| 2420 | p = open_exists(p, space, div: ls->div, latex: 0); |
| 2421 | p = print_affine_of_len(space, div: ls->div, p, c: c->v->el, len: c->v->size); |
| 2422 | if (isl_constraint_is_equality(constraint: c)) |
| 2423 | p = isl_printer_print_str(p, s: " = 0" ); |
| 2424 | else |
| 2425 | p = isl_printer_print_str(p, s: " >= 0" ); |
| 2426 | if (exists >= 0 && exists) |
| 2427 | p = isl_printer_print_str(p, s: s_close_exists[0]); |
| 2428 | p = isl_printer_print_str(p, s: " }" ); |
| 2429 | isl_space_free(space); |
| 2430 | isl_local_space_free(ls); |
| 2431 | |
| 2432 | return p; |
| 2433 | error: |
| 2434 | isl_printer_free(printer: p); |
| 2435 | return NULL; |
| 2436 | } |
| 2437 | |
| 2438 | static __isl_give isl_printer *isl_printer_print_space_isl( |
| 2439 | __isl_take isl_printer *p, __isl_keep isl_space *space) |
| 2440 | { |
| 2441 | struct isl_print_space_data data = { 0 }; |
| 2442 | |
| 2443 | if (!space) |
| 2444 | goto error; |
| 2445 | |
| 2446 | p = print_param_tuple(p, space, data: &data); |
| 2447 | |
| 2448 | p = isl_printer_print_str(p, s: "{ " ); |
| 2449 | if (isl_space_is_params(space)) |
| 2450 | p = isl_printer_print_str(p, s: s_such_that[0]); |
| 2451 | else |
| 2452 | p = isl_print_space(space, p, rational: 0, data: &data); |
| 2453 | p = isl_printer_print_str(p, s: " }" ); |
| 2454 | |
| 2455 | return p; |
| 2456 | error: |
| 2457 | isl_printer_free(printer: p); |
| 2458 | return NULL; |
| 2459 | } |
| 2460 | |
| 2461 | __isl_give isl_printer *isl_printer_print_space(__isl_take isl_printer *p, |
| 2462 | __isl_keep isl_space *space) |
| 2463 | { |
| 2464 | if (!p || !space) |
| 2465 | return isl_printer_free(printer: p); |
| 2466 | if (p->output_format == ISL_FORMAT_ISL) |
| 2467 | return isl_printer_print_space_isl(p, space); |
| 2468 | else if (p->output_format == ISL_FORMAT_OMEGA) |
| 2469 | return print_omega_parameters(space, p); |
| 2470 | |
| 2471 | isl_die(isl_space_get_ctx(space), isl_error_unsupported, |
| 2472 | "output format not supported for space" , |
| 2473 | return isl_printer_free(p)); |
| 2474 | } |
| 2475 | |
| 2476 | __isl_give isl_printer *isl_printer_print_local_space(__isl_take isl_printer *p, |
| 2477 | __isl_keep isl_local_space *ls) |
| 2478 | { |
| 2479 | struct isl_print_space_data data = { 0 }; |
| 2480 | isl_size n_div; |
| 2481 | |
| 2482 | n_div = isl_local_space_dim(ls, type: isl_dim_div); |
| 2483 | if (n_div < 0) |
| 2484 | goto error; |
| 2485 | |
| 2486 | p = print_param_tuple(p, space: ls->dim, data: &data); |
| 2487 | p = isl_printer_print_str(p, s: "{ " ); |
| 2488 | p = isl_print_space(space: ls->dim, p, rational: 0, data: &data); |
| 2489 | if (n_div > 0) { |
| 2490 | p = isl_printer_print_str(p, s: " : " ); |
| 2491 | p = isl_printer_print_str(p, s: s_open_exists[0]); |
| 2492 | p = print_div_list(p, space: ls->dim, div: ls->div, latex: 0, print_defined_divs: 1); |
| 2493 | p = isl_printer_print_str(p, s: s_close_exists[0]); |
| 2494 | } else if (isl_space_is_params(space: ls->dim)) |
| 2495 | p = isl_printer_print_str(p, s: s_such_that[0]); |
| 2496 | p = isl_printer_print_str(p, s: " }" ); |
| 2497 | return p; |
| 2498 | error: |
| 2499 | isl_printer_free(printer: p); |
| 2500 | return NULL; |
| 2501 | } |
| 2502 | |
| 2503 | /* Look for the last of the "n" integer divisions that is used in "aff" and |
| 2504 | * that can be printed as a modulo and |
| 2505 | * return the position of this integer division. |
| 2506 | * Return "n" if no such integer division can be found. |
| 2507 | * Return isl_size_error on error. |
| 2508 | * |
| 2509 | * In particular, look for an integer division that appears in "aff" |
| 2510 | * with a coefficient that is a multiple of the denominator |
| 2511 | * of the integer division. |
| 2512 | * That is, check if the numerator of "aff" is of the form |
| 2513 | * |
| 2514 | * f(...) + a m floor(g/m) |
| 2515 | * |
| 2516 | * and return the position of "floor(g/m)". |
| 2517 | * |
| 2518 | * Note that, unlike print_as_modulo_pos, no check needs to be made |
| 2519 | * for whether the integer division can be printed, since it will |
| 2520 | * need to be printed as an integer division anyway if it is not printed |
| 2521 | * as a modulo. |
| 2522 | */ |
| 2523 | static isl_size last_modulo(__isl_keep isl_printer *p, __isl_keep isl_aff *aff, |
| 2524 | unsigned n) |
| 2525 | { |
| 2526 | isl_size o_div; |
| 2527 | int i; |
| 2528 | |
| 2529 | if (n == 0) |
| 2530 | return n; |
| 2531 | o_div = isl_aff_domain_offset(aff, type: isl_dim_div); |
| 2532 | if (o_div < 0) |
| 2533 | return isl_size_error; |
| 2534 | for (i = n - 1; i >= 0; --i) { |
| 2535 | if (isl_int_is_zero(aff->v->el[1 + o_div + i])) |
| 2536 | continue; |
| 2537 | if (isl_int_is_divisible_by(aff->v->el[1 + o_div + i], |
| 2538 | aff->ls->div->row[i][0])) |
| 2539 | return i; |
| 2540 | } |
| 2541 | |
| 2542 | return n; |
| 2543 | } |
| 2544 | |
| 2545 | /* Print the numerator of the affine expression "aff" to "p", |
| 2546 | * with the variable names taken from "space". |
| 2547 | */ |
| 2548 | static __isl_give isl_printer *print_aff_num_base(__isl_take isl_printer *p, |
| 2549 | __isl_keep isl_space *space, __isl_keep isl_aff *aff) |
| 2550 | { |
| 2551 | isl_size total; |
| 2552 | |
| 2553 | total = isl_aff_domain_dim(aff, type: isl_dim_all); |
| 2554 | if (total < 0) |
| 2555 | return isl_printer_free(printer: p); |
| 2556 | p = print_affine_of_len(space, div: aff->ls->div, p, |
| 2557 | c: aff->v->el + 1, len: 1 + total); |
| 2558 | |
| 2559 | return p; |
| 2560 | } |
| 2561 | |
| 2562 | static __isl_give isl_printer *print_aff_num(__isl_take isl_printer *p, |
| 2563 | __isl_keep isl_space *space, __isl_keep isl_aff *aff); |
| 2564 | |
| 2565 | /* Print the modulo term "c" * ("aff" mod "mod") to "p", |
| 2566 | * with the variable names taken from "space". |
| 2567 | * If "first" is set, then this is the first term of an expression. |
| 2568 | */ |
| 2569 | static __isl_give isl_printer *print_mod_term(__isl_take isl_printer *p, |
| 2570 | __isl_keep isl_space *space, __isl_keep isl_aff *aff, int first, |
| 2571 | __isl_take isl_val *c, __isl_keep isl_val *mod) |
| 2572 | { |
| 2573 | isl_bool is_one, is_neg; |
| 2574 | |
| 2575 | is_neg = isl_val_is_neg(v: c); |
| 2576 | if (is_neg < 0) |
| 2577 | p = isl_printer_free(printer: p); |
| 2578 | if (!first) { |
| 2579 | if (is_neg) |
| 2580 | c = isl_val_neg(v: c); |
| 2581 | p = isl_printer_print_str(p, s: is_neg ? " - " : " + " ); |
| 2582 | } |
| 2583 | is_one = isl_val_is_one(v: c); |
| 2584 | if (is_one < 0) |
| 2585 | p = isl_printer_free(printer: p); |
| 2586 | if (!is_one) { |
| 2587 | p = isl_printer_print_val(p, v: c); |
| 2588 | p = isl_printer_print_str(p, s: "*(" ); |
| 2589 | } |
| 2590 | p = isl_printer_print_str(p, s: "(" ); |
| 2591 | p = print_aff_num(p, space, aff); |
| 2592 | p = isl_printer_print_str(p, s: ")" ); |
| 2593 | p = isl_printer_print_str(p, s: " mod " ); |
| 2594 | p = isl_printer_print_val(p, v: mod); |
| 2595 | if (!is_one) |
| 2596 | p = isl_printer_print_str(p, s: ")" ); |
| 2597 | |
| 2598 | isl_val_free(v: c); |
| 2599 | |
| 2600 | return p; |
| 2601 | } |
| 2602 | |
| 2603 | /* Print the numerator of the affine expression "aff" to "p", |
| 2604 | * with the variable names taken from "space", |
| 2605 | * given that the numerator of "aff" is of the form |
| 2606 | * |
| 2607 | * f(...) + a m floor(g/m) |
| 2608 | * |
| 2609 | * with "floor(g/m)" the integer division at position "last". |
| 2610 | * |
| 2611 | * First replace "aff" by its numerator and rewrite it as |
| 2612 | * |
| 2613 | * f(...) + a g - a (g mod m) |
| 2614 | * |
| 2615 | * Recursively write out (the numerator of) "f(...) + a g" |
| 2616 | * (which may involve other modulo expressions) and |
| 2617 | * then write out "- a (g mod m)". |
| 2618 | */ |
| 2619 | static __isl_give isl_printer *print_aff_num_mod(__isl_take isl_printer *p, |
| 2620 | __isl_keep isl_space *space, __isl_keep isl_aff *aff, unsigned last) |
| 2621 | { |
| 2622 | isl_bool is_zero; |
| 2623 | isl_val *a, *m; |
| 2624 | isl_aff *div, *term; |
| 2625 | |
| 2626 | aff = isl_aff_copy(aff); |
| 2627 | aff = isl_aff_scale_val(aff, v: isl_aff_get_denominator_val(aff)); |
| 2628 | a = isl_aff_get_coefficient_val(aff, type: isl_dim_div, pos: last); |
| 2629 | aff = isl_aff_set_coefficient_si(aff, type: isl_dim_div, pos: last, v: 0); |
| 2630 | div = isl_aff_get_div(aff, pos: last); |
| 2631 | m = isl_aff_get_denominator_val(aff: div); |
| 2632 | a = isl_val_div(v1: a, v2: isl_val_copy(v: m)); |
| 2633 | div = isl_aff_scale_val(aff: div, v: isl_val_copy(v: m)); |
| 2634 | term = isl_aff_scale_val(aff: isl_aff_copy(aff: div), v: isl_val_copy(v: a)); |
| 2635 | aff = isl_aff_add(aff1: aff, aff2: term); |
| 2636 | |
| 2637 | is_zero = isl_aff_plain_is_zero(aff); |
| 2638 | if (is_zero < 0) { |
| 2639 | p = isl_printer_free(printer: p); |
| 2640 | } else { |
| 2641 | if (!is_zero) |
| 2642 | p = print_aff_num(p, space, aff); |
| 2643 | a = isl_val_neg(v: a); |
| 2644 | p = print_mod_term(p, space, aff: div, first: is_zero, c: isl_val_copy(v: a), mod: m); |
| 2645 | } |
| 2646 | |
| 2647 | isl_val_free(v: a); |
| 2648 | isl_val_free(v: m); |
| 2649 | isl_aff_free(aff); |
| 2650 | isl_aff_free(aff: div); |
| 2651 | |
| 2652 | return p; |
| 2653 | } |
| 2654 | |
| 2655 | /* Print the numerator of the affine expression "aff" to "p", |
| 2656 | * with the variable names taken from "space", |
| 2657 | * separating out any (obvious) modulo expressions. |
| 2658 | * |
| 2659 | * In particular, look for modulo expressions in "aff", |
| 2660 | * separating them out if found and simply printing out "aff" otherwise. |
| 2661 | */ |
| 2662 | static __isl_give isl_printer *print_aff_num(__isl_take isl_printer *p, |
| 2663 | __isl_keep isl_space *space, __isl_keep isl_aff *aff) |
| 2664 | { |
| 2665 | isl_size n_div, mod; |
| 2666 | |
| 2667 | n_div = isl_aff_dim(aff, type: isl_dim_div); |
| 2668 | if (n_div < 0) |
| 2669 | return isl_printer_free(printer: p); |
| 2670 | mod = last_modulo(p, aff, n: n_div); |
| 2671 | if (mod < 0) |
| 2672 | return isl_printer_free(printer: p); |
| 2673 | if (mod < n_div) |
| 2674 | return print_aff_num_mod(p, space, aff, last: mod); |
| 2675 | else |
| 2676 | return print_aff_num_base(p, space, aff); |
| 2677 | } |
| 2678 | |
| 2679 | /* Print the (potentially rational) affine expression "aff" to "p", |
| 2680 | * with the variable names taken from "space". |
| 2681 | */ |
| 2682 | static __isl_give isl_printer *print_aff_body(__isl_take isl_printer *p, |
| 2683 | __isl_keep isl_space *space, __isl_keep isl_aff *aff) |
| 2684 | { |
| 2685 | if (isl_aff_is_nan(aff)) |
| 2686 | return isl_printer_print_str(p, s: "NaN" ); |
| 2687 | |
| 2688 | p = isl_printer_print_str(p, s: "(" ); |
| 2689 | p = print_aff_num(p, space, aff); |
| 2690 | if (isl_int_is_one(aff->v->el[0])) |
| 2691 | p = isl_printer_print_str(p, s: ")" ); |
| 2692 | else { |
| 2693 | p = isl_printer_print_str(p, s: ")/" ); |
| 2694 | p = isl_printer_print_isl_int(p, i: aff->v->el[0]); |
| 2695 | } |
| 2696 | |
| 2697 | return p; |
| 2698 | } |
| 2699 | |
| 2700 | static __isl_give isl_printer *print_body_aff(__isl_take isl_printer *p, |
| 2701 | __isl_keep isl_aff *aff) |
| 2702 | { |
| 2703 | struct isl_print_space_data data = { 0 }; |
| 2704 | |
| 2705 | if (isl_space_is_params(space: aff->ls->dim)) |
| 2706 | ; |
| 2707 | else { |
| 2708 | p = print_tuple(space: aff->ls->dim, p, type: isl_dim_set, data: &data); |
| 2709 | p = isl_printer_print_str(p, s: " -> " ); |
| 2710 | } |
| 2711 | p = isl_printer_print_str(p, s: "[" ); |
| 2712 | p = print_aff_body(p, space: aff->ls->dim, aff); |
| 2713 | p = isl_printer_print_str(p, s: "]" ); |
| 2714 | |
| 2715 | return p; |
| 2716 | } |
| 2717 | |
| 2718 | static __isl_give isl_printer *print_aff_isl(__isl_take isl_printer *p, |
| 2719 | __isl_keep isl_aff *aff) |
| 2720 | { |
| 2721 | struct isl_print_space_data data = { 0 }; |
| 2722 | |
| 2723 | if (!aff) |
| 2724 | goto error; |
| 2725 | |
| 2726 | p = print_param_tuple(p, space: aff->ls->dim, data: &data); |
| 2727 | p = isl_printer_print_str(p, s: "{ " ); |
| 2728 | p = print_body_aff(p, aff); |
| 2729 | p = isl_printer_print_str(p, s: " }" ); |
| 2730 | return p; |
| 2731 | error: |
| 2732 | isl_printer_free(printer: p); |
| 2733 | return NULL; |
| 2734 | } |
| 2735 | |
| 2736 | #undef BASE |
| 2737 | #define BASE aff |
| 2738 | #include "isl_pw_print_templ.c" |
| 2739 | |
| 2740 | static __isl_give isl_printer *print_ls_name_c(__isl_take isl_printer *p, |
| 2741 | __isl_keep isl_local_space *ls, enum isl_dim_type type, unsigned pos) |
| 2742 | { |
| 2743 | if (type == isl_dim_div) { |
| 2744 | p = isl_printer_print_str(p, s: "floord(" ); |
| 2745 | p = print_ls_affine_c(p, ls, c: ls->div->row[pos] + 1); |
| 2746 | p = isl_printer_print_str(p, s: ", " ); |
| 2747 | p = isl_printer_print_isl_int(p, i: ls->div->row[pos][0]); |
| 2748 | p = isl_printer_print_str(p, s: ")" ); |
| 2749 | } else { |
| 2750 | const char *name; |
| 2751 | |
| 2752 | name = isl_space_get_dim_name(space: ls->dim, type, pos); |
| 2753 | if (!name) |
| 2754 | name = "UNNAMED" ; |
| 2755 | p = isl_printer_print_str(p, s: name); |
| 2756 | } |
| 2757 | return p; |
| 2758 | } |
| 2759 | |
| 2760 | static __isl_give isl_printer *print_ls_term_c(__isl_take isl_printer *p, |
| 2761 | __isl_keep isl_local_space *ls, isl_int c, unsigned pos) |
| 2762 | { |
| 2763 | enum isl_dim_type type; |
| 2764 | |
| 2765 | if (!p || !ls) |
| 2766 | return isl_printer_free(printer: p); |
| 2767 | |
| 2768 | if (pos == 0) |
| 2769 | return isl_printer_print_isl_int(p, i: c); |
| 2770 | |
| 2771 | if (isl_int_is_one(c)) |
| 2772 | ; |
| 2773 | else if (isl_int_is_negone(c)) |
| 2774 | p = isl_printer_print_str(p, s: "-" ); |
| 2775 | else { |
| 2776 | p = isl_printer_print_isl_int(p, i: c); |
| 2777 | p = isl_printer_print_str(p, s: "*" ); |
| 2778 | } |
| 2779 | if (pos2type(space: ls->dim, type: &type, pos: &pos) < 0) |
| 2780 | return isl_printer_free(printer: p); |
| 2781 | p = print_ls_name_c(p, ls, type, pos); |
| 2782 | return p; |
| 2783 | } |
| 2784 | |
| 2785 | static __isl_give isl_printer *print_ls_partial_affine_c( |
| 2786 | __isl_take isl_printer *p, __isl_keep isl_local_space *ls, |
| 2787 | isl_int *c, unsigned len) |
| 2788 | { |
| 2789 | int i; |
| 2790 | int first; |
| 2791 | |
| 2792 | for (i = 0, first = 1; i < len; ++i) { |
| 2793 | int flip = 0; |
| 2794 | if (isl_int_is_zero(c[i])) |
| 2795 | continue; |
| 2796 | if (!first) { |
| 2797 | if (isl_int_is_neg(c[i])) { |
| 2798 | flip = 1; |
| 2799 | isl_int_neg(c[i], c[i]); |
| 2800 | p = isl_printer_print_str(p, s: " - " ); |
| 2801 | } else |
| 2802 | p = isl_printer_print_str(p, s: " + " ); |
| 2803 | } |
| 2804 | first = 0; |
| 2805 | p = print_ls_term_c(p, ls, c: c[i], pos: i); |
| 2806 | if (flip) |
| 2807 | isl_int_neg(c[i], c[i]); |
| 2808 | } |
| 2809 | if (first) |
| 2810 | p = isl_printer_print_str(p, s: "0" ); |
| 2811 | return p; |
| 2812 | } |
| 2813 | |
| 2814 | static __isl_give isl_printer *print_ls_affine_c(__isl_take isl_printer *p, |
| 2815 | __isl_keep isl_local_space *ls, isl_int *c) |
| 2816 | { |
| 2817 | isl_size total = isl_local_space_dim(ls, type: isl_dim_all); |
| 2818 | |
| 2819 | if (total < 0) |
| 2820 | return isl_printer_free(printer: p); |
| 2821 | return print_ls_partial_affine_c(p, ls, c, len: 1 + total); |
| 2822 | } |
| 2823 | |
| 2824 | static __isl_give isl_printer *print_aff_c(__isl_take isl_printer *p, |
| 2825 | __isl_keep isl_aff *aff) |
| 2826 | { |
| 2827 | isl_size total; |
| 2828 | |
| 2829 | total = isl_aff_domain_dim(aff, type: isl_dim_all); |
| 2830 | if (total < 0) |
| 2831 | return isl_printer_free(printer: p); |
| 2832 | if (!isl_int_is_one(aff->v->el[0])) |
| 2833 | p = isl_printer_print_str(p, s: "(" ); |
| 2834 | p = print_ls_partial_affine_c(p, ls: aff->ls, c: aff->v->el + 1, len: 1 + total); |
| 2835 | if (!isl_int_is_one(aff->v->el[0])) { |
| 2836 | p = isl_printer_print_str(p, s: ")/" ); |
| 2837 | p = isl_printer_print_isl_int(p, i: aff->v->el[0]); |
| 2838 | } |
| 2839 | return p; |
| 2840 | } |
| 2841 | |
| 2842 | /* In the C format, we cannot express that "pwaff" may be undefined |
| 2843 | * on parts of the domain space. We therefore assume that the expression |
| 2844 | * will only be evaluated on its definition domain and compute the gist |
| 2845 | * of each cell with respect to this domain. |
| 2846 | */ |
| 2847 | static __isl_give isl_printer *print_pw_aff_c(__isl_take isl_printer *p, |
| 2848 | __isl_keep isl_pw_aff *pwaff) |
| 2849 | { |
| 2850 | isl_set *domain; |
| 2851 | isl_ast_build *build; |
| 2852 | isl_ast_expr *expr; |
| 2853 | |
| 2854 | if (pwaff->n < 1) |
| 2855 | isl_die(p->ctx, isl_error_unsupported, |
| 2856 | "cannot print empty isl_pw_aff in C format" , |
| 2857 | return isl_printer_free(p)); |
| 2858 | |
| 2859 | domain = isl_pw_aff_domain(pwaff: isl_pw_aff_copy(pwaff)); |
| 2860 | build = isl_ast_build_from_context(set: domain); |
| 2861 | expr = isl_ast_build_expr_from_pw_aff(build, pa: isl_pw_aff_copy(pwaff)); |
| 2862 | p = isl_printer_print_ast_expr(p, expr); |
| 2863 | isl_ast_expr_free(expr); |
| 2864 | isl_ast_build_free(build); |
| 2865 | |
| 2866 | return p; |
| 2867 | } |
| 2868 | |
| 2869 | __isl_give isl_printer *isl_printer_print_aff(__isl_take isl_printer *p, |
| 2870 | __isl_keep isl_aff *aff) |
| 2871 | { |
| 2872 | if (!p || !aff) |
| 2873 | goto error; |
| 2874 | |
| 2875 | if (p->output_format == ISL_FORMAT_ISL) |
| 2876 | return print_aff_isl(p, aff); |
| 2877 | else if (p->output_format == ISL_FORMAT_C) |
| 2878 | return print_aff_c(p, aff); |
| 2879 | isl_die(p->ctx, isl_error_unsupported, "unsupported output format" , |
| 2880 | goto error); |
| 2881 | error: |
| 2882 | isl_printer_free(printer: p); |
| 2883 | return NULL; |
| 2884 | } |
| 2885 | |
| 2886 | __isl_give isl_printer *isl_printer_print_pw_aff(__isl_take isl_printer *p, |
| 2887 | __isl_keep isl_pw_aff *pwaff) |
| 2888 | { |
| 2889 | if (!p || !pwaff) |
| 2890 | goto error; |
| 2891 | |
| 2892 | if (p->output_format == ISL_FORMAT_ISL) |
| 2893 | return print_pw_aff_isl(p, pw: pwaff); |
| 2894 | else if (p->output_format == ISL_FORMAT_C) |
| 2895 | return print_pw_aff_c(p, pwaff); |
| 2896 | isl_die(p->ctx, isl_error_unsupported, "unsupported output format" , |
| 2897 | goto error); |
| 2898 | error: |
| 2899 | isl_printer_free(printer: p); |
| 2900 | return NULL; |
| 2901 | } |
| 2902 | |
| 2903 | #undef BASE |
| 2904 | #define BASE pw_aff |
| 2905 | #include "isl_union_print_templ.c" |
| 2906 | |
| 2907 | /* Print the isl_union_pw_aff "upa" to "p". |
| 2908 | * |
| 2909 | * We currently only support an isl format. |
| 2910 | */ |
| 2911 | __isl_give isl_printer *isl_printer_print_union_pw_aff( |
| 2912 | __isl_take isl_printer *p, __isl_keep isl_union_pw_aff *upa) |
| 2913 | { |
| 2914 | if (!p || !upa) |
| 2915 | return isl_printer_free(printer: p); |
| 2916 | |
| 2917 | if (p->output_format == ISL_FORMAT_ISL) |
| 2918 | return print_union_pw_aff_isl(p, u: upa); |
| 2919 | isl_die(isl_printer_get_ctx(p), isl_error_unsupported, |
| 2920 | "unsupported output format" , return isl_printer_free(p)); |
| 2921 | } |
| 2922 | |
| 2923 | /* Print dimension "pos" of data->space to "p". |
| 2924 | * |
| 2925 | * data->user is assumed to be an isl_multi_aff. |
| 2926 | * |
| 2927 | * If the current dimension is an output dimension, then print |
| 2928 | * the corresponding expression. Otherwise, print the name of the dimension. |
| 2929 | * Make sure to use the domain space for printing names as |
| 2930 | * that is the space that will be used for printing constraints (if any). |
| 2931 | */ |
| 2932 | static __isl_give isl_printer *print_dim_ma(__isl_take isl_printer *p, |
| 2933 | struct isl_print_space_data *data, unsigned pos) |
| 2934 | { |
| 2935 | isl_multi_aff *ma = data->user; |
| 2936 | isl_space *space; |
| 2937 | |
| 2938 | space = isl_multi_aff_get_domain_space(multi: ma); |
| 2939 | if (data->type == isl_dim_out) { |
| 2940 | p = print_aff_body(p, space, aff: ma->u.p[pos]); |
| 2941 | } else { |
| 2942 | enum isl_dim_type type = data->type; |
| 2943 | |
| 2944 | if (type == isl_dim_in) |
| 2945 | type = isl_dim_set; |
| 2946 | p = print_name(space, p, type, pos, latex: data->latex); |
| 2947 | } |
| 2948 | isl_space_free(space); |
| 2949 | |
| 2950 | return p; |
| 2951 | } |
| 2952 | |
| 2953 | static __isl_give isl_printer *print_body_multi_aff(__isl_take isl_printer *p, |
| 2954 | __isl_keep isl_multi_aff *maff) |
| 2955 | { |
| 2956 | struct isl_print_space_data data = { 0 }; |
| 2957 | |
| 2958 | data.print_dim = &print_dim_ma; |
| 2959 | data.user = maff; |
| 2960 | return isl_print_space(space: maff->space, p, rational: 0, data: &data); |
| 2961 | } |
| 2962 | |
| 2963 | static __isl_give isl_printer *print_multi_aff_isl(__isl_take isl_printer *p, |
| 2964 | __isl_keep isl_multi_aff *maff) |
| 2965 | { |
| 2966 | struct isl_print_space_data data = { 0 }; |
| 2967 | |
| 2968 | if (!maff) |
| 2969 | goto error; |
| 2970 | |
| 2971 | p = print_param_tuple(p, space: maff->space, data: &data); |
| 2972 | p = isl_printer_print_str(p, s: "{ " ); |
| 2973 | p = print_body_multi_aff(p, maff); |
| 2974 | p = isl_printer_print_str(p, s: " }" ); |
| 2975 | return p; |
| 2976 | error: |
| 2977 | isl_printer_free(printer: p); |
| 2978 | return NULL; |
| 2979 | } |
| 2980 | |
| 2981 | __isl_give isl_printer *isl_printer_print_multi_aff(__isl_take isl_printer *p, |
| 2982 | __isl_keep isl_multi_aff *maff) |
| 2983 | { |
| 2984 | if (!p || !maff) |
| 2985 | goto error; |
| 2986 | |
| 2987 | if (p->output_format == ISL_FORMAT_ISL) |
| 2988 | return print_multi_aff_isl(p, maff); |
| 2989 | isl_die(p->ctx, isl_error_unsupported, "unsupported output format" , |
| 2990 | goto error); |
| 2991 | error: |
| 2992 | isl_printer_free(printer: p); |
| 2993 | return NULL; |
| 2994 | } |
| 2995 | |
| 2996 | #undef BASE |
| 2997 | #define BASE multi_aff |
| 2998 | #include "isl_pw_print_templ.c" |
| 2999 | |
| 3000 | /* Print the unnamed, single-dimensional piecewise multi affine expression "pma" |
| 3001 | * to "p". |
| 3002 | */ |
| 3003 | static __isl_give isl_printer *print_unnamed_pw_multi_aff_c( |
| 3004 | __isl_take isl_printer *p, __isl_keep isl_pw_multi_aff *pma) |
| 3005 | { |
| 3006 | int i; |
| 3007 | isl_space *space; |
| 3008 | |
| 3009 | space = isl_pw_multi_aff_get_domain_space(pma); |
| 3010 | for (i = 0; i < pma->n - 1; ++i) { |
| 3011 | p = isl_printer_print_str(p, s: "(" ); |
| 3012 | p = print_set_c(p, space, set: pma->p[i].set); |
| 3013 | p = isl_printer_print_str(p, s: ") ? (" ); |
| 3014 | p = print_aff_c(p, aff: pma->p[i].maff->u.p[0]); |
| 3015 | p = isl_printer_print_str(p, s: ") : " ); |
| 3016 | } |
| 3017 | isl_space_free(space); |
| 3018 | |
| 3019 | return print_aff_c(p, aff: pma->p[pma->n - 1].maff->u.p[0]); |
| 3020 | } |
| 3021 | |
| 3022 | static __isl_give isl_printer *print_pw_multi_aff_c(__isl_take isl_printer *p, |
| 3023 | __isl_keep isl_pw_multi_aff *pma) |
| 3024 | { |
| 3025 | isl_size n; |
| 3026 | const char *name; |
| 3027 | |
| 3028 | if (!pma) |
| 3029 | goto error; |
| 3030 | if (pma->n < 1) |
| 3031 | isl_die(p->ctx, isl_error_unsupported, |
| 3032 | "cannot print empty isl_pw_multi_aff in C format" , |
| 3033 | goto error); |
| 3034 | n = isl_pw_multi_aff_dim(pma, type: isl_dim_out); |
| 3035 | if (n < 0) |
| 3036 | return isl_printer_free(printer: p); |
| 3037 | name = isl_pw_multi_aff_get_tuple_name(pma, type: isl_dim_out); |
| 3038 | if (!name && n == 1) |
| 3039 | return print_unnamed_pw_multi_aff_c(p, pma); |
| 3040 | if (!name) |
| 3041 | isl_die(p->ctx, isl_error_unsupported, |
| 3042 | "cannot print unnamed isl_pw_multi_aff in C format" , |
| 3043 | goto error); |
| 3044 | |
| 3045 | p = isl_printer_print_str(p, s: name); |
| 3046 | if (n != 0) |
| 3047 | isl_die(p->ctx, isl_error_unsupported, |
| 3048 | "not supported yet" , goto error); |
| 3049 | |
| 3050 | return p; |
| 3051 | error: |
| 3052 | isl_printer_free(printer: p); |
| 3053 | return NULL; |
| 3054 | } |
| 3055 | |
| 3056 | __isl_give isl_printer *isl_printer_print_pw_multi_aff( |
| 3057 | __isl_take isl_printer *p, __isl_keep isl_pw_multi_aff *pma) |
| 3058 | { |
| 3059 | if (!p || !pma) |
| 3060 | goto error; |
| 3061 | |
| 3062 | if (p->output_format == ISL_FORMAT_ISL) |
| 3063 | return print_pw_multi_aff_isl(p, pw: pma); |
| 3064 | if (p->output_format == ISL_FORMAT_C) |
| 3065 | return print_pw_multi_aff_c(p, pma); |
| 3066 | isl_die(p->ctx, isl_error_unsupported, "unsupported output format" , |
| 3067 | goto error); |
| 3068 | error: |
| 3069 | isl_printer_free(printer: p); |
| 3070 | return NULL; |
| 3071 | } |
| 3072 | |
| 3073 | #undef BASE |
| 3074 | #define BASE pw_multi_aff |
| 3075 | #include "isl_union_print_templ.c" |
| 3076 | |
| 3077 | __isl_give isl_printer *isl_printer_print_union_pw_multi_aff( |
| 3078 | __isl_take isl_printer *p, __isl_keep isl_union_pw_multi_aff *upma) |
| 3079 | { |
| 3080 | if (!p || !upma) |
| 3081 | goto error; |
| 3082 | |
| 3083 | if (p->output_format == ISL_FORMAT_ISL) |
| 3084 | return print_union_pw_multi_aff_isl(p, u: upma); |
| 3085 | isl_die(p->ctx, isl_error_unsupported, "unsupported output format" , |
| 3086 | goto error); |
| 3087 | error: |
| 3088 | isl_printer_free(printer: p); |
| 3089 | return NULL; |
| 3090 | } |
| 3091 | |
| 3092 | /* Print dimension "pos" of data->space to "p". |
| 3093 | * |
| 3094 | * data->user is assumed to be an isl_multi_pw_aff. |
| 3095 | * |
| 3096 | * If the current dimension is an output dimension, then print |
| 3097 | * the corresponding piecewise affine expression. |
| 3098 | * Otherwise, print the name of the dimension. |
| 3099 | * Make sure to use the same space in both cases. |
| 3100 | * In particular, use the domain space for printing names as |
| 3101 | * that is the space that is used for printing constraints. |
| 3102 | */ |
| 3103 | static __isl_give isl_printer *print_dim_mpa(__isl_take isl_printer *p, |
| 3104 | struct isl_print_space_data *data, unsigned pos) |
| 3105 | { |
| 3106 | int i; |
| 3107 | int need_parens; |
| 3108 | isl_space *space; |
| 3109 | isl_multi_pw_aff *mpa = data->user; |
| 3110 | isl_pw_aff *pa; |
| 3111 | |
| 3112 | if (data->type != isl_dim_out) { |
| 3113 | enum isl_dim_type type = data->type; |
| 3114 | |
| 3115 | if (type == isl_dim_in) |
| 3116 | type = isl_dim_set; |
| 3117 | space = isl_multi_pw_aff_get_domain_space(multi: mpa); |
| 3118 | p = print_name(space, p, type, pos, latex: data->latex); |
| 3119 | isl_space_free(space); |
| 3120 | return p; |
| 3121 | } |
| 3122 | |
| 3123 | pa = mpa->u.p[pos]; |
| 3124 | if (pa->n == 0) |
| 3125 | return isl_printer_print_str(p, s: "(0 : false)" ); |
| 3126 | |
| 3127 | need_parens = pa->n != 1 || !isl_set_plain_is_universe(set: pa->p[0].set); |
| 3128 | if (need_parens) |
| 3129 | p = isl_printer_print_str(p, s: "(" ); |
| 3130 | space = isl_multi_pw_aff_get_domain_space(multi: mpa); |
| 3131 | for (i = 0; i < pa->n; ++i) { |
| 3132 | |
| 3133 | if (i) |
| 3134 | p = isl_printer_print_str(p, s: "; " ); |
| 3135 | p = print_aff_body(p, space, aff: pa->p[i].aff); |
| 3136 | p = print_disjuncts(map: pa->p[i].set, space, p, latex: 0); |
| 3137 | } |
| 3138 | isl_space_free(space); |
| 3139 | if (need_parens) |
| 3140 | p = isl_printer_print_str(p, s: ")" ); |
| 3141 | |
| 3142 | return p; |
| 3143 | } |
| 3144 | |
| 3145 | /* Print "mpa" to "p" in isl format. |
| 3146 | * |
| 3147 | * If "mpa" is zero-dimensional and has a non-trivial explicit domain, |
| 3148 | * then it is printed after the tuple of affine expressions. |
| 3149 | */ |
| 3150 | static __isl_give isl_printer *print_multi_pw_aff_isl(__isl_take isl_printer *p, |
| 3151 | __isl_keep isl_multi_pw_aff *mpa) |
| 3152 | { |
| 3153 | struct isl_print_space_data data = { 0 }; |
| 3154 | isl_bool has_domain; |
| 3155 | |
| 3156 | if (!mpa) |
| 3157 | return isl_printer_free(printer: p); |
| 3158 | |
| 3159 | p = print_param_tuple(p, space: mpa->space, data: &data); |
| 3160 | p = isl_printer_print_str(p, s: "{ " ); |
| 3161 | data.print_dim = &print_dim_mpa; |
| 3162 | data.user = mpa; |
| 3163 | p = isl_print_space(space: mpa->space, p, rational: 0, data: &data); |
| 3164 | has_domain = isl_multi_pw_aff_has_non_trivial_domain(multi: mpa); |
| 3165 | if (has_domain < 0) |
| 3166 | return isl_printer_free(printer: p); |
| 3167 | if (has_domain) { |
| 3168 | isl_space *space; |
| 3169 | |
| 3170 | space = isl_space_domain(space: isl_space_copy(space: mpa->space)); |
| 3171 | p = print_disjuncts_set(set: mpa->u.dom, space, p, latex: 0); |
| 3172 | isl_space_free(space); |
| 3173 | } |
| 3174 | p = isl_printer_print_str(p, s: " }" ); |
| 3175 | return p; |
| 3176 | } |
| 3177 | |
| 3178 | __isl_give isl_printer *isl_printer_print_multi_pw_aff( |
| 3179 | __isl_take isl_printer *p, __isl_keep isl_multi_pw_aff *mpa) |
| 3180 | { |
| 3181 | if (!p || !mpa) |
| 3182 | return isl_printer_free(printer: p); |
| 3183 | |
| 3184 | if (p->output_format == ISL_FORMAT_ISL) |
| 3185 | return print_multi_pw_aff_isl(p, mpa); |
| 3186 | isl_die(p->ctx, isl_error_unsupported, "unsupported output format" , |
| 3187 | return isl_printer_free(p)); |
| 3188 | } |
| 3189 | |
| 3190 | /* Print dimension "pos" of data->space to "p". |
| 3191 | * |
| 3192 | * data->user is assumed to be an isl_multi_val. |
| 3193 | * |
| 3194 | * If the current dimension is an output dimension, then print |
| 3195 | * the corresponding value. Otherwise, print the name of the dimension. |
| 3196 | */ |
| 3197 | static __isl_give isl_printer *print_dim_mv(__isl_take isl_printer *p, |
| 3198 | struct isl_print_space_data *data, unsigned pos) |
| 3199 | { |
| 3200 | isl_multi_val *mv = data->user; |
| 3201 | |
| 3202 | if (data->type == isl_dim_out) |
| 3203 | return isl_printer_print_val(p, v: mv->u.p[pos]); |
| 3204 | else |
| 3205 | return print_name(space: data->space, p, type: data->type, pos, latex: data->latex); |
| 3206 | } |
| 3207 | |
| 3208 | /* Print the isl_multi_val "mv" to "p" in isl format. |
| 3209 | */ |
| 3210 | static __isl_give isl_printer *print_multi_val_isl(__isl_take isl_printer *p, |
| 3211 | __isl_keep isl_multi_val *mv) |
| 3212 | { |
| 3213 | struct isl_print_space_data data = { 0 }; |
| 3214 | |
| 3215 | if (!mv) |
| 3216 | return isl_printer_free(printer: p); |
| 3217 | |
| 3218 | p = print_param_tuple(p, space: mv->space, data: &data); |
| 3219 | p = isl_printer_print_str(p, s: "{ " ); |
| 3220 | data.print_dim = &print_dim_mv; |
| 3221 | data.user = mv; |
| 3222 | p = isl_print_space(space: mv->space, p, rational: 0, data: &data); |
| 3223 | p = isl_printer_print_str(p, s: " }" ); |
| 3224 | return p; |
| 3225 | } |
| 3226 | |
| 3227 | /* Print the isl_multi_val "mv" to "p". |
| 3228 | * |
| 3229 | * Currently only supported in isl format. |
| 3230 | */ |
| 3231 | __isl_give isl_printer *isl_printer_print_multi_val( |
| 3232 | __isl_take isl_printer *p, __isl_keep isl_multi_val *mv) |
| 3233 | { |
| 3234 | if (!p || !mv) |
| 3235 | return isl_printer_free(printer: p); |
| 3236 | |
| 3237 | if (p->output_format == ISL_FORMAT_ISL) |
| 3238 | return print_multi_val_isl(p, mv); |
| 3239 | isl_die(p->ctx, isl_error_unsupported, "unsupported output format" , |
| 3240 | return isl_printer_free(p)); |
| 3241 | } |
| 3242 | |
| 3243 | /* Print dimension "pos" of data->space to "p". |
| 3244 | * |
| 3245 | * data->user is assumed to be an isl_multi_id. |
| 3246 | * |
| 3247 | * If the current dimension is an output dimension, then print |
| 3248 | * the corresponding identifier. Otherwise, print the name of the dimension. |
| 3249 | */ |
| 3250 | static __isl_give isl_printer *print_dim_mi(__isl_take isl_printer *p, |
| 3251 | struct isl_print_space_data *data, unsigned pos) |
| 3252 | { |
| 3253 | isl_multi_id *mi = data->user; |
| 3254 | |
| 3255 | if (data->type == isl_dim_out) |
| 3256 | return isl_printer_print_id(p, id: mi->u.p[pos]); |
| 3257 | else |
| 3258 | return print_name(space: data->space, p, type: data->type, pos, latex: data->latex); |
| 3259 | } |
| 3260 | |
| 3261 | /* Print the isl_multi_id "mi" to "p" in isl format. |
| 3262 | */ |
| 3263 | static __isl_give isl_printer *print_multi_id_isl(__isl_take isl_printer *p, |
| 3264 | __isl_keep isl_multi_id *mi) |
| 3265 | { |
| 3266 | isl_space *space; |
| 3267 | struct isl_print_space_data data = { 0 }; |
| 3268 | |
| 3269 | space = isl_multi_id_peek_space(multi: mi); |
| 3270 | p = print_param_tuple(p, space, data: &data); |
| 3271 | p = isl_printer_print_str(p, s: "{ " ); |
| 3272 | data.print_dim = &print_dim_mi; |
| 3273 | data.user = mi; |
| 3274 | p = isl_print_space(space, p, rational: 0, data: &data); |
| 3275 | p = isl_printer_print_str(p, s: " }" ); |
| 3276 | return p; |
| 3277 | } |
| 3278 | |
| 3279 | /* Print the isl_multi_id "mi" to "p". |
| 3280 | * |
| 3281 | * Currently only supported in isl format. |
| 3282 | */ |
| 3283 | __isl_give isl_printer *isl_printer_print_multi_id( |
| 3284 | __isl_take isl_printer *p, __isl_keep isl_multi_id *mi) |
| 3285 | { |
| 3286 | if (!p || !mi) |
| 3287 | return isl_printer_free(printer: p); |
| 3288 | |
| 3289 | if (p->output_format == ISL_FORMAT_ISL) |
| 3290 | return print_multi_id_isl(p, mi); |
| 3291 | isl_die(isl_printer_get_ctx(p), isl_error_unsupported, |
| 3292 | "unsupported output format" , return isl_printer_free(p)); |
| 3293 | } |
| 3294 | |
| 3295 | /* Print dimension "pos" of data->space to "p". |
| 3296 | * |
| 3297 | * data->user is assumed to be an isl_multi_union_pw_aff. |
| 3298 | * |
| 3299 | * The current dimension is necessarily a set dimension, so |
| 3300 | * we print the corresponding isl_union_pw_aff, including |
| 3301 | * the braces. |
| 3302 | */ |
| 3303 | static __isl_give isl_printer *print_union_pw_aff_dim(__isl_take isl_printer *p, |
| 3304 | struct isl_print_space_data *data, unsigned pos) |
| 3305 | { |
| 3306 | isl_multi_union_pw_aff *mupa = data->user; |
| 3307 | isl_union_pw_aff *upa; |
| 3308 | |
| 3309 | upa = isl_multi_union_pw_aff_get_union_pw_aff(multi: mupa, pos); |
| 3310 | p = print_body_union_pw_aff(p, u: upa); |
| 3311 | isl_union_pw_aff_free(upa); |
| 3312 | |
| 3313 | return p; |
| 3314 | } |
| 3315 | |
| 3316 | /* Print the isl_multi_union_pw_aff "mupa" to "p" in isl format. |
| 3317 | * |
| 3318 | * If "mupa" is zero-dimensional and has a non-trivial explicit domain, |
| 3319 | * then it is printed after the tuple of affine expressions. |
| 3320 | * In order to clarify that this domain belongs to the expression, |
| 3321 | * the tuple along with the domain are placed inside parentheses. |
| 3322 | * If "mupa" has any parameters, then the opening parenthesis |
| 3323 | * appears after the parameter declarations. |
| 3324 | */ |
| 3325 | static __isl_give isl_printer *print_multi_union_pw_aff_isl( |
| 3326 | __isl_take isl_printer *p, __isl_keep isl_multi_union_pw_aff *mupa) |
| 3327 | { |
| 3328 | struct isl_print_space_data data = { 0 }; |
| 3329 | isl_bool has_domain; |
| 3330 | isl_space *space; |
| 3331 | |
| 3332 | if (!mupa) |
| 3333 | return isl_printer_free(printer: p); |
| 3334 | has_domain = isl_multi_union_pw_aff_has_non_trivial_domain(multi: mupa); |
| 3335 | if (has_domain < 0) |
| 3336 | return isl_printer_free(printer: p); |
| 3337 | |
| 3338 | space = isl_multi_union_pw_aff_get_space(multi: mupa); |
| 3339 | p = print_param_tuple(p, space, data: &data); |
| 3340 | |
| 3341 | if (has_domain) |
| 3342 | p = isl_printer_print_str(p, s: "(" ); |
| 3343 | |
| 3344 | data.print_dim = &print_union_pw_aff_dim; |
| 3345 | data.user = mupa; |
| 3346 | |
| 3347 | p = isl_print_space(space, p, rational: 0, data: &data); |
| 3348 | isl_space_free(space); |
| 3349 | |
| 3350 | if (has_domain) { |
| 3351 | p = isl_printer_print_str(p, s: " : " ); |
| 3352 | p = isl_printer_print_union_set_isl_body(p, uset: mupa->u.dom); |
| 3353 | p = isl_printer_print_str(p, s: ")" ); |
| 3354 | } |
| 3355 | |
| 3356 | return p; |
| 3357 | } |
| 3358 | |
| 3359 | /* Print the isl_multi_union_pw_aff "mupa" to "p" in isl format. |
| 3360 | * |
| 3361 | * We currently only support an isl format. |
| 3362 | */ |
| 3363 | __isl_give isl_printer *isl_printer_print_multi_union_pw_aff( |
| 3364 | __isl_take isl_printer *p, __isl_keep isl_multi_union_pw_aff *mupa) |
| 3365 | { |
| 3366 | if (!p || !mupa) |
| 3367 | return isl_printer_free(printer: p); |
| 3368 | |
| 3369 | if (p->output_format == ISL_FORMAT_ISL) |
| 3370 | return print_multi_union_pw_aff_isl(p, mupa); |
| 3371 | isl_die(isl_printer_get_ctx(p), isl_error_unsupported, |
| 3372 | "unsupported output format" , return isl_printer_free(p)); |
| 3373 | } |
| 3374 | |