+/* Check if basic map "i" contains the basic map represented
+ * by the tableau "tab".
+ */
+static int contains(struct isl_map *map, int i, int *ineq_i,
+ struct isl_tab *tab)
+{
+ int k, l;
+ unsigned dim;
+
+ dim = isl_basic_map_total_dim(map->p[i]);
+ for (k = 0; k < map->p[i]->n_eq; ++k) {
+ for (l = 0; l < 2; ++l) {
+ int stat;
+ isl_seq_neg(map->p[i]->eq[k], map->p[i]->eq[k], 1+dim);
+ stat = status_in(map->p[i]->eq[k], tab);
+ if (stat != STATUS_VALID)
+ return 0;
+ }
+ }
+
+ for (k = 0; k < map->p[i]->n_ineq; ++k) {
+ int stat;
+ if (ineq_i[k] == STATUS_REDUNDANT)
+ continue;
+ stat = status_in(map->p[i]->ineq[k], tab);
+ if (stat != STATUS_VALID)
+ return 0;
+ }
+ return 1;
+}
+
+/* Basic map "i" has an inequality (say "k") that is adjacent
+ * to some inequality of basic map "j". All the other inequalities
+ * are valid for "j".
+ * Check if basic map "j" forms an extension of basic map "i".
+ *
+ * Note that this function is only called if some of the equalities or
+ * inequalities of basic map "j" do cut basic map "i". The function is
+ * correct even if there are no such cut constraints, but in that case
+ * the additional checks performed by this function are overkill.
+ *
+ * In particular, we replace constraint k, say f >= 0, by constraint
+ * f <= -1, add the inequalities of "j" that are valid for "i"
+ * and check if the result is a subset of basic map "j".
+ * If so, then we know that this result is exactly equal to basic map "j"
+ * since all its constraints are valid for basic map "j".
+ * By combining the valid constraints of "i" (all equalities and all
+ * inequalities except "k") and the valid constraints of "j" we therefore
+ * obtain a basic map that is equal to their union.
+ * In this case, there is no need to perform a rollback of the tableau
+ * since it is going to be destroyed in fuse().
+ *
+ *
+ * |\__ |\__
+ * | \__ | \__
+ * | \_ => | \__
+ * |_______| _ |_________\
+ *
+ *
+ * |\ |\
+ * | \ | \
+ * | \ | \
+ * | | | \
+ * | ||\ => | \
+ * | || \ | \
+ * | || | | |
+ * |__||_/ |_____/
+ */
+static int is_adj_ineq_extension(__isl_keep isl_map *map, int i, int j,
+ struct isl_tab **tabs, int *eq_i, int *ineq_i, int *eq_j, int *ineq_j)
+{
+ int k;
+ struct isl_tab_undo *snap;
+ unsigned n_eq = map->p[i]->n_eq;
+ unsigned total = isl_basic_map_total_dim(map->p[i]);
+ int r;
+
+ if (isl_tab_extend_cons(tabs[i], 1 + map->p[j]->n_ineq) < 0)
+ return -1;
+
+ for (k = 0; k < map->p[i]->n_ineq; ++k)
+ if (ineq_i[k] == STATUS_ADJ_INEQ)
+ break;
+ if (k >= map->p[i]->n_ineq)
+ isl_die(isl_map_get_ctx(map), isl_error_internal,
+ "ineq_i should have exactly one STATUS_ADJ_INEQ",
+ return -1);
+
+ snap = isl_tab_snap(tabs[i]);
+
+ if (isl_tab_unrestrict(tabs[i], n_eq + k) < 0)
+ return -1;
+
+ isl_seq_neg(map->p[i]->ineq[k], map->p[i]->ineq[k], 1 + total);
+ isl_int_sub_ui(map->p[i]->ineq[k][0], map->p[i]->ineq[k][0], 1);
+ r = isl_tab_add_ineq(tabs[i], map->p[i]->ineq[k]);
+ isl_seq_neg(map->p[i]->ineq[k], map->p[i]->ineq[k], 1 + total);
+ isl_int_sub_ui(map->p[i]->ineq[k][0], map->p[i]->ineq[k][0], 1);
+ if (r < 0)
+ return -1;
+
+ for (k = 0; k < map->p[j]->n_ineq; ++k) {
+ if (ineq_j[k] != STATUS_VALID)
+ continue;
+ if (isl_tab_add_ineq(tabs[i], map->p[j]->ineq[k]) < 0)
+ return -1;
+ }
+
+ if (contains(map, j, ineq_j, tabs[i]))
+ return fuse(map, i, j, tabs, eq_i, ineq_i, eq_j, ineq_j, NULL);
+
+ if (isl_tab_rollback(tabs[i], snap) < 0)
+ return -1;
+
+ return 0;
+}
+
+