+struct isl_aff_split {
+ isl_basic_map *aff;
+ isl_map *map;
+};
+
+static void free_split(__isl_take struct isl_aff_split *split, int n)
+{
+ int i;
+
+ if (!split)
+ return;
+
+ for (i = 0; i < n; ++i) {
+ isl_basic_map_free(split[i].aff);
+ isl_map_free(split[i].map);
+ }
+
+ free(split);
+}
+
+static __isl_give isl_basic_map *get_aff(__isl_take isl_basic_map *bmap)
+{
+ int i, j;
+ unsigned nparam, n_in, n_out, total;
+
+ bmap = isl_basic_map_cow(bmap);
+ if (!bmap)
+ return NULL;
+ if (isl_basic_map_free_inequality(bmap, bmap->n_ineq) < 0)
+ goto error;
+
+ nparam = isl_basic_map_dim(bmap, isl_dim_param);
+ n_in = isl_basic_map_dim(bmap, isl_dim_in);
+ n_out = isl_basic_map_dim(bmap, isl_dim_out);
+ total = isl_basic_map_dim(bmap, isl_dim_all);
+ for (i = bmap->n_eq - 1; i >= 0; --i) {
+ j = isl_seq_last_non_zero(bmap->eq[i] + 1, total);
+ if (j >= nparam && j < nparam + n_in + n_out &&
+ (isl_int_is_one(bmap->eq[i][1 + j]) ||
+ isl_int_is_negone(bmap->eq[i][1 + j])))
+ continue;
+ if (isl_basic_map_drop_equality(bmap, i) < 0)
+ goto error;
+ }
+
+ bmap = isl_basic_map_finalize(bmap);
+
+ return bmap;
+error:
+ isl_basic_map_free(bmap);
+ return NULL;
+}
+
+static int aff_split_cmp(const void *p1, const void *p2)
+{
+ const struct isl_aff_split *s1, *s2;
+ s1 = (const struct isl_aff_split *) p1;
+ s2 = (const struct isl_aff_split *) p2;
+
+ return isl_basic_map_fast_cmp(s1->aff, s2->aff);
+}
+
+static __isl_give isl_basic_map *drop_aff(__isl_take isl_basic_map *bmap,
+ __isl_keep isl_basic_map *aff)
+{
+ int i, j;
+ unsigned total;
+
+ if (!bmap || !aff)
+ goto error;
+
+ total = isl_dim_total(bmap->dim);
+
+ for (i = bmap->n_eq - 1; i >= 0; --i) {
+ if (isl_seq_first_non_zero(bmap->eq[i] + 1 + total,
+ bmap->n_div) != -1)
+ continue;
+ for (j = 0; j < aff->n_eq; ++j) {
+ if (!isl_seq_eq(bmap->eq[i], aff->eq[j], 1 + total) &&
+ !isl_seq_is_neg(bmap->eq[i], aff->eq[j], 1 + total))
+ continue;
+ if (isl_basic_map_drop_equality(bmap, i) < 0)
+ goto error;
+ break;
+ }
+ }
+
+ return bmap;
+error:
+ isl_basic_map_free(bmap);
+ return NULL;
+}
+
+static __isl_give struct isl_aff_split *split_aff(__isl_keep isl_map *map)
+{
+ int i, n;
+ struct isl_aff_split *split;
+
+ split = isl_calloc_array(map->isl, struct isl_aff_split, map->n);
+ if (!split)
+ return NULL;
+
+ for (i = 0; i < map->n; ++i) {
+ isl_basic_map *bmap;
+ split[i].aff = get_aff(isl_basic_map_copy(map->p[i]));
+ bmap = isl_basic_map_copy(map->p[i]);
+ bmap = isl_basic_map_cow(bmap);
+ bmap = drop_aff(bmap, split[i].aff);
+ split[i].map = isl_map_from_basic_map(bmap);
+ if (!split[i].aff || !split[i].map)
+ goto error;
+ }
+
+ qsort(split, map->n, sizeof(struct isl_aff_split), &aff_split_cmp);
+
+ n = map->n;
+ for (i = n - 1; i >= 1; --i) {
+ if (!isl_basic_map_fast_is_equal(split[i - 1].aff,
+ split[i].aff))
+ continue;
+ isl_basic_map_free(split[i].aff);
+ split[i - 1].map = isl_map_union(split[i - 1].map,
+ split[i].map);
+ if (i != n - 1)
+ split[i] = split[n - 1];
+ split[n - 1].aff = NULL;
+ split[n - 1].map = NULL;
+ --n;
+ }
+
+ return split;
+error:
+ free_split(split, map->n);
+ return NULL;
+}
+
+static __isl_give isl_printer *print_split_map(__isl_take isl_printer *p,
+ struct isl_aff_split *split, int n, int set)
+{
+ int i;
+
+ for (i = 0; i < n; ++i) {
+ isl_dim *dim;
+
+ if (!split[i].map)
+ break;
+ dim = split[i].map->dim;
+ if (i)
+ p = isl_printer_print_str(p, "; ");
+ if (set)
+ p = print_tuple(dim, p, isl_dim_set, 1, 0, split[i].aff);
+ else {
+ p = print_tuple(dim, p, isl_dim_in, 0, 0, split[i].aff);
+ p = isl_printer_print_str(p, s_to[0]);
+ p = print_tuple(dim, p, isl_dim_out, 0, 0, split[i].aff);
+ }
+ p = print_disjuncts(split[i].map, p, set, 0);
+ }
+
+ return p;
+}
+