isl_basic_map_range_product: check that parameters match
[platform/upstream/isl.git] / isl_map.c
index 14732c3..e68b192 100644 (file)
--- a/isl_map.c
+++ b/isl_map.c
@@ -1,6 +1,7 @@
 /*
  * Copyright 2008-2009 Katholieke Universiteit Leuven
  * Copyright 2010      INRIA Saclay
+ * Copyright 2012      Ecole Normale Superieure
  *
  * Use of this software is governed by the GNU LGPLv2.1 license
  *
@@ -8,13 +9,14 @@
  * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
  * and INRIA Saclay - Ile-de-France, Parc Club Orsay Universite,
  * ZAC des vignes, 4 rue Jacques Monod, 91893 Orsay, France 
+ * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
  */
 
 #include <string.h>
 #include <isl_ctx_private.h>
 #include <isl_map_private.h>
 #include <isl/blk.h>
-#include "isl_dim_private.h"
+#include "isl_space_private.h"
 #include "isl_equalities.h"
 #include <isl_list_private.h>
 #include <isl/lp.h>
@@ -30,8 +32,9 @@
 #include <isl_dim_map.h>
 #include <isl_local_space_private.h>
 #include <isl_aff_private.h>
+#include <isl_options_private.h>
 
-static unsigned n(struct isl_dim *dim, enum isl_dim_type type)
+static unsigned n(__isl_keep isl_space *dim, enum isl_dim_type type)
 {
        switch (type) {
        case isl_dim_param:     return dim->nparam;
@@ -42,7 +45,7 @@ static unsigned n(struct isl_dim *dim, enum isl_dim_type type)
        }
 }
 
-static unsigned pos(struct isl_dim *dim, enum isl_dim_type type)
+static unsigned pos(__isl_keep isl_space *dim, enum isl_dim_type type)
 {
        switch (type) {
        case isl_dim_param:     return 1;
@@ -61,7 +64,7 @@ unsigned isl_basic_map_dim(__isl_keep isl_basic_map *bmap,
        case isl_dim_cst:       return 1;
        case isl_dim_param:
        case isl_dim_in:
-       case isl_dim_out:       return isl_dim_size(bmap->dim, type);
+       case isl_dim_out:       return isl_space_dim(bmap->dim, type);
        case isl_dim_div:       return bmap->n_div;
        case isl_dim_all:       return isl_basic_map_total_dim(bmap);
        default:                return 0;
@@ -81,7 +84,7 @@ unsigned isl_set_dim(__isl_keep isl_set *set, enum isl_dim_type type)
 unsigned isl_basic_map_offset(struct isl_basic_map *bmap,
                                        enum isl_dim_type type)
 {
-       struct isl_dim *dim = bmap->dim;
+       isl_space *dim = bmap->dim;
        switch (type) {
        case isl_dim_cst:       return 0;
        case isl_dim_param:     return 1;
@@ -121,7 +124,9 @@ unsigned isl_basic_set_n_param(__isl_keep isl_basic_set *bset)
 
 unsigned isl_basic_set_total_dim(const struct isl_basic_set *bset)
 {
-       return isl_dim_total(bset->dim) + bset->n_div;
+       if (!bset)
+               return 0;
+       return isl_space_dim(bset->dim, isl_dim_all) + bset->n_div;
 }
 
 unsigned isl_set_n_dim(__isl_keep isl_set *set)
@@ -156,7 +161,7 @@ unsigned isl_basic_map_n_div(const struct isl_basic_map *bmap)
 
 unsigned isl_basic_map_total_dim(const struct isl_basic_map *bmap)
 {
-       return bmap ? isl_dim_total(bmap->dim) + bmap->n_div : 0;
+       return bmap ? isl_space_dim(bmap->dim, isl_dim_all) + bmap->n_div : 0;
 }
 
 unsigned isl_map_n_in(const struct isl_map *map)
@@ -179,10 +184,10 @@ int isl_map_compatible_domain(struct isl_map *map, struct isl_set *set)
        int m;
        if (!map || !set)
                return -1;
-       m = isl_dim_match(map->dim, isl_dim_param, set->dim, isl_dim_param);
+       m = isl_space_match(map->dim, isl_dim_param, set->dim, isl_dim_param);
        if (m < 0 || !m)
                return m;
-       return isl_dim_tuple_match(map->dim, isl_dim_in, set->dim, isl_dim_set);
+       return isl_space_tuple_match(map->dim, isl_dim_in, set->dim, isl_dim_set);
 }
 
 int isl_basic_map_compatible_domain(struct isl_basic_map *bmap,
@@ -191,10 +196,10 @@ int isl_basic_map_compatible_domain(struct isl_basic_map *bmap,
        int m;
        if (!bmap || !bset)
                return -1;
-       m = isl_dim_match(bmap->dim, isl_dim_param, bset->dim, isl_dim_param);
+       m = isl_space_match(bmap->dim, isl_dim_param, bset->dim, isl_dim_param);
        if (m < 0 || !m)
                return m;
-       return isl_dim_tuple_match(bmap->dim, isl_dim_in, bset->dim, isl_dim_set);
+       return isl_space_tuple_match(bmap->dim, isl_dim_in, bset->dim, isl_dim_set);
 }
 
 int isl_map_compatible_range(__isl_keep isl_map *map, __isl_keep isl_set *set)
@@ -202,10 +207,10 @@ int isl_map_compatible_range(__isl_keep isl_map *map, __isl_keep isl_set *set)
        int m;
        if (!map || !set)
                return -1;
-       m = isl_dim_match(map->dim, isl_dim_param, set->dim, isl_dim_param);
+       m = isl_space_match(map->dim, isl_dim_param, set->dim, isl_dim_param);
        if (m < 0 || !m)
                return m;
-       return isl_dim_tuple_match(map->dim, isl_dim_out, set->dim, isl_dim_set);
+       return isl_space_tuple_match(map->dim, isl_dim_out, set->dim, isl_dim_set);
 }
 
 int isl_basic_map_compatible_range(struct isl_basic_map *bmap,
@@ -214,10 +219,10 @@ int isl_basic_map_compatible_range(struct isl_basic_map *bmap,
        int m;
        if (!bmap || !bset)
                return -1;
-       m = isl_dim_match(bmap->dim, isl_dim_param, bset->dim, isl_dim_param);
+       m = isl_space_match(bmap->dim, isl_dim_param, bset->dim, isl_dim_param);
        if (m < 0 || !m)
                return m;
-       return isl_dim_tuple_match(bmap->dim, isl_dim_out, bset->dim, isl_dim_set);
+       return isl_space_tuple_match(bmap->dim, isl_dim_out, bset->dim, isl_dim_set);
 }
 
 isl_ctx *isl_basic_map_get_ctx(__isl_keep isl_basic_map *bmap)
@@ -240,39 +245,56 @@ isl_ctx *isl_set_get_ctx(__isl_keep isl_set *set)
        return set ? set->ctx : NULL;
 }
 
-struct isl_dim *isl_basic_map_get_dim(struct isl_basic_map *bmap)
+__isl_give isl_space *isl_basic_map_get_space(__isl_keep isl_basic_map *bmap)
 {
        if (!bmap)
                return NULL;
-       return isl_dim_copy(bmap->dim);
+       return isl_space_copy(bmap->dim);
 }
 
-struct isl_dim *isl_basic_set_get_dim(struct isl_basic_set *bset)
+__isl_give isl_space *isl_basic_set_get_space(__isl_keep isl_basic_set *bset)
 {
        if (!bset)
                return NULL;
-       return isl_dim_copy(bset->dim);
+       return isl_space_copy(bset->dim);
 }
 
-__isl_give isl_local_space *isl_basic_map_get_local_space(
-       __isl_keep isl_basic_map *bmap)
+/* Extract the divs in "bmap" as a matrix.
+ */
+__isl_give isl_mat *isl_basic_map_get_divs(__isl_keep isl_basic_map *bmap)
 {
        int i;
-       isl_local_space *ls;
+       isl_ctx *ctx;
+       isl_mat *div;
        unsigned total;
+       unsigned cols;
 
        if (!bmap)
                return NULL;
 
-       total = isl_basic_map_total_dim(bmap);
-       ls = isl_local_space_alloc(isl_dim_copy(bmap->dim), bmap->n_div);
-       if (!ls)
+       ctx = isl_basic_map_get_ctx(bmap);
+       total = isl_space_dim(bmap->dim, isl_dim_all);
+       cols = 1 + 1 + total + bmap->n_div;
+       div = isl_mat_alloc(ctx, bmap->n_div, cols);
+       if (!div)
                return NULL;
 
        for (i = 0; i < bmap->n_div; ++i)
-               isl_seq_cpy(ls->div->row[i], bmap->div[i], 2 + total);
+               isl_seq_cpy(div->row[i], bmap->div[i], cols);
+
+       return div;
+}
+
+__isl_give isl_local_space *isl_basic_map_get_local_space(
+       __isl_keep isl_basic_map *bmap)
+{
+       isl_mat *div;
+
+       if (!bmap)
+               return NULL;
 
-       return ls;
+       div = isl_basic_map_get_divs(bmap);
+       return isl_local_space_alloc_div(isl_space_copy(bmap->dim), div);
 }
 
 __isl_give isl_local_space *isl_basic_set_get_local_space(
@@ -292,7 +314,7 @@ __isl_give isl_basic_map *isl_basic_map_from_local_space(
                return NULL;
 
        n_div = isl_local_space_dim(ls, isl_dim_div);
-       bmap = isl_basic_map_alloc_dim(isl_local_space_get_dim(ls),
+       bmap = isl_basic_map_alloc_space(isl_local_space_get_space(ls),
                                        n_div, 0, 2 * n_div);
 
        for (i = 0; i < n_div; ++i)
@@ -319,18 +341,18 @@ __isl_give isl_basic_set *isl_basic_set_from_local_space(
        return isl_basic_map_from_local_space(ls);
 }
 
-struct isl_dim *isl_map_get_dim(struct isl_map *map)
+__isl_give isl_space *isl_map_get_space(__isl_keep isl_map *map)
 {
        if (!map)
                return NULL;
-       return isl_dim_copy(map->dim);
+       return isl_space_copy(map->dim);
 }
 
-struct isl_dim *isl_set_get_dim(struct isl_set *set)
+__isl_give isl_space *isl_set_get_space(__isl_keep isl_set *set)
 {
        if (!set)
                return NULL;
-       return isl_dim_copy(set->dim);
+       return isl_space_copy(set->dim);
 }
 
 __isl_give isl_basic_map *isl_basic_map_set_tuple_name(
@@ -339,7 +361,7 @@ __isl_give isl_basic_map *isl_basic_map_set_tuple_name(
        bmap = isl_basic_map_cow(bmap);
        if (!bmap)
                return NULL;
-       bmap->dim = isl_dim_set_tuple_name(bmap->dim, type, s);
+       bmap->dim = isl_space_set_tuple_name(bmap->dim, type, s);
        if (!bmap->dim)
                goto error;
        bmap = isl_basic_map_finalize(bmap);
@@ -358,7 +380,7 @@ __isl_give isl_basic_set *isl_basic_set_set_tuple_name(
 const char *isl_basic_map_get_tuple_name(__isl_keep isl_basic_map *bmap,
        enum isl_dim_type type)
 {
-       return bmap ? isl_dim_get_tuple_name(bmap->dim, type) : NULL;
+       return bmap ? isl_space_get_tuple_name(bmap->dim, type) : NULL;
 }
 
 __isl_give isl_map *isl_map_set_tuple_name(__isl_take isl_map *map,
@@ -370,7 +392,7 @@ __isl_give isl_map *isl_map_set_tuple_name(__isl_take isl_map *map,
        if (!map)
                return NULL;
 
-       map->dim = isl_dim_set_tuple_name(map->dim, type, s);
+       map->dim = isl_space_set_tuple_name(map->dim, type, s);
        if (!map->dim)
                goto error;
 
@@ -389,7 +411,7 @@ error:
 const char *isl_map_get_tuple_name(__isl_keep isl_map *map,
        enum isl_dim_type type)
 {
-       return map ? isl_dim_get_tuple_name(map->dim, type) : NULL;
+       return map ? isl_space_get_tuple_name(map->dim, type) : NULL;
 }
 
 __isl_give isl_set *isl_set_set_tuple_name(__isl_take isl_set *set,
@@ -405,9 +427,9 @@ __isl_give isl_map *isl_map_set_tuple_id(__isl_take isl_map *map,
        if (!map)
                return isl_id_free(id);
 
-       map->dim = isl_dim_set_tuple_id(map->dim, type, id);
+       map->dim = isl_space_set_tuple_id(map->dim, type, id);
 
-       return isl_map_reset_dim(map, isl_dim_copy(map->dim));
+       return isl_map_reset_space(map, isl_space_copy(map->dim));
 }
 
 __isl_give isl_set *isl_set_set_tuple_id(__isl_take isl_set *set,
@@ -423,9 +445,9 @@ __isl_give isl_map *isl_map_reset_tuple_id(__isl_take isl_map *map,
        if (!map)
                return NULL;
 
-       map->dim = isl_dim_reset_tuple_id(map->dim, type);
+       map->dim = isl_space_reset_tuple_id(map->dim, type);
 
-       return isl_map_reset_dim(map, isl_dim_copy(map->dim));
+       return isl_map_reset_space(map, isl_space_copy(map->dim));
 }
 
 __isl_give isl_set *isl_set_reset_tuple_id(__isl_take isl_set *set)
@@ -435,13 +457,13 @@ __isl_give isl_set *isl_set_reset_tuple_id(__isl_take isl_set *set)
 
 int isl_map_has_tuple_id(__isl_keep isl_map *map, enum isl_dim_type type)
 {
-       return map ? isl_dim_has_tuple_id(map->dim, type) : -1;
+       return map ? isl_space_has_tuple_id(map->dim, type) : -1;
 }
 
 __isl_give isl_id *isl_map_get_tuple_id(__isl_keep isl_map *map,
        enum isl_dim_type type)
 {
-       return map ? isl_dim_get_tuple_id(map->dim, type) : NULL;
+       return map ? isl_space_get_tuple_id(map->dim, type) : NULL;
 }
 
 int isl_set_has_tuple_id(__isl_keep isl_set *set)
@@ -454,50 +476,67 @@ __isl_give isl_id *isl_set_get_tuple_id(__isl_keep isl_set *set)
        return isl_map_get_tuple_id(set, isl_dim_set);
 }
 
+/* Does the set tuple have a name?
+ */
+int isl_set_has_tuple_name(__isl_keep isl_set *set)
+{
+       return set ? isl_space_has_tuple_name(set->dim, isl_dim_set) : -1;
+}
+
+
 const char *isl_basic_set_get_tuple_name(__isl_keep isl_basic_set *bset)
 {
-       return bset ? isl_dim_get_tuple_name(bset->dim, isl_dim_set) : NULL;
+       return bset ? isl_space_get_tuple_name(bset->dim, isl_dim_set) : NULL;
 }
 
 const char *isl_set_get_tuple_name(__isl_keep isl_set *set)
 {
-       return set ? isl_dim_get_tuple_name(set->dim, isl_dim_set) : NULL;
+       return set ? isl_space_get_tuple_name(set->dim, isl_dim_set) : NULL;
 }
 
 const char *isl_basic_map_get_dim_name(__isl_keep isl_basic_map *bmap,
        enum isl_dim_type type, unsigned pos)
 {
-       return bmap ? isl_dim_get_name(bmap->dim, type, pos) : NULL;
+       return bmap ? isl_space_get_dim_name(bmap->dim, type, pos) : NULL;
 }
 
 const char *isl_basic_set_get_dim_name(__isl_keep isl_basic_set *bset,
        enum isl_dim_type type, unsigned pos)
 {
-       return bset ? isl_dim_get_name(bset->dim, type, pos) : NULL;
+       return bset ? isl_space_get_dim_name(bset->dim, type, pos) : NULL;
 }
 
 const char *isl_map_get_dim_name(__isl_keep isl_map *map,
        enum isl_dim_type type, unsigned pos)
 {
-       return map ? isl_dim_get_name(map->dim, type, pos) : NULL;
+       return map ? isl_space_get_dim_name(map->dim, type, pos) : NULL;
 }
 
 const char *isl_set_get_dim_name(__isl_keep isl_set *set,
        enum isl_dim_type type, unsigned pos)
 {
-       return set ? isl_dim_get_name(set->dim, type, pos) : NULL;
+       return set ? isl_space_get_dim_name(set->dim, type, pos) : NULL;
+}
+
+/* Does the given dimension have a name?
+ */
+int isl_set_has_dim_name(__isl_keep isl_set *set,
+       enum isl_dim_type type, unsigned pos)
+{
+       return set ? isl_space_has_dim_name(set->dim, type, pos) : -1;
 }
 
 __isl_give isl_basic_map *isl_basic_map_set_dim_name(
        __isl_take isl_basic_map *bmap,
        enum isl_dim_type type, unsigned pos, const char *s)
 {
+       bmap = isl_basic_map_cow(bmap);
        if (!bmap)
                return NULL;
-       bmap->dim = isl_dim_set_name(bmap->dim, type, pos, s);
+       bmap->dim = isl_space_set_dim_name(bmap->dim, type, pos, s);
        if (!bmap->dim)
                goto error;
-       return bmap;
+       return isl_basic_map_finalize(bmap);
 error:
        isl_basic_map_free(bmap);
        return NULL;
@@ -508,10 +547,11 @@ __isl_give isl_map *isl_map_set_dim_name(__isl_take isl_map *map,
 {
        int i;
 
+       map = isl_map_cow(map);
        if (!map)
                return NULL;
 
-       map->dim = isl_dim_set_name(map->dim, type, pos, s);
+       map->dim = isl_space_set_dim_name(map->dim, type, pos, s);
        if (!map->dim)
                goto error;
 
@@ -541,16 +581,28 @@ __isl_give isl_set *isl_set_set_dim_name(__isl_take isl_set *set,
        return (isl_set *)isl_map_set_dim_name((isl_map *)set, type, pos, s);
 }
 
+int isl_basic_map_has_dim_id(__isl_keep isl_basic_map *bmap,
+       enum isl_dim_type type, unsigned pos)
+{
+       return bmap ? isl_space_has_dim_id(bmap->dim, type, pos) : -1;
+}
+
+__isl_give isl_id *isl_basic_set_get_dim_id(__isl_keep isl_basic_set *bset,
+       enum isl_dim_type type, unsigned pos)
+{
+       return bset ? isl_space_get_dim_id(bset->dim, type, pos) : NULL;
+}
+
 int isl_map_has_dim_id(__isl_keep isl_map *map,
        enum isl_dim_type type, unsigned pos)
 {
-       return map ? isl_dim_has_dim_id(map->dim, type, pos) : -1;
+       return map ? isl_space_has_dim_id(map->dim, type, pos) : -1;
 }
 
 __isl_give isl_id *isl_map_get_dim_id(__isl_keep isl_map *map,
        enum isl_dim_type type, unsigned pos)
 {
-       return map ? isl_dim_get_dim_id(map->dim, type, pos) : NULL;
+       return map ? isl_space_get_dim_id(map->dim, type, pos) : NULL;
 }
 
 int isl_set_has_dim_id(__isl_keep isl_set *set,
@@ -572,9 +624,9 @@ __isl_give isl_map *isl_map_set_dim_id(__isl_take isl_map *map,
        if (!map)
                return isl_id_free(id);
 
-       map->dim = isl_dim_set_dim_id(map->dim, type, pos, id);
+       map->dim = isl_space_set_dim_id(map->dim, type, pos, id);
 
-       return isl_map_reset_dim(map, isl_dim_copy(map->dim));
+       return isl_map_reset_space(map, isl_space_copy(map->dim));
 }
 
 __isl_give isl_set *isl_set_set_dim_id(__isl_take isl_set *set,
@@ -588,7 +640,7 @@ int isl_map_find_dim_by_id(__isl_keep isl_map *map, enum isl_dim_type type,
 {
        if (!map)
                return -1;
-       return isl_dim_find_dim_by_id(map->dim, type, id);
+       return isl_space_find_dim_by_id(map->dim, type, id);
 }
 
 int isl_set_find_dim_by_id(__isl_keep isl_set *set, enum isl_dim_type type,
@@ -597,6 +649,20 @@ int isl_set_find_dim_by_id(__isl_keep isl_set *set, enum isl_dim_type type,
        return isl_map_find_dim_by_id(set, type, id);
 }
 
+int isl_map_find_dim_by_name(__isl_keep isl_map *map, enum isl_dim_type type,
+       const char *name)
+{
+       if (!map)
+               return -1;
+       return isl_space_find_dim_by_name(map->dim, type, name);
+}
+
+int isl_set_find_dim_by_name(__isl_keep isl_set *set, enum isl_dim_type type,
+       const char *name)
+{
+       return isl_map_find_dim_by_name(set, type, name);
+}
+
 int isl_basic_map_is_rational(__isl_keep isl_basic_map *bmap)
 {
        if (!bmap)
@@ -609,12 +675,41 @@ int isl_basic_set_is_rational(__isl_keep isl_basic_set *bset)
        return isl_basic_map_is_rational(bset);
 }
 
+/* Is this basic set a parameter domain?
+ */
+int isl_basic_set_is_params(__isl_keep isl_basic_set *bset)
+{
+       if (!bset)
+               return -1;
+       return isl_space_is_params(bset->dim);
+}
+
+/* Is this set a parameter domain?
+ */
+int isl_set_is_params(__isl_keep isl_set *set)
+{
+       if (!set)
+               return -1;
+       return isl_space_is_params(set->dim);
+}
+
+/* Is this map actually a parameter domain?
+ * Users should never call this function.  Outside of isl,
+ * a map can never be a parameter domain.
+ */
+int isl_map_is_params(__isl_keep isl_map *map)
+{
+       if (!map)
+               return -1;
+       return isl_space_is_params(map->dim);
+}
+
 static struct isl_basic_map *basic_map_init(struct isl_ctx *ctx,
                struct isl_basic_map *bmap, unsigned extra,
                unsigned n_eq, unsigned n_ineq)
 {
        int i;
-       size_t row_size = 1 + isl_dim_total(bmap->dim) + extra;
+       size_t row_size = 1 + isl_space_dim(bmap->dim, isl_dim_all) + extra;
 
        bmap->ctx = ctx;
        isl_ctx_ref(ctx);
@@ -667,25 +762,31 @@ struct isl_basic_set *isl_basic_set_alloc(struct isl_ctx *ctx,
                unsigned n_eq, unsigned n_ineq)
 {
        struct isl_basic_map *bmap;
-       bmap = isl_basic_map_alloc(ctx, nparam, 0, dim, extra, n_eq, n_ineq);
+       isl_space *space;
+
+       space = isl_space_set_alloc(ctx, nparam, dim);
+       if (!space)
+               return NULL;
+
+       bmap = isl_basic_map_alloc_space(space, extra, n_eq, n_ineq);
        return (struct isl_basic_set *)bmap;
 }
 
-struct isl_basic_set *isl_basic_set_alloc_dim(struct isl_dim *dim,
+struct isl_basic_set *isl_basic_set_alloc_space(__isl_take isl_space *dim,
                unsigned extra, unsigned n_eq, unsigned n_ineq)
 {
        struct isl_basic_map *bmap;
        if (!dim)
                return NULL;
        isl_assert(dim->ctx, dim->n_in == 0, goto error);
-       bmap = isl_basic_map_alloc_dim(dim, extra, n_eq, n_ineq);
+       bmap = isl_basic_map_alloc_space(dim, extra, n_eq, n_ineq);
        return (struct isl_basic_set *)bmap;
 error:
-       isl_dim_free(dim);
+       isl_space_free(dim);
        return NULL;
 }
 
-struct isl_basic_map *isl_basic_map_alloc_dim(struct isl_dim *dim,
+struct isl_basic_map *isl_basic_map_alloc_space(__isl_take isl_space *dim,
                unsigned extra, unsigned n_eq, unsigned n_ineq)
 {
        struct isl_basic_map *bmap;
@@ -699,7 +800,7 @@ struct isl_basic_map *isl_basic_map_alloc_dim(struct isl_dim *dim,
 
        return basic_map_init(dim->ctx, bmap, extra, n_eq, n_ineq);
 error:
-       isl_dim_free(dim);
+       isl_space_free(dim);
        return NULL;
 }
 
@@ -708,13 +809,13 @@ struct isl_basic_map *isl_basic_map_alloc(struct isl_ctx *ctx,
                unsigned n_eq, unsigned n_ineq)
 {
        struct isl_basic_map *bmap;
-       struct isl_dim *dim;
+       isl_space *dim;
 
-       dim = isl_dim_alloc(ctx, nparam, in, out);
+       dim = isl_space_alloc(ctx, nparam, in, out);
        if (!dim)
                return NULL;
 
-       bmap = isl_basic_map_alloc_dim(dim, extra, n_eq, n_ineq);
+       bmap = isl_basic_map_alloc_space(dim, extra, n_eq, n_ineq);
        return bmap;
 }
 
@@ -747,7 +848,7 @@ struct isl_basic_map *isl_basic_map_dup(struct isl_basic_map *bmap)
 
        if (!bmap)
                return NULL;
-       dup = isl_basic_map_alloc_dim(isl_dim_copy(bmap->dim),
+       dup = isl_basic_map_alloc_space(isl_space_copy(bmap->dim),
                        bmap->n_div, bmap->n_eq, bmap->n_ineq);
        if (!dup)
                return NULL;
@@ -824,7 +925,7 @@ void isl_basic_map_free(struct isl_basic_map *bmap)
        free(bmap->ineq);
        isl_blk_free(bmap->ctx, bmap->block);
        isl_vec_free(bmap->sample);
-       isl_dim_free(bmap->dim);
+       isl_space_free(bmap->dim);
        free(bmap);
 }
 
@@ -845,14 +946,14 @@ __isl_give isl_map *isl_map_align_params_map_map_and(
 {
        if (!map1 || !map2)
                goto error;
-       if (isl_dim_match(map1->dim, isl_dim_param, map2->dim, isl_dim_param))
+       if (isl_space_match(map1->dim, isl_dim_param, map2->dim, isl_dim_param))
                return fn(map1, map2);
-       if (!isl_dim_has_named_params(map1->dim) ||
-           !isl_dim_has_named_params(map2->dim))
+       if (!isl_space_has_named_params(map1->dim) ||
+           !isl_space_has_named_params(map2->dim))
                isl_die(map1->ctx, isl_error_invalid,
                        "unaligned unnamed parameters", goto error);
-       map1 = isl_map_align_params(map1, isl_map_get_dim(map2));
-       map2 = isl_map_align_params(map2, isl_map_get_dim(map1));
+       map1 = isl_map_align_params(map1, isl_map_get_space(map2));
+       map2 = isl_map_align_params(map2, isl_map_get_space(map1));
        return fn(map1, map2);
 error:
        isl_map_free(map1);
@@ -860,7 +961,7 @@ error:
        return NULL;
 }
 
-static int align_params_map_map_and_test(__isl_keep isl_map *map1,
+int isl_map_align_params_map_map_and_test(__isl_keep isl_map *map1,
        __isl_keep isl_map *map2,
        int (*fn)(__isl_keep isl_map *map1, __isl_keep isl_map *map2))
 {
@@ -868,16 +969,16 @@ static int align_params_map_map_and_test(__isl_keep isl_map *map1,
 
        if (!map1 || !map2)
                return -1;
-       if (isl_dim_match(map1->dim, isl_dim_param, map2->dim, isl_dim_param))
+       if (isl_space_match(map1->dim, isl_dim_param, map2->dim, isl_dim_param))
                return fn(map1, map2);
-       if (!isl_dim_has_named_params(map1->dim) ||
-           !isl_dim_has_named_params(map2->dim))
+       if (!isl_space_has_named_params(map1->dim) ||
+           !isl_space_has_named_params(map2->dim))
                isl_die(map1->ctx, isl_error_invalid,
                        "unaligned unnamed parameters", return -1);
        map1 = isl_map_copy(map1);
        map2 = isl_map_copy(map2);
-       map1 = isl_map_align_params(map1, isl_map_get_dim(map2));
-       map2 = isl_map_align_params(map2, isl_map_get_dim(map1));
+       map1 = isl_map_align_params(map1, isl_map_get_space(map2));
+       map2 = isl_map_align_params(map2, isl_map_get_space(map1));
        r = fn(map1, map2);
        isl_map_free(map1);
        isl_map_free(map2);
@@ -1224,8 +1325,8 @@ struct isl_basic_set *isl_basic_set_add_constraints(struct isl_basic_set *bset1,
                                (struct isl_basic_map *)bset2, 0, pos);
 }
 
-struct isl_basic_map *isl_basic_map_extend_dim(struct isl_basic_map *base,
-               struct isl_dim *dim, unsigned extra,
+struct isl_basic_map *isl_basic_map_extend_space(struct isl_basic_map *base,
+               __isl_take isl_space *dim, unsigned extra,
                unsigned n_eq, unsigned n_ineq)
 {
        struct isl_basic_map *ext;
@@ -1238,12 +1339,12 @@ struct isl_basic_map *isl_basic_map_extend_dim(struct isl_basic_map *base,
        if (!base)
                goto error;
 
-       dims_ok = isl_dim_equal(base->dim, dim) &&
+       dims_ok = isl_space_is_equal(base->dim, dim) &&
                  base->extra >= base->n_div + extra;
 
        if (dims_ok && room_for_con(base, n_eq + n_ineq) &&
                       room_for_ineq(base, n_ineq)) {
-               isl_dim_free(dim);
+               isl_space_free(dim);
                return base;
        }
 
@@ -1254,7 +1355,7 @@ struct isl_basic_map *isl_basic_map_extend_dim(struct isl_basic_map *base,
        n_eq += base->n_eq;
        n_ineq += base->n_ineq;
 
-       ext = isl_basic_map_alloc_dim(dim, extra, n_eq, n_ineq);
+       ext = isl_basic_map_alloc_space(dim, extra, n_eq, n_ineq);
        dim = NULL;
        if (!ext)
                goto error;
@@ -1271,17 +1372,17 @@ struct isl_basic_map *isl_basic_map_extend_dim(struct isl_basic_map *base,
        return ext;
 
 error:
-       isl_dim_free(dim);
+       isl_space_free(dim);
        isl_basic_map_free(base);
        return NULL;
 }
 
-struct isl_basic_set *isl_basic_set_extend_dim(struct isl_basic_set *base,
-               struct isl_dim *dim, unsigned extra,
+struct isl_basic_set *isl_basic_set_extend_space(struct isl_basic_set *base,
+               __isl_take isl_space *dim, unsigned extra,
                unsigned n_eq, unsigned n_ineq)
 {
        return (struct isl_basic_set *)
-               isl_basic_map_extend_dim((struct isl_basic_map *)base, dim,
+               isl_basic_map_extend_space((struct isl_basic_map *)base, dim,
                                                        extra, n_eq, n_ineq);
 }
 
@@ -1290,7 +1391,7 @@ struct isl_basic_map *isl_basic_map_extend_constraints(
 {
        if (!base)
                return NULL;
-       return isl_basic_map_extend_dim(base, isl_dim_copy(base->dim),
+       return isl_basic_map_extend_space(base, isl_space_copy(base->dim),
                                        0, n_eq, n_ineq);
 }
 
@@ -1299,15 +1400,15 @@ struct isl_basic_map *isl_basic_map_extend(struct isl_basic_map *base,
                unsigned n_eq, unsigned n_ineq)
 {
        struct isl_basic_map *bmap;
-       struct isl_dim *dim;
+       isl_space *dim;
 
        if (!base)
                return NULL;
-       dim = isl_dim_alloc(base->ctx, nparam, n_in, n_out);
+       dim = isl_space_alloc(base->ctx, nparam, n_in, n_out);
        if (!dim)
                goto error;
 
-       bmap = isl_basic_map_extend_dim(base, dim, extra, n_eq, n_ineq);
+       bmap = isl_basic_map_extend_space(base, dim, extra, n_eq, n_ineq);
        return bmap;
 error:
        isl_basic_map_free(base);
@@ -1478,7 +1579,7 @@ struct isl_basic_set *isl_basic_set_set_to_empty(struct isl_basic_set *bset)
 void isl_basic_map_swap_div(struct isl_basic_map *bmap, int a, int b)
 {
        int i;
-       unsigned off = isl_dim_total(bmap->dim);
+       unsigned off = isl_space_dim(bmap->dim, isl_dim_all);
        isl_int *t = bmap->div[a];
        bmap->div[a] = bmap->div[b];
        bmap->div[b] = t;
@@ -1495,8 +1596,8 @@ void isl_basic_map_swap_div(struct isl_basic_map *bmap, int a, int b)
 }
 
 /* Eliminate the specified n dimensions starting at first from the
- * constraints using Fourier-Motzkin.  The dimensions themselves
- * are not removed.
+ * constraints, without removing the dimensions from the space.
+ * If the set is rational, the dimensions are eliminated using Fourier-Motzkin.
  */
 __isl_give isl_map *isl_map_eliminate(__isl_take isl_map *map,
        enum isl_dim_type type, unsigned first, unsigned n)
@@ -1508,14 +1609,16 @@ __isl_give isl_map *isl_map_eliminate(__isl_take isl_map *map,
        if (n == 0)
                return map;
 
+       if (first + n > isl_map_dim(map, type) || first + n < first)
+               isl_die(map->ctx, isl_error_invalid,
+                       "index out of bounds", goto error);
+
        map = isl_map_cow(map);
        if (!map)
                return NULL;
-       isl_assert(map->ctx, first + n <= isl_map_dim(map, type), goto error);
-       first += pos(map->dim, type) - 1;
-       
+
        for (i = 0; i < map->n; ++i) {
-               map->p[i] = isl_basic_map_eliminate_vars(map->p[i], first, n);
+               map->p[i] = isl_basic_map_eliminate(map->p[i], type, first, n);
                if (!map->p[i])
                        goto error;
        }
@@ -1526,8 +1629,8 @@ error:
 }
 
 /* Eliminate the specified n dimensions starting at first from the
- * constraints using Fourier-Motzkin.  The dimensions themselves
- * are not removed.
+ * constraints, without removing the dimensions from the space.
+ * If the set is rational, the dimensions are eliminated using Fourier-Motzkin.
  */
 __isl_give isl_set *isl_set_eliminate(__isl_take isl_set *set,
        enum isl_dim_type type, unsigned first, unsigned n)
@@ -1536,8 +1639,8 @@ __isl_give isl_set *isl_set_eliminate(__isl_take isl_set *set,
 }
 
 /* Eliminate the specified n dimensions starting at first from the
- * constraints using Fourier-Motzkin.  The dimensions themselves
- * are not removed.
+ * constraints, without removing the dimensions from the space.
+ * If the set is rational, the dimensions are eliminated using Fourier-Motzkin.
  */
 __isl_give isl_set *isl_set_eliminate_dims(__isl_take isl_set *set,
        unsigned first, unsigned n)
@@ -1550,8 +1653,8 @@ __isl_give isl_basic_map *isl_basic_map_remove_divs(
 {
        if (!bmap)
                return NULL;
-       bmap = isl_basic_map_eliminate_vars(bmap, isl_dim_total(bmap->dim),
-                                               bmap->n_div);
+       bmap = isl_basic_map_eliminate_vars(bmap,
+                           isl_space_dim(bmap->dim, isl_dim_all), bmap->n_div);
        if (!bmap)
                return NULL;
        bmap->n_div = 0;
@@ -1601,7 +1704,7 @@ struct isl_basic_map *isl_basic_map_remove_dims(struct isl_basic_map *bmap,
                return NULL;
        isl_assert(bmap->ctx, first + n <= isl_basic_map_dim(bmap, type),
                        goto error);
-       if (n == 0 && !isl_dim_is_named_or_nested(bmap->dim, type))
+       if (n == 0 && !isl_space_is_named_or_nested(bmap->dim, type))
                return bmap;
        bmap = isl_basic_map_eliminate_vars(bmap,
                        isl_basic_map_offset(bmap, type) - 1 + first, n);
@@ -1640,6 +1743,196 @@ static int div_involves_vars(__isl_keep isl_basic_map *bmap, int div,
        return 0;
 }
 
+/* Try and add a lower and/or upper bound on "div" to "bmap"
+ * based on inequality "i".
+ * "total" is the total number of variables (excluding the divs).
+ * "v" is a temporary object that can be used during the calculations.
+ * If "lb" is set, then a lower bound should be constructed.
+ * If "ub" is set, then an upper bound should be constructed.
+ *
+ * The calling function has already checked that the inequality does not
+ * reference "div", but we still need to check that the inequality is
+ * of the right form.  We'll consider the case where we want to construct
+ * a lower bound.  The construction of upper bounds is similar.
+ *
+ * Let "div" be of the form
+ *
+ *     q = floor((a + f(x))/d)
+ *
+ * We essentially check if constraint "i" is of the form
+ *
+ *     b + f(x) >= 0
+ *
+ * so that we can use it to derive a lower bound on "div".
+ * However, we allow a slightly more general form
+ *
+ *     b + g(x) >= 0
+ *
+ * with the condition that the coefficients of g(x) - f(x) are all
+ * divisible by d.
+ * Rewriting this constraint as
+ *
+ *     0 >= -b - g(x)
+ *
+ * adding a + f(x) to both sides and dividing by d, we obtain
+ *
+ *     (a + f(x))/d >= (a-b)/d + (f(x)-g(x))/d
+ *
+ * Taking the floor on both sides, we obtain
+ *
+ *     q >= floor((a-b)/d) + (f(x)-g(x))/d
+ *
+ * or
+ *
+ *     (g(x)-f(x))/d + ceil((b-a)/d) + q >= 0
+ *
+ * In the case of an upper bound, we construct the constraint
+ *
+ *     (g(x)+f(x))/d + floor((b+a)/d) - q >= 0
+ *
+ */
+static __isl_give isl_basic_map *insert_bounds_on_div_from_ineq(
+       __isl_take isl_basic_map *bmap, int div, int i,
+       unsigned total, isl_int v, int lb, int ub)
+{
+       int j;
+
+       for (j = 0; (lb || ub) && j < total + bmap->n_div; ++j) {
+               if (lb) {
+                       isl_int_sub(v, bmap->ineq[i][1 + j],
+                                       bmap->div[div][1 + 1 + j]);
+                       lb = isl_int_is_divisible_by(v, bmap->div[div][0]);
+               }
+               if (ub) {
+                       isl_int_add(v, bmap->ineq[i][1 + j],
+                                       bmap->div[div][1 + 1 + j]);
+                       ub = isl_int_is_divisible_by(v, bmap->div[div][0]);
+               }
+       }
+       if (!lb && !ub)
+               return bmap;
+
+       bmap = isl_basic_map_extend_constraints(bmap, 0, lb + ub);
+       if (lb) {
+               int k = isl_basic_map_alloc_inequality(bmap);
+               if (k < 0)
+                       goto error;
+               for (j = 0; j < 1 + total + bmap->n_div; ++j) {
+                       isl_int_sub(bmap->ineq[k][j], bmap->ineq[i][j],
+                                       bmap->div[div][1 + j]);
+                       isl_int_cdiv_q(bmap->ineq[k][j],
+                                       bmap->ineq[k][j], bmap->div[div][0]);
+               }
+               isl_int_set_si(bmap->ineq[k][1 + total + div], 1);
+       }
+       if (ub) {
+               int k = isl_basic_map_alloc_inequality(bmap);
+               if (k < 0)
+                       goto error;
+               for (j = 0; j < 1 + total + bmap->n_div; ++j) {
+                       isl_int_add(bmap->ineq[k][j], bmap->ineq[i][j],
+                                       bmap->div[div][1 + j]);
+                       isl_int_fdiv_q(bmap->ineq[k][j],
+                                       bmap->ineq[k][j], bmap->div[div][0]);
+               }
+               isl_int_set_si(bmap->ineq[k][1 + total + div], -1);
+       }
+
+       return bmap;
+error:
+       isl_basic_map_free(bmap);
+       return NULL;
+}
+
+/* This function is called right before "div" is eliminated from "bmap"
+ * using Fourier-Motzkin.
+ * Look through the constraints of "bmap" for constraints on the argument
+ * of the integer division and use them to construct constraints on the
+ * integer division itself.  These constraints can then be combined
+ * during the Fourier-Motzkin elimination.
+ * Note that it is only useful to introduce lower bounds on "div"
+ * if "bmap" already contains upper bounds on "div" as the newly
+ * introduce lower bounds can then be combined with the pre-existing
+ * upper bounds.  Similarly for upper bounds.
+ * We therefore first check if "bmap" contains any lower and/or upper bounds
+ * on "div".
+ *
+ * It is interesting to note that the introduction of these constraints
+ * can indeed lead to more accurate results, even when compared to
+ * deriving constraints on the argument of "div" from constraints on "div".
+ * Consider, for example, the set
+ *
+ *     { [i,j,k] : 3 + i + 2j >= 0 and 2 * [(i+2j)/4] <= k }
+ *
+ * The second constraint can be rewritten as
+ *
+ *     2 * [(-i-2j+3)/4] + k >= 0
+ *
+ * from which we can derive
+ *
+ *     -i - 2j + 3 >= -2k
+ *
+ * or
+ *
+ *     i + 2j <= 3 + 2k
+ *
+ * Combined with the first constraint, we obtain
+ *
+ *     -3 <= 3 + 2k    or      k >= -3
+ *
+ * If, on the other hand we derive a constraint on [(i+2j)/4] from
+ * the first constraint, we obtain
+ *
+ *     [(i + 2j)/4] >= [-3/4] = -1
+ *
+ * Combining this constraint with the second constraint, we obtain
+ *
+ *     k >= -2
+ */
+static __isl_give isl_basic_map *insert_bounds_on_div(
+       __isl_take isl_basic_map *bmap, int div)
+{
+       int i;
+       int check_lb, check_ub;
+       isl_int v;
+       unsigned total;
+
+       if (!bmap)
+               return NULL;
+
+       if (isl_int_is_zero(bmap->div[div][0]))
+               return bmap;
+
+       total = isl_space_dim(bmap->dim, isl_dim_all);
+
+       check_lb = 0;
+       check_ub = 0;
+       for (i = 0; (!check_lb || !check_ub) && i < bmap->n_ineq; ++i) {
+               int s = isl_int_sgn(bmap->ineq[i][1 + total + div]);
+               if (s > 0)
+                       check_ub = 1;
+               if (s < 0)
+                       check_lb = 1;
+       }
+
+       if (!check_lb && !check_ub)
+               return bmap;
+
+       isl_int_init(v);
+
+       for (i = 0; bmap && i < bmap->n_ineq; ++i) {
+               if (!isl_int_is_zero(bmap->ineq[i][1 + total + div]))
+                       continue;
+
+               bmap = insert_bounds_on_div_from_ineq(bmap, div, i, total, v,
+                                                       check_lb, check_ub);
+       }
+
+       isl_int_clear(v);
+
+       return bmap;
+}
+
 /* Remove all divs (recursively) involving any of the given dimensions
  * in their definitions.
  */
@@ -1658,6 +1951,7 @@ __isl_give isl_basic_map *isl_basic_map_remove_divs_involving_dims(
        for (i = bmap->n_div - 1; i >= 0; --i) {
                if (!div_involves_vars(bmap, i, first, n))
                        continue;
+               bmap = insert_bounds_on_div(bmap, i);
                bmap = isl_basic_map_remove_dims(bmap, isl_dim_div, i, 1);
                if (!bmap)
                        return NULL;
@@ -1703,6 +1997,12 @@ __isl_give isl_set *isl_set_remove_divs_involving_dims(__isl_take isl_set *set,
                                                              type, first, n);
 }
 
+/* Does the desciption of "bmap" depend on the specified dimensions?
+ * We also check whether the dimensions appear in any of the div definitions.
+ * In principle there is no need for this check.  If the dimensions appear
+ * in a div definition, they also appear in the defining constraints of that
+ * div.
+ */
 int isl_basic_map_involves_dims(__isl_keep isl_basic_map *bmap,
        enum isl_dim_type type, unsigned first, unsigned n)
 {
@@ -1722,6 +2022,12 @@ int isl_basic_map_involves_dims(__isl_keep isl_basic_map *bmap,
        for (i = 0; i < bmap->n_ineq; ++i)
                if (isl_seq_first_non_zero(bmap->ineq[i] + first, n) >= 0)
                        return 1;
+       for (i = 0; i < bmap->n_div; ++i) {
+               if (isl_int_is_zero(bmap->div[i][0]))
+                       continue;
+               if (isl_seq_first_non_zero(bmap->div[i] + 1 + first, n) >= 0)
+                       return 1;
+       }
 
        return 0;
 }
@@ -1741,11 +2047,11 @@ int isl_map_involves_dims(__isl_keep isl_map *map,
        for (i = 0; i < map->n; ++i) {
                int involves = isl_basic_map_involves_dims(map->p[i],
                                                            type, first, n);
-               if (involves < 0 || !involves)
+               if (involves < 0 || involves)
                        return involves;
        }
 
-       return 1;
+       return 0;
 }
 
 int isl_basic_set_involves_dims(__isl_keep isl_basic_set *bset,
@@ -1795,6 +2101,9 @@ __isl_give isl_basic_map *isl_basic_map_remove_unknown_divs(
                if (!div_is_unknown(bmap, i))
                        continue;
                bmap = isl_basic_map_remove_dims(bmap, isl_dim_div, i, 1);
+               if (!bmap)
+                       return NULL;
+               i = bmap->n_div;
        }
 
        return bmap;
@@ -1889,7 +2198,7 @@ static void dump_term(struct isl_basic_map *bmap,
                if (!isl_int_is_one(c))
                        isl_int_print(out, c, 0);
                if (pos < 1 + nparam) {
-                       name = isl_dim_get_name(bmap->dim,
+                       name = isl_space_get_dim_name(bmap->dim,
                                                isl_dim_param, pos - 1);
                        if (name)
                                fprintf(out, "%s", name);
@@ -1941,7 +2250,7 @@ static void dump_constraint(struct isl_basic_map *bmap, isl_int *c,
        fprintf(out, "\n");
 
        for (i = bmap->n_div; i < bmap->extra; ++i) {
-               if (isl_int_is_zero(c[1+isl_dim_total(bmap->dim)+i]))
+               if (isl_int_is_zero(c[1+isl_space_dim(bmap->dim, isl_dim_all)+i]))
                        continue;
                fprintf(out, "%*s", indent, "");
                fprintf(out, "ERROR: unused div coefficient not zero\n");
@@ -2037,7 +2346,8 @@ int isl_inequality_negate(struct isl_basic_map *bmap, unsigned pos)
        return 0;
 }
 
-struct isl_set *isl_set_alloc_dim(struct isl_dim *dim, int n, unsigned flags)
+__isl_give isl_set *isl_set_alloc_space(__isl_take isl_space *dim, int n,
+       unsigned flags)
 {
        struct isl_set *set;
 
@@ -2060,7 +2370,7 @@ struct isl_set *isl_set_alloc_dim(struct isl_dim *dim, int n, unsigned flags)
        set->flags = flags;
        return set;
 error:
-       isl_dim_free(dim);
+       isl_space_free(dim);
        return NULL;
 }
 
@@ -2068,13 +2378,13 @@ struct isl_set *isl_set_alloc(struct isl_ctx *ctx,
                unsigned nparam, unsigned dim, int n, unsigned flags)
 {
        struct isl_set *set;
-       struct isl_dim *dims;
+       isl_space *dims;
 
-       dims = isl_dim_alloc(ctx, nparam, 0, dim);
+       dims = isl_space_alloc(ctx, nparam, 0, dim);
        if (!dims)
                return NULL;
 
-       set = isl_set_alloc_dim(dims, n, flags);
+       set = isl_set_alloc_space(dims, n, flags);
        return set;
 }
 
@@ -2090,7 +2400,7 @@ struct isl_map *isl_map_grow(struct isl_map *map, int n)
        isl_assert(map->ctx, n >= 0, goto error);
        if (map->n + n <= map->size)
                return map;
-       grown = isl_map_alloc_dim(isl_map_get_dim(map), map->n + n, map->flags);
+       grown = isl_map_alloc_space(isl_map_get_space(map), map->n + n, map->flags);
        if (!grown)
                goto error;
        for (i = 0; i < map->n; ++i) {
@@ -2122,7 +2432,7 @@ struct isl_set *isl_set_dup(struct isl_set *set)
        if (!set)
                return NULL;
 
-       dup = isl_set_alloc_dim(isl_dim_copy(set->dim), set->n, set->flags);
+       dup = isl_set_alloc_space(isl_space_copy(set->dim), set->n, set->flags);
        if (!dup)
                return NULL;
        for (i = 0; i < set->n; ++i)
@@ -2142,7 +2452,7 @@ struct isl_map *isl_map_from_basic_map(struct isl_basic_map *bmap)
        if (!bmap)
                return NULL;
 
-       map = isl_map_alloc_dim(isl_dim_copy(bmap->dim), 1, ISL_MAP_DISJOINT);
+       map = isl_map_alloc_space(isl_space_copy(bmap->dim), 1, ISL_MAP_DISJOINT);
        return isl_map_add_basic_map(map, bmap);
 }
 
@@ -2166,7 +2476,7 @@ void isl_set_free(struct isl_set *set)
        isl_ctx_deref(set->ctx);
        for (i = 0; i < set->n; ++i)
                isl_basic_set_free(set->p[i]);
-       isl_dim_free(set->dim);
+       isl_space_free(set->dim);
        free(set);
 }
 
@@ -2219,17 +2529,17 @@ struct isl_basic_map *isl_basic_map_intersect_domain(
        if (!bmap || !bset)
                goto error;
 
-       isl_assert(bset->ctx, isl_dim_match(bmap->dim, isl_dim_param,
+       isl_assert(bset->ctx, isl_space_match(bmap->dim, isl_dim_param,
                                        bset->dim, isl_dim_param), goto error);
 
-       if (isl_dim_size(bset->dim, isl_dim_set) != 0)
+       if (isl_space_dim(bset->dim, isl_dim_set) != 0)
                isl_assert(bset->ctx,
                    isl_basic_map_compatible_domain(bmap, bset), goto error);
 
        bmap = isl_basic_map_cow(bmap);
        if (!bmap)
                goto error;
-       bmap = isl_basic_map_extend_dim(bmap, isl_dim_copy(bmap->dim),
+       bmap = isl_basic_map_extend_space(bmap, isl_space_copy(bmap->dim),
                        bset->n_div, bset->n_eq, bset->n_ineq);
        bmap_domain = isl_basic_map_from_domain(bset);
        bmap = add_constraints(bmap, bmap_domain, 0, 0);
@@ -2250,10 +2560,10 @@ struct isl_basic_map *isl_basic_map_intersect_range(
        if (!bmap || !bset)
                goto error;
 
-       isl_assert(bset->ctx, isl_dim_match(bmap->dim, isl_dim_param,
+       isl_assert(bset->ctx, isl_space_match(bmap->dim, isl_dim_param,
                                        bset->dim, isl_dim_param), goto error);
 
-       if (isl_dim_size(bset->dim, isl_dim_set) != 0)
+       if (isl_space_dim(bset->dim, isl_dim_set) != 0)
                isl_assert(bset->ctx,
                    isl_basic_map_compatible_range(bmap, bset), goto error);
 
@@ -2265,9 +2575,9 @@ struct isl_basic_map *isl_basic_map_intersect_range(
        bmap = isl_basic_map_cow(bmap);
        if (!bmap)
                goto error;
-       bmap = isl_basic_map_extend_dim(bmap, isl_dim_copy(bmap->dim),
+       bmap = isl_basic_map_extend_space(bmap, isl_space_copy(bmap->dim),
                        bset->n_div, bset->n_eq, bset->n_ineq);
-       bmap_range = isl_basic_map_from_basic_set(bset, isl_dim_copy(bset->dim));
+       bmap_range = isl_basic_map_from_basic_set(bset, isl_space_copy(bset->dim));
        bmap = add_constraints(bmap, bmap_range, 0, 0);
 
        bmap = isl_basic_map_simplify(bmap);
@@ -2324,18 +2634,18 @@ struct isl_basic_map *isl_basic_map_intersect(
        if (!bmap1 || !bmap2)
                goto error;
 
-       isl_assert(bmap1->ctx, isl_dim_match(bmap1->dim, isl_dim_param,
+       isl_assert(bmap1->ctx, isl_space_match(bmap1->dim, isl_dim_param,
                                     bmap2->dim, isl_dim_param), goto error);
-       if (isl_dim_total(bmap1->dim) ==
-                               isl_dim_size(bmap1->dim, isl_dim_param) &&
-           isl_dim_total(bmap2->dim) !=
-                               isl_dim_size(bmap2->dim, isl_dim_param))
+       if (isl_space_dim(bmap1->dim, isl_dim_all) ==
+                               isl_space_dim(bmap1->dim, isl_dim_param) &&
+           isl_space_dim(bmap2->dim, isl_dim_all) !=
+                               isl_space_dim(bmap2->dim, isl_dim_param))
                return isl_basic_map_intersect(bmap2, bmap1);
 
-       if (isl_dim_total(bmap2->dim) !=
-                                       isl_dim_size(bmap2->dim, isl_dim_param))
+       if (isl_space_dim(bmap2->dim, isl_dim_all) !=
+                                       isl_space_dim(bmap2->dim, isl_dim_param))
                isl_assert(bmap1->ctx,
-                           isl_dim_equal(bmap1->dim, bmap2->dim), goto error);
+                           isl_space_is_equal(bmap1->dim, bmap2->dim), goto error);
 
        if (bmap1->sample &&
            isl_basic_map_contains(bmap1, bmap1->sample) > 0 &&
@@ -2349,7 +2659,7 @@ struct isl_basic_map *isl_basic_map_intersect(
        bmap1 = isl_basic_map_cow(bmap1);
        if (!bmap1)
                goto error;
-       bmap1 = isl_basic_map_extend_dim(bmap1, isl_dim_copy(bmap1->dim),
+       bmap1 = isl_basic_map_extend_space(bmap1, isl_space_copy(bmap1->dim),
                        bmap2->n_div, bmap2->n_eq, bmap2->n_ineq);
        bmap1 = add_constraints(bmap1, bmap2, 0, 0);
 
@@ -2379,6 +2689,12 @@ struct isl_basic_set *isl_basic_set_intersect(
                        (struct isl_basic_map *)bset2);
 }
 
+__isl_give isl_basic_set *isl_basic_set_intersect_params(
+       __isl_take isl_basic_set *bset1, __isl_take isl_basic_set *bset2)
+{
+       return isl_basic_set_intersect(bset1, bset2);
+}
+
 /* Special case of isl_map_intersect, where both map1 and map2
  * are convex, without any divs and such that either map1 or map2
  * contains a single constraint.  This constraint is then simply
@@ -2431,7 +2747,10 @@ error:
        return NULL;
 }
 
-static __isl_give isl_map *map_intersect(__isl_take isl_map *map1,
+/* map2 may be either a parameter domain or a map living in the same
+ * space as map1.
+ */
+static __isl_give isl_map *map_intersect_internal(__isl_take isl_map *map1,
        __isl_take isl_map *map2)
 {
        unsigned flags = 0;
@@ -2442,36 +2761,33 @@ static __isl_give isl_map *map_intersect(__isl_take isl_map *map1,
                goto error;
 
        if (isl_map_plain_is_empty(map1) &&
-           isl_dim_equal(map1->dim, map2->dim)) {
+           isl_space_is_equal(map1->dim, map2->dim)) {
                isl_map_free(map2);
                return map1;
        }
        if (isl_map_plain_is_empty(map2) &&
-           isl_dim_equal(map1->dim, map2->dim)) {
+           isl_space_is_equal(map1->dim, map2->dim)) {
                isl_map_free(map1);
                return map2;
        }
 
        if (map1->n == 1 && map2->n == 1 &&
            map1->p[0]->n_div == 0 && map2->p[0]->n_div == 0 &&
-           isl_dim_equal(map1->dim, map2->dim) &&
+           isl_space_is_equal(map1->dim, map2->dim) &&
            (map1->p[0]->n_eq + map1->p[0]->n_ineq == 1 ||
             map2->p[0]->n_eq + map2->p[0]->n_ineq == 1))
                return map_intersect_add_constraint(map1, map2);
-       if (isl_dim_total(map1->dim) ==
-                               isl_dim_size(map1->dim, isl_dim_param) &&
-           isl_dim_total(map2->dim) != isl_dim_size(map2->dim, isl_dim_param))
-               return isl_map_intersect(map2, map1);
 
-       if (isl_dim_total(map2->dim) != isl_dim_size(map2->dim, isl_dim_param))
+       if (isl_space_dim(map2->dim, isl_dim_all) !=
+                               isl_space_dim(map2->dim, isl_dim_param))
                isl_assert(map1->ctx,
-                           isl_dim_equal(map1->dim, map2->dim), goto error);
+                           isl_space_is_equal(map1->dim, map2->dim), goto error);
 
        if (ISL_F_ISSET(map1, ISL_MAP_DISJOINT) &&
            ISL_F_ISSET(map2, ISL_MAP_DISJOINT))
                ISL_FL_SET(flags, ISL_MAP_DISJOINT);
 
-       result = isl_map_alloc_dim(isl_dim_copy(map1->dim),
+       result = isl_map_alloc_space(isl_space_copy(map1->dim),
                                map1->n * map2->n, flags);
        if (!result)
                goto error;
@@ -2497,6 +2813,21 @@ error:
        return NULL;
 }
 
+static __isl_give isl_map *map_intersect(__isl_take isl_map *map1,
+       __isl_take isl_map *map2)
+{
+       if (!map1 || !map2)
+               goto error;
+       if (!isl_space_is_equal(map1->dim, map2->dim))
+               isl_die(isl_map_get_ctx(map1), isl_error_invalid,
+                       "spaces don't match", goto error);
+       return map_intersect_internal(map1, map2);
+error:
+       isl_map_free(map1);
+       isl_map_free(map2);
+       return NULL;
+}
+
 __isl_give isl_map *isl_map_intersect(__isl_take isl_map *map1,
        __isl_take isl_map *map2)
 {
@@ -2510,13 +2841,13 @@ struct isl_set *isl_set_intersect(struct isl_set *set1, struct isl_set *set2)
                                  (struct isl_map *)set2);
 }
 
-/* The current implementation of isl_map_intersect accepts intersections
- * with parameter domains, so we can just call that for now.
+/* map_intersect_internal accepts intersections
+ * with parameter domains, so we can just call that function.
  */
 static __isl_give isl_map *map_intersect_params(__isl_take isl_map *map,
                __isl_take isl_set *params)
 {
-       return isl_map_intersect(map, params);
+       return map_intersect_internal(map, params);
 }
 
 __isl_give isl_map *isl_map_intersect_params(__isl_take isl_map *map1,
@@ -2533,7 +2864,7 @@ __isl_give isl_set *isl_set_intersect_params(__isl_take isl_set *set,
 
 struct isl_basic_map *isl_basic_map_reverse(struct isl_basic_map *bmap)
 {
-       struct isl_dim *dim;
+       isl_space *dim;
        struct isl_basic_set *bset;
        unsigned in;
 
@@ -2542,29 +2873,43 @@ struct isl_basic_map *isl_basic_map_reverse(struct isl_basic_map *bmap)
        bmap = isl_basic_map_cow(bmap);
        if (!bmap)
                return NULL;
-       dim = isl_dim_reverse(isl_dim_copy(bmap->dim));
+       dim = isl_space_reverse(isl_space_copy(bmap->dim));
        in = isl_basic_map_n_in(bmap);
        bset = isl_basic_set_from_basic_map(bmap);
        bset = isl_basic_set_swap_vars(bset, in);
        return isl_basic_map_from_basic_set(bset, dim);
 }
 
+static __isl_give isl_basic_map *basic_map_space_reset(
+       __isl_take isl_basic_map *bmap, enum isl_dim_type type)
+{
+       isl_space *space;
+
+       if (!isl_space_is_named_or_nested(bmap->dim, type))
+               return bmap;
+
+       space = isl_basic_map_get_space(bmap);
+       space = isl_space_reset(space, type);
+       bmap = isl_basic_map_reset_space(bmap, space);
+       return bmap;
+}
+
 __isl_give isl_basic_map *isl_basic_map_insert(__isl_take isl_basic_map *bmap,
                enum isl_dim_type type, unsigned pos, unsigned n)
 {
-       struct isl_dim *res_dim;
+       isl_space *res_dim;
        struct isl_basic_map *res;
        struct isl_dim_map *dim_map;
        unsigned total, off;
        enum isl_dim_type t;
 
        if (n == 0)
-               return bmap;
+               return basic_map_space_reset(bmap, type);
 
        if (!bmap)
                return NULL;
 
-       res_dim = isl_dim_insert(isl_basic_map_get_dim(bmap), type, pos, n);
+       res_dim = isl_space_insert_dims(isl_basic_map_get_space(bmap), type, pos, n);
 
        total = isl_basic_map_total_dim(bmap) + n;
        dim_map = isl_dim_map_alloc(bmap->ctx, total);
@@ -2579,14 +2924,18 @@ __isl_give isl_basic_map *isl_basic_map_insert(__isl_take isl_basic_map *bmap,
                        isl_dim_map_dim_range(dim_map, bmap->dim, t,
                                                pos, size - pos, off + pos + n);
                }
-               off += isl_dim_size(res_dim, t);
+               off += isl_space_dim(res_dim, t);
        }
        isl_dim_map_div(dim_map, bmap, off);
 
-       res = isl_basic_map_alloc_dim(res_dim,
+       res = isl_basic_map_alloc_space(res_dim,
                        bmap->n_div, bmap->n_eq, bmap->n_ineq);
        if (isl_basic_map_is_rational(bmap))
                res = isl_basic_map_set_rational(res);
+       if (isl_basic_map_plain_is_empty(bmap)) {
+               isl_basic_map_free(bmap);
+               return isl_basic_map_set_to_empty(res);
+       }
        res = isl_basic_map_add_constraints_dim_map(res, bmap, dim_map);
        return isl_basic_map_finalize(res);
 }
@@ -2612,19 +2961,33 @@ error:
        return NULL;
 }
 
+static __isl_give isl_map *map_space_reset(__isl_take isl_map *map,
+       enum isl_dim_type type)
+{
+       isl_space *space;
+
+       if (!map || !isl_space_is_named_or_nested(map->dim, type))
+               return map;
+
+       space = isl_map_get_space(map);
+       space = isl_space_reset(space, type);
+       map = isl_map_reset_space(map, space);
+       return map;
+}
+
 __isl_give isl_map *isl_map_insert_dims(__isl_take isl_map *map,
                enum isl_dim_type type, unsigned pos, unsigned n)
 {
        int i;
 
        if (n == 0)
-               return map;
+               return map_space_reset(map, type);
 
        map = isl_map_cow(map);
        if (!map)
                return NULL;
 
-       map->dim = isl_dim_insert(map->dim, type, pos, n);
+       map->dim = isl_space_insert_dims(map->dim, type, pos, n);
        if (!map->dim)
                goto error;
 
@@ -2696,7 +3059,7 @@ __isl_give isl_basic_map *isl_basic_map_move_dims(
                if (!bmap)
                        return NULL;
 
-               bmap->dim = isl_dim_move(bmap->dim, dst_type, dst_pos,
+               bmap->dim = isl_space_move_dims(bmap->dim, dst_type, dst_pos,
                                                src_type, src_pos, n);
                if (!bmap->dim)
                        goto error;
@@ -2711,7 +3074,7 @@ __isl_give isl_basic_map *isl_basic_map_move_dims(
 
        off = 0;
        for (t = isl_dim_param; t <= isl_dim_out; ++t) {
-               unsigned size = isl_dim_size(bmap->dim, t);
+               unsigned size = isl_space_dim(bmap->dim, t);
                if (t == dst_type) {
                        isl_dim_map_dim_range(dim_map, bmap->dim, t,
                                            0, dst_pos, off);
@@ -2736,11 +3099,11 @@ __isl_give isl_basic_map *isl_basic_map_move_dims(
        }
        isl_dim_map_div(dim_map, bmap, off);
 
-       res = isl_basic_map_alloc_dim(isl_basic_map_get_dim(bmap),
+       res = isl_basic_map_alloc_space(isl_basic_map_get_space(bmap),
                        bmap->n_div, bmap->n_eq, bmap->n_ineq);
        bmap = isl_basic_map_add_constraints_dim_map(res, bmap, dim_map);
 
-       bmap->dim = isl_dim_move(bmap->dim, dst_type, dst_pos,
+       bmap->dim = isl_space_move_dims(bmap->dim, dst_type, dst_pos,
                                        src_type, src_pos, n);
        if (!bmap->dim)
                goto error;
@@ -2800,7 +3163,7 @@ __isl_give isl_map *isl_map_move_dims(__isl_take isl_map *map,
        if (!map)
                return NULL;
 
-       map->dim = isl_dim_move(map->dim, dst_type, dst_pos, src_type, src_pos, n);
+       map->dim = isl_space_move_dims(map->dim, dst_type, dst_pos, src_type, src_pos, n);
        if (!map->dim)
                goto error;
 
@@ -2832,7 +3195,8 @@ static __isl_give isl_basic_map *move_last(__isl_take isl_basic_map *bmap,
 
        if (!bmap)
                return NULL;
-       if (pos(bmap->dim, type) + first + n == 1 + isl_dim_total(bmap->dim))
+       if (pos(bmap->dim, type) + first + n ==
+                               1 + isl_space_dim(bmap->dim, isl_dim_all))
                return bmap;
 
        total = isl_basic_map_total_dim(bmap);
@@ -2840,7 +3204,7 @@ static __isl_give isl_basic_map *move_last(__isl_take isl_basic_map *bmap,
 
        off = 0;
        for (t = isl_dim_param; t <= isl_dim_out; ++t) {
-               unsigned size = isl_dim_size(bmap->dim, t);
+               unsigned size = isl_space_dim(bmap->dim, t);
                if (t == type) {
                        isl_dim_map_dim_range(dim_map, bmap->dim, t,
                                            0, first, off);
@@ -2857,7 +3221,7 @@ static __isl_give isl_basic_map *move_last(__isl_take isl_basic_map *bmap,
        }
        isl_dim_map_div(dim_map, bmap, off + n);
 
-       res = isl_basic_map_alloc_dim(isl_basic_map_get_dim(bmap),
+       res = isl_basic_map_alloc_space(isl_basic_map_get_space(bmap),
                        bmap->n_div, bmap->n_eq, bmap->n_ineq);
        res = isl_basic_map_add_constraints_dim_map(res, bmap, dim_map);
        return res;
@@ -2876,7 +3240,7 @@ __isl_give isl_basic_map *isl_basic_map_project_out(
        isl_int *old;
 
        if (n == 0)
-               return bmap;
+               return basic_map_space_reset(bmap, type);
 
        if (!bmap)
                return NULL;
@@ -2892,7 +3256,7 @@ __isl_give isl_basic_map *isl_basic_map_project_out(
        if (!bmap)
                return NULL;
 
-       row_size = 1 + isl_dim_total(bmap->dim) + bmap->extra;
+       row_size = 1 + isl_space_dim(bmap->dim, isl_dim_all) + bmap->extra;
        old = bmap->block2.data;
        bmap->block2 = isl_blk_extend(bmap->ctx, bmap->block2,
                                        (bmap->extra + n) * (1 + row_size));
@@ -2913,7 +3277,7 @@ __isl_give isl_basic_map *isl_basic_map_project_out(
        bmap->n_div += n;
        bmap->extra += n;
 
-       bmap->dim = isl_dim_drop(bmap->dim, type, first, n);
+       bmap->dim = isl_space_drop_dims(bmap->dim, type, first, n);
        if (!bmap->dim)
                goto error;
        bmap = isl_basic_map_simplify(bmap);
@@ -2946,7 +3310,7 @@ __isl_give isl_map *isl_map_project_out(__isl_take isl_map *map,
                return NULL;
 
        if (n == 0)
-               return map;
+               return map_space_reset(map, type);
 
        isl_assert(map->ctx, first + n <= isl_map_dim(map, type), goto error);
 
@@ -2954,7 +3318,7 @@ __isl_give isl_map *isl_map_project_out(__isl_take isl_map *map,
        if (!map)
                return NULL;
 
-       map->dim = isl_dim_drop(map->dim, type, first, n);
+       map->dim = isl_space_drop_dims(map->dim, type, first, n);
        if (!map->dim)
                goto error;
 
@@ -2998,7 +3362,7 @@ error:
 struct isl_basic_map *isl_basic_map_apply_range(
                struct isl_basic_map *bmap1, struct isl_basic_map *bmap2)
 {
-       struct isl_dim *dim_result = NULL;
+       isl_space *dim_result = NULL;
        struct isl_basic_map *bmap;
        unsigned n_in, n_out, n, nparam, total, pos;
        struct isl_dim_map *dim_map1, *dim_map2;
@@ -3006,8 +3370,8 @@ struct isl_basic_map *isl_basic_map_apply_range(
        if (!bmap1 || !bmap2)
                goto error;
 
-       dim_result = isl_dim_join(isl_dim_copy(bmap1->dim),
-                                 isl_dim_copy(bmap2->dim));
+       dim_result = isl_space_join(isl_space_copy(bmap1->dim),
+                                 isl_space_copy(bmap2->dim));
 
        n_in = isl_basic_map_n_in(bmap1);
        n_out = isl_basic_map_n_out(bmap2);
@@ -3026,7 +3390,7 @@ struct isl_basic_map *isl_basic_map_apply_range(
        isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_out, pos += bmap2->n_div);
        isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_in, pos);
 
-       bmap = isl_basic_map_alloc_dim(dim_result,
+       bmap = isl_basic_map_alloc_space(dim_result,
                        bmap1->n_div + bmap2->n_div + n,
                        bmap1->n_eq + bmap2->n_eq,
                        bmap1->n_ineq + bmap2->n_ineq);
@@ -3094,7 +3458,7 @@ struct isl_basic_map *isl_basic_map_sum(
        if (!bmap1 || !bmap2)
                goto error;
 
-       isl_assert(bmap1->ctx, isl_dim_equal(bmap1->dim, bmap2->dim),
+       isl_assert(bmap1->ctx, isl_space_is_equal(bmap1->dim, bmap2->dim),
                goto error);
 
        nparam = isl_basic_map_n_param(bmap1);
@@ -3113,7 +3477,7 @@ struct isl_basic_map *isl_basic_map_sum(
        isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_out, pos += bmap2->n_div);
        isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_out, pos += n_out);
 
-       bmap = isl_basic_map_alloc_dim(isl_dim_copy(bmap1->dim),
+       bmap = isl_basic_map_alloc_space(isl_space_copy(bmap1->dim),
                        bmap1->n_div + bmap2->n_div + 2 * n_out,
                        bmap1->n_eq + bmap2->n_eq + n_out,
                        bmap1->n_ineq + bmap2->n_ineq);
@@ -3150,9 +3514,9 @@ struct isl_map *isl_map_sum(struct isl_map *map1, struct isl_map *map2)
        if (!map1 || !map2)
                goto error;
 
-       isl_assert(map1->ctx, isl_dim_equal(map1->dim, map2->dim), goto error);
+       isl_assert(map1->ctx, isl_space_is_equal(map1->dim, map2->dim), goto error);
 
-       result = isl_map_alloc_dim(isl_dim_copy(map1->dim),
+       result = isl_map_alloc_space(isl_space_copy(map1->dim),
                                map1->n * map2->n, 0);
        if (!result)
                goto error;
@@ -3206,6 +3570,7 @@ struct isl_basic_map *isl_basic_map_neg(struct isl_basic_map *bmap)
        for (i = 0; i < bmap->n_div; ++i)
                for (j = 0; j < n; ++j)
                        isl_int_neg(bmap->div[i][1+off+j], bmap->div[i][1+off+j]);
+       bmap = isl_basic_map_gauss(bmap, NULL);
        return isl_basic_map_finalize(bmap);
 }
 
@@ -3266,7 +3631,7 @@ struct isl_basic_map *isl_basic_map_floordiv(struct isl_basic_map *bmap,
        isl_dim_map_div(dim_map, bmap, pos += n_in + n_out);
        isl_dim_map_dim(dim_map, bmap->dim, isl_dim_out, pos += bmap->n_div);
 
-       result = isl_basic_map_alloc_dim(isl_dim_copy(bmap->dim),
+       result = isl_basic_map_alloc_space(isl_space_copy(bmap->dim),
                        bmap->n_div + n_out,
                        bmap->n_eq, bmap->n_ineq + 2 * n_out);
        result = isl_basic_map_add_constraints_dim_map(result, bmap, dim_map);
@@ -3432,11 +3797,12 @@ error:
        return NULL;
 }
 
-struct isl_basic_map *isl_basic_map_equal(struct isl_dim *dim, unsigned n_equal)
+__isl_give isl_basic_map *isl_basic_map_equal(
+       __isl_take isl_space *dim, unsigned n_equal)
 {
        int i;
        struct isl_basic_map *bmap;
-       bmap = isl_basic_map_alloc_dim(dim, 0, n_equal, 0);
+       bmap = isl_basic_map_alloc_space(dim, 0, n_equal, 0);
        if (!bmap)
                return NULL;
        for (i = 0; i < n_equal && bmap; ++i)
@@ -3446,11 +3812,12 @@ struct isl_basic_map *isl_basic_map_equal(struct isl_dim *dim, unsigned n_equal)
 
 /* Return a relation on of dimension "dim" expressing i_[0..pos] << o_[0..pos]
  */
-struct isl_basic_map *isl_basic_map_less_at(struct isl_dim *dim, unsigned pos)
+__isl_give isl_basic_map *isl_basic_map_less_at(__isl_take isl_space *dim,
+       unsigned pos)
 {
        int i;
        struct isl_basic_map *bmap;
-       bmap = isl_basic_map_alloc_dim(dim, 0, pos, 1);
+       bmap = isl_basic_map_alloc_space(dim, 0, pos, 1);
        if (!bmap)
                return NULL;
        for (i = 0; i < pos && bmap; ++i)
@@ -3463,12 +3830,12 @@ struct isl_basic_map *isl_basic_map_less_at(struct isl_dim *dim, unsigned pos)
 /* Return a relation on of dimension "dim" expressing i_[0..pos] <<= o_[0..pos]
  */
 __isl_give isl_basic_map *isl_basic_map_less_or_equal_at(
-       __isl_take isl_dim *dim, unsigned pos)
+       __isl_take isl_space *dim, unsigned pos)
 {
        int i;
        isl_basic_map *bmap;
 
-       bmap = isl_basic_map_alloc_dim(dim, 0, pos, 1);
+       bmap = isl_basic_map_alloc_space(dim, 0, pos, 1);
        for (i = 0; i < pos; ++i)
                bmap = var_equal(bmap, i);
        bmap = var_less_or_equal(bmap, pos);
@@ -3477,11 +3844,12 @@ __isl_give isl_basic_map *isl_basic_map_less_or_equal_at(
 
 /* Return a relation on pairs of sets of dimension "dim" expressing i_pos > o_pos
  */
-struct isl_basic_map *isl_basic_map_more_at(struct isl_dim *dim, unsigned pos)
+__isl_give isl_basic_map *isl_basic_map_more_at(__isl_take isl_space *dim,
+       unsigned pos)
 {
        int i;
        struct isl_basic_map *bmap;
-       bmap = isl_basic_map_alloc_dim(dim, 0, pos, 1);
+       bmap = isl_basic_map_alloc_space(dim, 0, pos, 1);
        if (!bmap)
                return NULL;
        for (i = 0; i < pos && bmap; ++i)
@@ -3494,19 +3862,19 @@ struct isl_basic_map *isl_basic_map_more_at(struct isl_dim *dim, unsigned pos)
 /* Return a relation on of dimension "dim" expressing i_[0..pos] >>= o_[0..pos]
  */
 __isl_give isl_basic_map *isl_basic_map_more_or_equal_at(
-       __isl_take isl_dim *dim, unsigned pos)
+       __isl_take isl_space *dim, unsigned pos)
 {
        int i;
        isl_basic_map *bmap;
 
-       bmap = isl_basic_map_alloc_dim(dim, 0, pos, 1);
+       bmap = isl_basic_map_alloc_space(dim, 0, pos, 1);
        for (i = 0; i < pos; ++i)
                bmap = var_equal(bmap, i);
        bmap = var_more_or_equal(bmap, pos);
        return isl_basic_map_finalize(bmap);
 }
 
-static __isl_give isl_map *map_lex_lte_first(__isl_take isl_dim *dims,
+static __isl_give isl_map *map_lex_lte_first(__isl_take isl_space *dims,
        unsigned n, int equal)
 {
        struct isl_map *map;
@@ -3515,11 +3883,11 @@ static __isl_give isl_map *map_lex_lte_first(__isl_take isl_dim *dims,
        if (n == 0 && equal)
                return isl_map_universe(dims);
 
-       map = isl_map_alloc_dim(isl_dim_copy(dims), n, ISL_MAP_DISJOINT);
+       map = isl_map_alloc_space(isl_space_copy(dims), n, ISL_MAP_DISJOINT);
 
        for (i = 0; i + 1 < n; ++i)
                map = isl_map_add_basic_map(map,
-                                 isl_basic_map_less_at(isl_dim_copy(dims), i));
+                                 isl_basic_map_less_at(isl_space_copy(dims), i));
        if (n > 0) {
                if (equal)
                        map = isl_map_add_basic_map(map,
@@ -3528,39 +3896,39 @@ static __isl_give isl_map *map_lex_lte_first(__isl_take isl_dim *dims,
                        map = isl_map_add_basic_map(map,
                              isl_basic_map_less_at(dims, n - 1));
        } else
-               isl_dim_free(dims);
+               isl_space_free(dims);
 
        return map;
 }
 
-static __isl_give isl_map *map_lex_lte(__isl_take isl_dim *dims, int equal)
+static __isl_give isl_map *map_lex_lte(__isl_take isl_space *dims, int equal)
 {
        if (!dims)
                return NULL;
        return map_lex_lte_first(dims, dims->n_out, equal);
 }
 
-__isl_give isl_map *isl_map_lex_lt_first(__isl_take isl_dim *dim, unsigned n)
+__isl_give isl_map *isl_map_lex_lt_first(__isl_take isl_space *dim, unsigned n)
 {
        return map_lex_lte_first(dim, n, 0);
 }
 
-__isl_give isl_map *isl_map_lex_le_first(__isl_take isl_dim *dim, unsigned n)
+__isl_give isl_map *isl_map_lex_le_first(__isl_take isl_space *dim, unsigned n)
 {
        return map_lex_lte_first(dim, n, 1);
 }
 
-__isl_give isl_map *isl_map_lex_lt(__isl_take isl_dim *set_dim)
+__isl_give isl_map *isl_map_lex_lt(__isl_take isl_space *set_dim)
 {
-       return map_lex_lte(isl_dim_map_from_set(set_dim), 0);
+       return map_lex_lte(isl_space_map_from_set(set_dim), 0);
 }
 
-__isl_give isl_map *isl_map_lex_le(__isl_take isl_dim *set_dim)
+__isl_give isl_map *isl_map_lex_le(__isl_take isl_space *set_dim)
 {
-       return map_lex_lte(isl_dim_map_from_set(set_dim), 1);
+       return map_lex_lte(isl_space_map_from_set(set_dim), 1);
 }
 
-static __isl_give isl_map *map_lex_gte_first(__isl_take isl_dim *dims,
+static __isl_give isl_map *map_lex_gte_first(__isl_take isl_space *dims,
        unsigned n, int equal)
 {
        struct isl_map *map;
@@ -3569,11 +3937,11 @@ static __isl_give isl_map *map_lex_gte_first(__isl_take isl_dim *dims,
        if (n == 0 && equal)
                return isl_map_universe(dims);
 
-       map = isl_map_alloc_dim(isl_dim_copy(dims), n, ISL_MAP_DISJOINT);
+       map = isl_map_alloc_space(isl_space_copy(dims), n, ISL_MAP_DISJOINT);
 
        for (i = 0; i + 1 < n; ++i)
                map = isl_map_add_basic_map(map,
-                                 isl_basic_map_more_at(isl_dim_copy(dims), i));
+                                 isl_basic_map_more_at(isl_space_copy(dims), i));
        if (n > 0) {
                if (equal)
                        map = isl_map_add_basic_map(map,
@@ -3582,43 +3950,43 @@ static __isl_give isl_map *map_lex_gte_first(__isl_take isl_dim *dims,
                        map = isl_map_add_basic_map(map,
                              isl_basic_map_more_at(dims, n - 1));
        } else
-               isl_dim_free(dims);
+               isl_space_free(dims);
 
        return map;
 }
 
-static __isl_give isl_map *map_lex_gte(__isl_take isl_dim *dims, int equal)
+static __isl_give isl_map *map_lex_gte(__isl_take isl_space *dims, int equal)
 {
        if (!dims)
                return NULL;
        return map_lex_gte_first(dims, dims->n_out, equal);
 }
 
-__isl_give isl_map *isl_map_lex_gt_first(__isl_take isl_dim *dim, unsigned n)
+__isl_give isl_map *isl_map_lex_gt_first(__isl_take isl_space *dim, unsigned n)
 {
        return map_lex_gte_first(dim, n, 0);
 }
 
-__isl_give isl_map *isl_map_lex_ge_first(__isl_take isl_dim *dim, unsigned n)
+__isl_give isl_map *isl_map_lex_ge_first(__isl_take isl_space *dim, unsigned n)
 {
        return map_lex_gte_first(dim, n, 1);
 }
 
-__isl_give isl_map *isl_map_lex_gt(__isl_take isl_dim *set_dim)
+__isl_give isl_map *isl_map_lex_gt(__isl_take isl_space *set_dim)
 {
-       return map_lex_gte(isl_dim_map_from_set(set_dim), 0);
+       return map_lex_gte(isl_space_map_from_set(set_dim), 0);
 }
 
-__isl_give isl_map *isl_map_lex_ge(__isl_take isl_dim *set_dim)
+__isl_give isl_map *isl_map_lex_ge(__isl_take isl_space *set_dim)
 {
-       return map_lex_gte(isl_dim_map_from_set(set_dim), 1);
+       return map_lex_gte(isl_space_map_from_set(set_dim), 1);
 }
 
 __isl_give isl_map *isl_set_lex_le_set(__isl_take isl_set *set1,
        __isl_take isl_set *set2)
 {
        isl_map *map;
-       map = isl_map_lex_le(isl_set_get_dim(set1));
+       map = isl_map_lex_le(isl_set_get_space(set1));
        map = isl_map_intersect_domain(map, set1);
        map = isl_map_intersect_range(map, set2);
        return map;
@@ -3628,7 +3996,7 @@ __isl_give isl_map *isl_set_lex_lt_set(__isl_take isl_set *set1,
        __isl_take isl_set *set2)
 {
        isl_map *map;
-       map = isl_map_lex_lt(isl_set_get_dim(set1));
+       map = isl_map_lex_lt(isl_set_get_space(set1));
        map = isl_map_intersect_domain(map, set1);
        map = isl_map_intersect_range(map, set2);
        return map;
@@ -3638,7 +4006,7 @@ __isl_give isl_map *isl_set_lex_ge_set(__isl_take isl_set *set1,
        __isl_take isl_set *set2)
 {
        isl_map *map;
-       map = isl_map_lex_ge(isl_set_get_dim(set1));
+       map = isl_map_lex_ge(isl_set_get_space(set1));
        map = isl_map_intersect_domain(map, set1);
        map = isl_map_intersect_range(map, set2);
        return map;
@@ -3648,7 +4016,7 @@ __isl_give isl_map *isl_set_lex_gt_set(__isl_take isl_set *set1,
        __isl_take isl_set *set2)
 {
        isl_map *map;
-       map = isl_map_lex_gt(isl_set_get_dim(set1));
+       map = isl_map_lex_gt(isl_set_get_space(set1));
        map = isl_map_intersect_domain(map, set1);
        map = isl_map_intersect_range(map, set2);
        return map;
@@ -3658,7 +4026,7 @@ __isl_give isl_map *isl_map_lex_le_map(__isl_take isl_map *map1,
        __isl_take isl_map *map2)
 {
        isl_map *map;
-       map = isl_map_lex_le(isl_dim_range(isl_map_get_dim(map1)));
+       map = isl_map_lex_le(isl_space_range(isl_map_get_space(map1)));
        map = isl_map_apply_domain(map, isl_map_reverse(map1));
        map = isl_map_apply_range(map, isl_map_reverse(map2));
        return map;
@@ -3668,7 +4036,7 @@ __isl_give isl_map *isl_map_lex_lt_map(__isl_take isl_map *map1,
        __isl_take isl_map *map2)
 {
        isl_map *map;
-       map = isl_map_lex_lt(isl_dim_range(isl_map_get_dim(map1)));
+       map = isl_map_lex_lt(isl_space_range(isl_map_get_space(map1)));
        map = isl_map_apply_domain(map, isl_map_reverse(map1));
        map = isl_map_apply_range(map, isl_map_reverse(map2));
        return map;
@@ -3678,7 +4046,7 @@ __isl_give isl_map *isl_map_lex_ge_map(__isl_take isl_map *map1,
        __isl_take isl_map *map2)
 {
        isl_map *map;
-       map = isl_map_lex_ge(isl_dim_range(isl_map_get_dim(map1)));
+       map = isl_map_lex_ge(isl_space_range(isl_map_get_space(map1)));
        map = isl_map_apply_domain(map, isl_map_reverse(map1));
        map = isl_map_apply_range(map, isl_map_reverse(map2));
        return map;
@@ -3688,14 +4056,14 @@ __isl_give isl_map *isl_map_lex_gt_map(__isl_take isl_map *map1,
        __isl_take isl_map *map2)
 {
        isl_map *map;
-       map = isl_map_lex_gt(isl_dim_range(isl_map_get_dim(map1)));
+       map = isl_map_lex_gt(isl_space_range(isl_map_get_space(map1)));
        map = isl_map_apply_domain(map, isl_map_reverse(map1));
        map = isl_map_apply_range(map, isl_map_reverse(map2));
        return map;
 }
 
-struct isl_basic_map *isl_basic_map_from_basic_set(
-               struct isl_basic_set *bset, struct isl_dim *dim)
+__isl_give isl_basic_map *isl_basic_map_from_basic_set(
+       __isl_take isl_basic_set *bset, __isl_take isl_space *dim)
 {
        struct isl_basic_map *bmap;
 
@@ -3703,14 +4071,14 @@ struct isl_basic_map *isl_basic_map_from_basic_set(
        if (!bset || !dim)
                goto error;
 
-       isl_assert(bset->ctx, isl_dim_compatible(bset->dim, dim), goto error);
-       isl_dim_free(bset->dim);
+       isl_assert(bset->ctx, isl_space_compatible(bset->dim, dim), goto error);
+       isl_space_free(bset->dim);
        bmap = (struct isl_basic_map *) bset;
        bmap->dim = dim;
        return isl_basic_map_finalize(bmap);
 error:
        isl_basic_set_free(bset);
-       isl_dim_free(dim);
+       isl_space_free(dim);
        return NULL;
 }
 
@@ -3723,7 +4091,7 @@ struct isl_basic_set *isl_basic_set_from_basic_map(struct isl_basic_map *bmap)
        bmap = isl_basic_map_cow(bmap);
        if (!bmap)
                goto error;
-       bmap->dim = isl_dim_as_set_dim(bmap->dim);
+       bmap->dim = isl_space_as_set_space(bmap->dim);
        if (!bmap->dim)
                goto error;
        bmap = isl_basic_map_finalize(bmap);
@@ -3786,13 +4154,13 @@ struct isl_basic_set *isl_basic_map_underlying_set(
                goto error;
        if (bmap->dim->nparam == 0 && bmap->dim->n_in == 0 &&
            bmap->n_div == 0 &&
-           !isl_dim_is_named_or_nested(bmap->dim, isl_dim_in) &&
-           !isl_dim_is_named_or_nested(bmap->dim, isl_dim_out))
+           !isl_space_is_named_or_nested(bmap->dim, isl_dim_in) &&
+           !isl_space_is_named_or_nested(bmap->dim, isl_dim_out))
                return (struct isl_basic_set *)bmap;
        bmap = isl_basic_map_cow(bmap);
        if (!bmap)
                goto error;
-       bmap->dim = isl_dim_underlying(bmap->dim, bmap->n_div);
+       bmap->dim = isl_space_underlying(bmap->dim, bmap->n_div);
        if (!bmap->dim)
                goto error;
        bmap->extra -= bmap->n_div;
@@ -3824,7 +4192,7 @@ struct isl_basic_map *isl_basic_map_overlying_set(
        isl_assert(ctx, isl_basic_set_n_param(bset) == 0, goto error);
        isl_assert(ctx, bset->dim->n_out == isl_basic_map_total_dim(like),
                        goto error);
-       if (isl_dim_equal(bset->dim, like->dim) && like->n_div == 0) {
+       if (isl_space_is_equal(bset->dim, like->dim) && like->n_div == 0) {
                isl_basic_map_free(like);
                return (struct isl_basic_map *)bset;
        }
@@ -3833,8 +4201,8 @@ struct isl_basic_map *isl_basic_map_overlying_set(
                goto error;
        total = bset->dim->n_out + bset->extra;
        bmap = (struct isl_basic_map *)bset;
-       isl_dim_free(bmap->dim);
-       bmap->dim = isl_dim_copy(like->dim);
+       isl_space_free(bmap->dim);
+       bmap->dim = isl_space_copy(like->dim);
        if (!bmap->dim)
                goto error;
        bmap->n_div = like->n_div;
@@ -3894,7 +4262,7 @@ struct isl_set *isl_set_from_underlying_set(
                goto error;
        isl_assert(set->ctx, set->dim->n_out == isl_basic_set_total_dim(like),
                    goto error);
-       if (isl_dim_equal(set->dim, like->dim) && like->n_div == 0) {
+       if (isl_space_is_equal(set->dim, like->dim) && like->n_div == 0) {
                isl_basic_set_free(like);
                return set;
        }
@@ -3907,8 +4275,8 @@ struct isl_set *isl_set_from_underlying_set(
                if (!set->p[i])
                        goto error;
        }
-       isl_dim_free(set->dim);
-       set->dim = isl_dim_copy(like->dim);
+       isl_space_free(set->dim);
+       set->dim = isl_space_copy(like->dim);
        if (!set->dim)
                goto error;
        isl_basic_set_free(like);
@@ -3926,7 +4294,7 @@ struct isl_set *isl_map_underlying_set(struct isl_map *map)
        map = isl_map_cow(map);
        if (!map)
                return NULL;
-       map->dim = isl_dim_cow(map->dim);
+       map->dim = isl_space_cow(map->dim);
        if (!map->dim)
                goto error;
 
@@ -3940,10 +4308,10 @@ struct isl_set *isl_map_underlying_set(struct isl_map *map)
                        goto error;
        }
        if (map->n == 0)
-               map->dim = isl_dim_underlying(map->dim, 0);
+               map->dim = isl_space_underlying(map->dim, 0);
        else {
-               isl_dim_free(map->dim);
-               map->dim = isl_dim_copy(map->p[0]->dim);
+               isl_space_free(map->dim);
+               map->dim = isl_space_copy(map->p[0]->dim);
        }
        if (!map->dim)
                goto error;
@@ -3958,14 +4326,14 @@ struct isl_set *isl_set_to_underlying_set(struct isl_set *set)
        return (struct isl_set *)isl_map_underlying_set((struct isl_map *)set);
 }
 
-__isl_give isl_basic_map *isl_basic_map_reset_dim(
-       __isl_take isl_basic_map *bmap, __isl_take isl_dim *dim)
+__isl_give isl_basic_map *isl_basic_map_reset_space(
+       __isl_take isl_basic_map *bmap, __isl_take isl_space *dim)
 {
        bmap = isl_basic_map_cow(bmap);
        if (!bmap || !dim)
                goto error;
 
-       isl_dim_free(bmap->dim);
+       isl_space_free(bmap->dim);
        bmap->dim = dim;
 
        bmap = isl_basic_map_finalize(bmap);
@@ -3973,19 +4341,19 @@ __isl_give isl_basic_map *isl_basic_map_reset_dim(
        return bmap;
 error:
        isl_basic_map_free(bmap);
-       isl_dim_free(dim);
+       isl_space_free(dim);
        return NULL;
 }
 
-__isl_give isl_basic_set *isl_basic_set_reset_dim(
-       __isl_take isl_basic_set *bset, __isl_take isl_dim *dim)
+__isl_give isl_basic_set *isl_basic_set_reset_space(
+       __isl_take isl_basic_set *bset, __isl_take isl_space *dim)
 {
-       return (isl_basic_set *)isl_basic_map_reset_dim((isl_basic_map *)bset,
+       return (isl_basic_set *)isl_basic_map_reset_space((isl_basic_map *)bset,
                                                        dim);
 }
 
-__isl_give isl_map *isl_map_reset_dim(__isl_take isl_map *map,
-       __isl_take isl_dim *dim)
+__isl_give isl_map *isl_map_reset_space(__isl_take isl_map *map,
+       __isl_take isl_space *dim)
 {
        int i;
 
@@ -3994,44 +4362,108 @@ __isl_give isl_map *isl_map_reset_dim(__isl_take isl_map *map,
                goto error;
 
        for (i = 0; i < map->n; ++i) {
-               map->p[i] = isl_basic_map_reset_dim(map->p[i],
-                                                   isl_dim_copy(dim));
+               map->p[i] = isl_basic_map_reset_space(map->p[i],
+                                                   isl_space_copy(dim));
                if (!map->p[i])
                        goto error;
        }
-       isl_dim_free(map->dim);
+       isl_space_free(map->dim);
        map->dim = dim;
 
        return map;
 error:
        isl_map_free(map);
-       isl_dim_free(dim);
+       isl_space_free(dim);
        return NULL;
 }
 
-__isl_give isl_set *isl_set_reset_dim(__isl_take isl_set *set,
-       __isl_take isl_dim *dim)
+__isl_give isl_set *isl_set_reset_space(__isl_take isl_set *set,
+       __isl_take isl_space *dim)
+{
+       return (struct isl_set *) isl_map_reset_space((struct isl_map *)set, dim);
+}
+
+/* Compute the parameter domain of the given basic set.
+ */
+__isl_give isl_basic_set *isl_basic_set_params(__isl_take isl_basic_set *bset)
+{
+       isl_space *space;
+       unsigned n;
+
+       if (isl_basic_set_is_params(bset))
+               return bset;
+
+       n = isl_basic_set_dim(bset, isl_dim_set);
+       bset = isl_basic_set_project_out(bset, isl_dim_set, 0, n);
+       space = isl_basic_set_get_space(bset);
+       space = isl_space_params(space);
+       bset = isl_basic_set_reset_space(bset, space);
+       return bset;
+}
+
+/* Compute the parameter domain of the given set.
+ */
+__isl_give isl_set *isl_set_params(__isl_take isl_set *set)
+{
+       isl_space *space;
+       unsigned n;
+
+       if (isl_set_is_params(set))
+               return set;
+
+       n = isl_set_dim(set, isl_dim_set);
+       set = isl_set_project_out(set, isl_dim_set, 0, n);
+       space = isl_set_get_space(set);
+       space = isl_space_params(space);
+       set = isl_set_reset_space(set, space);
+       return set;
+}
+
+/* Construct a zero-dimensional set with the given parameter domain.
+ */
+__isl_give isl_set *isl_set_from_params(__isl_take isl_set *set)
 {
-       return (struct isl_set *) isl_map_reset_dim((struct isl_map *)set, dim);
+       isl_space *space;
+       space = isl_set_get_space(set);
+       space = isl_space_set_from_params(space);
+       set = isl_set_reset_space(set, space);
+       return set;
+}
+
+/* Compute the parameter domain of the given map.
+ */
+__isl_give isl_set *isl_map_params(__isl_take isl_map *map)
+{
+       isl_space *space;
+       unsigned n;
+
+       n = isl_map_dim(map, isl_dim_in);
+       map = isl_map_project_out(map, isl_dim_in, 0, n);
+       n = isl_map_dim(map, isl_dim_out);
+       map = isl_map_project_out(map, isl_dim_out, 0, n);
+       space = isl_map_get_space(map);
+       space = isl_space_params(space);
+       map = isl_map_reset_space(map, space);
+       return map;
 }
 
 struct isl_basic_set *isl_basic_map_domain(struct isl_basic_map *bmap)
 {
-       isl_dim *dim;
+       isl_space *dim;
        struct isl_basic_set *domain;
        unsigned n_in;
        unsigned n_out;
 
        if (!bmap)
                return NULL;
-       dim = isl_dim_domain(isl_basic_map_get_dim(bmap));
+       dim = isl_space_domain(isl_basic_map_get_space(bmap));
 
        n_in = isl_basic_map_n_in(bmap);
        n_out = isl_basic_map_n_out(bmap);
        domain = isl_basic_set_from_basic_map(bmap);
        domain = isl_basic_set_project_out(domain, isl_dim_set, n_in, n_out);
 
-       domain = isl_basic_set_reset_dim(domain, dim);
+       domain = isl_basic_set_reset_space(domain, dim);
 
        return domain;
 }
@@ -4040,14 +4472,25 @@ int isl_basic_map_may_be_set(__isl_keep isl_basic_map *bmap)
 {
        if (!bmap)
                return -1;
-       return isl_dim_may_be_set(bmap->dim);
+       return isl_space_may_be_set(bmap->dim);
+}
+
+/* Is this basic map actually a set?
+ * Users should never call this function.  Outside of isl,
+ * the type should indicate whether something is a set or a map.
+ */
+int isl_basic_map_is_set(__isl_keep isl_basic_map *bmap)
+{
+       if (!bmap)
+               return -1;
+       return isl_space_is_set(bmap->dim);
 }
 
 struct isl_basic_set *isl_basic_map_range(struct isl_basic_map *bmap)
 {
        if (!bmap)
                return NULL;
-       if (isl_basic_map_may_be_set(bmap))
+       if (isl_basic_map_is_set(bmap))
                return bmap;
        return isl_basic_map_domain(isl_basic_map_reverse(bmap));
 }
@@ -4056,7 +4499,7 @@ __isl_give isl_basic_map *isl_basic_map_domain_map(
        __isl_take isl_basic_map *bmap)
 {
        int i, k;
-       isl_dim *dim;
+       isl_space *dim;
        isl_basic_map *domain;
        int nparam, n_in, n_out;
        unsigned total;
@@ -4065,7 +4508,7 @@ __isl_give isl_basic_map *isl_basic_map_domain_map(
        n_in = isl_basic_map_dim(bmap, isl_dim_in);
        n_out = isl_basic_map_dim(bmap, isl_dim_out);
 
-       dim = isl_dim_from_range(isl_dim_domain(isl_basic_map_get_dim(bmap)));
+       dim = isl_space_from_range(isl_space_domain(isl_basic_map_get_space(bmap)));
        domain = isl_basic_map_universe(dim);
 
        bmap = isl_basic_map_from_domain(isl_basic_map_wrap(bmap));
@@ -4094,7 +4537,7 @@ __isl_give isl_basic_map *isl_basic_map_range_map(
        __isl_take isl_basic_map *bmap)
 {
        int i, k;
-       isl_dim *dim;
+       isl_space *dim;
        isl_basic_map *range;
        int nparam, n_in, n_out;
        unsigned total;
@@ -4103,7 +4546,7 @@ __isl_give isl_basic_map *isl_basic_map_range_map(
        n_in = isl_basic_map_dim(bmap, isl_dim_in);
        n_out = isl_basic_map_dim(bmap, isl_dim_out);
 
-       dim = isl_dim_from_range(isl_dim_range(isl_basic_map_get_dim(bmap)));
+       dim = isl_space_from_range(isl_space_range(isl_basic_map_get_space(bmap)));
        range = isl_basic_map_universe(dim);
 
        bmap = isl_basic_map_from_domain(isl_basic_map_wrap(bmap));
@@ -4132,7 +4575,18 @@ int isl_map_may_be_set(__isl_keep isl_map *map)
 {
        if (!map)
                return -1;
-       return isl_dim_may_be_set(map->dim);
+       return isl_space_may_be_set(map->dim);
+}
+
+/* Is this map actually a set?
+ * Users should never call this function.  Outside of isl,
+ * the type should indicate whether something is a set or a map.
+ */
+int isl_map_is_set(__isl_keep isl_map *map)
+{
+       if (!map)
+               return -1;
+       return isl_space_is_set(map->dim);
 }
 
 struct isl_set *isl_map_range(struct isl_map *map)
@@ -4142,7 +4596,7 @@ struct isl_set *isl_map_range(struct isl_map *map)
 
        if (!map)
                goto error;
-       if (isl_map_may_be_set(map))
+       if (isl_map_is_set(map))
                return (isl_set *)map;
 
        map = isl_map_cow(map);
@@ -4150,7 +4604,7 @@ struct isl_set *isl_map_range(struct isl_map *map)
                goto error;
 
        set = (struct isl_set *) map;
-       set->dim = isl_dim_drop_inputs(set->dim, 0, set->dim->n_in);
+       set->dim = isl_space_range(set->dim);
        if (!set->dim)
                goto error;
        for (i = 0; i < map->n; ++i) {
@@ -4169,15 +4623,15 @@ error:
 __isl_give isl_map *isl_map_domain_map(__isl_take isl_map *map)
 {
        int i;
-       isl_dim *domain_dim;
+       isl_space *domain_dim;
 
        map = isl_map_cow(map);
        if (!map)
                return NULL;
 
-       domain_dim = isl_dim_from_range(isl_dim_domain(isl_map_get_dim(map)));
-       map->dim = isl_dim_from_domain(isl_dim_wrap(map->dim));
-       map->dim = isl_dim_join(map->dim, domain_dim);
+       domain_dim = isl_space_from_range(isl_space_domain(isl_map_get_space(map)));
+       map->dim = isl_space_from_domain(isl_space_wrap(map->dim));
+       map->dim = isl_space_join(map->dim, domain_dim);
        if (!map->dim)
                goto error;
        for (i = 0; i < map->n; ++i) {
@@ -4196,15 +4650,16 @@ error:
 __isl_give isl_map *isl_map_range_map(__isl_take isl_map *map)
 {
        int i;
-       isl_dim *range_dim;
+       isl_space *range_dim;
 
        map = isl_map_cow(map);
        if (!map)
                return NULL;
 
-       range_dim = isl_dim_range(isl_map_get_dim(map));
-       map->dim = isl_dim_from_domain(isl_dim_wrap(map->dim));
-       map->dim = isl_dim_join(map->dim, range_dim);
+       range_dim = isl_space_range(isl_map_get_space(map));
+       range_dim = isl_space_from_range(range_dim);
+       map->dim = isl_space_from_domain(isl_space_wrap(map->dim));
+       map->dim = isl_space_join(map->dim, range_dim);
        if (!map->dim)
                goto error;
        for (i = 0; i < map->n; ++i) {
@@ -4220,7 +4675,8 @@ error:
        return NULL;
 }
 
-struct isl_map *isl_map_from_set(struct isl_set *set, struct isl_dim *dim)
+__isl_give isl_map *isl_map_from_set(__isl_take isl_set *set,
+       __isl_take isl_space *dim)
 {
        int i;
        struct isl_map *map = NULL;
@@ -4228,19 +4684,19 @@ struct isl_map *isl_map_from_set(struct isl_set *set, struct isl_dim *dim)
        set = isl_set_cow(set);
        if (!set || !dim)
                goto error;
-       isl_assert(set->ctx, isl_dim_compatible(set->dim, dim), goto error);
+       isl_assert(set->ctx, isl_space_compatible(set->dim, dim), goto error);
        map = (struct isl_map *)set;
        for (i = 0; i < set->n; ++i) {
                map->p[i] = isl_basic_map_from_basic_set(
-                               set->p[i], isl_dim_copy(dim));
+                               set->p[i], isl_space_copy(dim));
                if (!map->p[i])
                        goto error;
        }
-       isl_dim_free(map->dim);
+       isl_space_free(map->dim);
        map->dim = dim;
        return map;
 error:
-       isl_dim_free(dim);
+       isl_space_free(dim);
        isl_set_free(set);
        return NULL;
 }
@@ -4254,11 +4710,19 @@ __isl_give isl_basic_map *isl_basic_map_from_domain(
 __isl_give isl_basic_map *isl_basic_map_from_range(
        __isl_take isl_basic_set *bset)
 {
+       isl_space *space;
+       space = isl_basic_set_get_space(bset);
+       space = isl_space_from_range(space);
+       bset = isl_basic_set_reset_space(bset, space);
        return (isl_basic_map *)bset;
 }
 
 struct isl_map *isl_map_from_range(struct isl_set *set)
 {
+       isl_space *space;
+       space = isl_set_get_space(set);
+       space = isl_space_from_range(space);
+       set = isl_set_reset_space(set, space);
        return (struct isl_map *)set;
 }
 
@@ -4270,15 +4734,13 @@ __isl_give isl_map *isl_map_from_domain(__isl_take isl_set *set)
 __isl_give isl_basic_map *isl_basic_map_from_domain_and_range(
        __isl_take isl_basic_set *domain, __isl_take isl_basic_set *range)
 {
-       return isl_basic_map_apply_range(isl_basic_map_from_domain(domain),
-                                        isl_basic_map_from_range(range));
+       return isl_basic_map_apply_range(isl_basic_map_reverse(domain), range);
 }
 
 __isl_give isl_map *isl_map_from_domain_and_range(__isl_take isl_set *domain,
        __isl_take isl_set *range)
 {
-       return isl_map_apply_range(isl_map_from_domain(domain),
-                                  isl_map_from_range(range));
+       return isl_map_apply_range(isl_map_reverse(domain), range);
 }
 
 struct isl_set *isl_set_from_map(struct isl_map *map)
@@ -4291,7 +4753,7 @@ struct isl_set *isl_set_from_map(struct isl_map *map)
        map = isl_map_cow(map);
        if (!map)
                return NULL;
-       map->dim = isl_dim_as_set_dim(map->dim);
+       map->dim = isl_space_as_set_space(map->dim);
        if (!map->dim)
                goto error;
        set = (struct isl_set *)map;
@@ -4306,13 +4768,16 @@ error:
        return NULL;
 }
 
-struct isl_map *isl_map_alloc_dim(struct isl_dim *dim, int n, unsigned flags)
+__isl_give isl_map *isl_map_alloc_space(__isl_take isl_space *dim, int n,
+       unsigned flags)
 {
        struct isl_map *map;
 
        if (!dim)
                return NULL;
-       isl_assert(dim->ctx, n >= 0, return NULL);
+       if (n < 0)
+               isl_die(dim->ctx, isl_error_internal,
+                       "negative number of basic maps", goto error);
        map = isl_alloc(dim->ctx, struct isl_map,
                        sizeof(struct isl_map) +
                        (n - 1) * sizeof(struct isl_basic_map *));
@@ -4328,7 +4793,7 @@ struct isl_map *isl_map_alloc_dim(struct isl_dim *dim, int n, unsigned flags)
        map->flags = flags;
        return map;
 error:
-       isl_dim_free(dim);
+       isl_space_free(dim);
        return NULL;
 }
 
@@ -4337,28 +4802,28 @@ struct isl_map *isl_map_alloc(struct isl_ctx *ctx,
                unsigned flags)
 {
        struct isl_map *map;
-       struct isl_dim *dims;
+       isl_space *dims;
 
-       dims = isl_dim_alloc(ctx, nparam, in, out);
+       dims = isl_space_alloc(ctx, nparam, in, out);
        if (!dims)
                return NULL;
 
-       map = isl_map_alloc_dim(dims, n, flags);
+       map = isl_map_alloc_space(dims, n, flags);
        return map;
 }
 
-struct isl_basic_map *isl_basic_map_empty(struct isl_dim *dim)
+__isl_give isl_basic_map *isl_basic_map_empty(__isl_take isl_space *dim)
 {
        struct isl_basic_map *bmap;
-       bmap = isl_basic_map_alloc_dim(dim, 0, 1, 0);
+       bmap = isl_basic_map_alloc_space(dim, 0, 1, 0);
        bmap = isl_basic_map_set_to_empty(bmap);
        return bmap;
 }
 
-struct isl_basic_set *isl_basic_set_empty(struct isl_dim *dim)
+__isl_give isl_basic_set *isl_basic_set_empty(__isl_take isl_space *dim)
 {
        struct isl_basic_set *bset;
-       bset = isl_basic_set_alloc_dim(dim, 0, 1, 0);
+       bset = isl_basic_set_alloc_space(dim, 0, 1, 0);
        bset = isl_basic_set_set_to_empty(bset);
        return bset;
 }
@@ -4368,7 +4833,7 @@ struct isl_basic_map *isl_basic_map_empty_like(struct isl_basic_map *model)
        struct isl_basic_map *bmap;
        if (!model)
                return NULL;
-       bmap = isl_basic_map_alloc_dim(isl_dim_copy(model->dim), 0, 1, 0);
+       bmap = isl_basic_map_alloc_space(isl_space_copy(model->dim), 0, 1, 0);
        bmap = isl_basic_map_set_to_empty(bmap);
        return bmap;
 }
@@ -4378,7 +4843,7 @@ struct isl_basic_map *isl_basic_map_empty_like_map(struct isl_map *model)
        struct isl_basic_map *bmap;
        if (!model)
                return NULL;
-       bmap = isl_basic_map_alloc_dim(isl_dim_copy(model->dim), 0, 1, 0);
+       bmap = isl_basic_map_alloc_space(isl_space_copy(model->dim), 0, 1, 0);
        bmap = isl_basic_map_set_to_empty(bmap);
        return bmap;
 }
@@ -4388,34 +4853,34 @@ struct isl_basic_set *isl_basic_set_empty_like(struct isl_basic_set *model)
        struct isl_basic_set *bset;
        if (!model)
                return NULL;
-       bset = isl_basic_set_alloc_dim(isl_dim_copy(model->dim), 0, 1, 0);
+       bset = isl_basic_set_alloc_space(isl_space_copy(model->dim), 0, 1, 0);
        bset = isl_basic_set_set_to_empty(bset);
        return bset;
 }
 
-struct isl_basic_map *isl_basic_map_universe(struct isl_dim *dim)
+__isl_give isl_basic_map *isl_basic_map_universe(__isl_take isl_space *dim)
 {
        struct isl_basic_map *bmap;
-       bmap = isl_basic_map_alloc_dim(dim, 0, 0, 0);
+       bmap = isl_basic_map_alloc_space(dim, 0, 0, 0);
        bmap = isl_basic_map_finalize(bmap);
        return bmap;
 }
 
-struct isl_basic_set *isl_basic_set_universe(struct isl_dim *dim)
+__isl_give isl_basic_set *isl_basic_set_universe(__isl_take isl_space *dim)
 {
        struct isl_basic_set *bset;
-       bset = isl_basic_set_alloc_dim(dim, 0, 0, 0);
+       bset = isl_basic_set_alloc_space(dim, 0, 0, 0);
        bset = isl_basic_set_finalize(bset);
        return bset;
 }
 
-__isl_give isl_basic_map *isl_basic_map_nat_universe(__isl_take isl_dim *dim)
+__isl_give isl_basic_map *isl_basic_map_nat_universe(__isl_take isl_space *dim)
 {
        int i;
-       unsigned total = isl_dim_total(dim);
+       unsigned total = isl_space_dim(dim, isl_dim_all);
        isl_basic_map *bmap;
 
-       bmap= isl_basic_map_alloc_dim(dim, 0, 0, total);
+       bmap= isl_basic_map_alloc_space(dim, 0, 0, total);
        for (i = 0; i < total; ++i) {
                int k = isl_basic_map_alloc_inequality(bmap);
                if (k < 0)
@@ -4429,17 +4894,17 @@ error:
        return NULL;
 }
 
-__isl_give isl_basic_set *isl_basic_set_nat_universe(__isl_take isl_dim *dim)
+__isl_give isl_basic_set *isl_basic_set_nat_universe(__isl_take isl_space *dim)
 {
        return isl_basic_map_nat_universe(dim);
 }
 
-__isl_give isl_map *isl_map_nat_universe(__isl_take isl_dim *dim)
+__isl_give isl_map *isl_map_nat_universe(__isl_take isl_space *dim)
 {
        return isl_map_from_basic_map(isl_basic_map_nat_universe(dim));
 }
 
-__isl_give isl_set *isl_set_nat_universe(__isl_take isl_dim *dim)
+__isl_give isl_set *isl_set_nat_universe(__isl_take isl_space *dim)
 {
        return isl_map_nat_universe(dim);
 }
@@ -4449,14 +4914,14 @@ __isl_give isl_basic_map *isl_basic_map_universe_like(
 {
        if (!model)
                return NULL;
-       return isl_basic_map_alloc_dim(isl_dim_copy(model->dim), 0, 0, 0);
+       return isl_basic_map_alloc_space(isl_space_copy(model->dim), 0, 0, 0);
 }
 
 struct isl_basic_set *isl_basic_set_universe_like(struct isl_basic_set *model)
 {
        if (!model)
                return NULL;
-       return isl_basic_set_alloc_dim(isl_dim_copy(model->dim), 0, 0, 0);
+       return isl_basic_set_alloc_space(isl_space_copy(model->dim), 0, 0, 0);
 }
 
 __isl_give isl_basic_set *isl_basic_set_universe_like_set(
@@ -4464,56 +4929,56 @@ __isl_give isl_basic_set *isl_basic_set_universe_like_set(
 {
        if (!model)
                return NULL;
-       return isl_basic_set_alloc_dim(isl_dim_copy(model->dim), 0, 0, 0);
+       return isl_basic_set_alloc_space(isl_space_copy(model->dim), 0, 0, 0);
 }
 
-struct isl_map *isl_map_empty(struct isl_dim *dim)
+__isl_give isl_map *isl_map_empty(__isl_take isl_space *dim)
 {
-       return isl_map_alloc_dim(dim, 0, ISL_MAP_DISJOINT);
+       return isl_map_alloc_space(dim, 0, ISL_MAP_DISJOINT);
 }
 
 struct isl_map *isl_map_empty_like(struct isl_map *model)
 {
        if (!model)
                return NULL;
-       return isl_map_alloc_dim(isl_dim_copy(model->dim), 0, ISL_MAP_DISJOINT);
+       return isl_map_alloc_space(isl_space_copy(model->dim), 0, ISL_MAP_DISJOINT);
 }
 
 struct isl_map *isl_map_empty_like_basic_map(struct isl_basic_map *model)
 {
        if (!model)
                return NULL;
-       return isl_map_alloc_dim(isl_dim_copy(model->dim), 0, ISL_MAP_DISJOINT);
+       return isl_map_alloc_space(isl_space_copy(model->dim), 0, ISL_MAP_DISJOINT);
 }
 
-struct isl_set *isl_set_empty(struct isl_dim *dim)
+__isl_give isl_set *isl_set_empty(__isl_take isl_space *dim)
 {
-       return isl_set_alloc_dim(dim, 0, ISL_MAP_DISJOINT);
+       return isl_set_alloc_space(dim, 0, ISL_MAP_DISJOINT);
 }
 
 struct isl_set *isl_set_empty_like(struct isl_set *model)
 {
        if (!model)
                return NULL;
-       return isl_set_empty(isl_dim_copy(model->dim));
+       return isl_set_empty(isl_space_copy(model->dim));
 }
 
-struct isl_map *isl_map_universe(struct isl_dim *dim)
+__isl_give isl_map *isl_map_universe(__isl_take isl_space *dim)
 {
        struct isl_map *map;
        if (!dim)
                return NULL;
-       map = isl_map_alloc_dim(isl_dim_copy(dim), 1, ISL_MAP_DISJOINT);
+       map = isl_map_alloc_space(isl_space_copy(dim), 1, ISL_MAP_DISJOINT);
        map = isl_map_add_basic_map(map, isl_basic_map_universe(dim));
        return map;
 }
 
-struct isl_set *isl_set_universe(struct isl_dim *dim)
+__isl_give isl_set *isl_set_universe(__isl_take isl_space *dim)
 {
        struct isl_set *set;
        if (!dim)
                return NULL;
-       set = isl_set_alloc_dim(isl_dim_copy(dim), 1, ISL_MAP_DISJOINT);
+       set = isl_set_alloc_space(isl_space_copy(dim), 1, ISL_MAP_DISJOINT);
        set = isl_set_add_basic_set(set, isl_basic_set_universe(dim));
        return set;
 }
@@ -4522,7 +4987,7 @@ __isl_give isl_set *isl_set_universe_like(__isl_keep isl_set *model)
 {
        if (!model)
                return NULL;
-       return isl_set_universe(isl_dim_copy(model->dim));
+       return isl_set_universe(isl_space_copy(model->dim));
 }
 
 struct isl_map *isl_map_dup(struct isl_map *map)
@@ -4532,7 +4997,7 @@ struct isl_map *isl_map_dup(struct isl_map *map)
 
        if (!map)
                return NULL;
-       dup = isl_map_alloc_dim(isl_dim_copy(map->dim), map->n, map->flags);
+       dup = isl_map_alloc_space(isl_space_copy(map->dim), map->n, map->flags);
        for (i = 0; i < map->n; ++i)
                dup = isl_map_add_basic_map(dup, isl_basic_map_copy(map->p[i]));
        return dup;
@@ -4547,7 +5012,7 @@ __isl_give isl_map *isl_map_add_basic_map(__isl_take isl_map *map,
                isl_basic_map_free(bmap);
                return map;
        }
-       isl_assert(map->ctx, isl_dim_equal(map->dim, bmap->dim), goto error);
+       isl_assert(map->ctx, isl_space_is_equal(map->dim, bmap->dim), goto error);
        isl_assert(map->ctx, map->n < map->size, goto error);
        map->p[map->n] = bmap;
        map->n++;
@@ -4574,7 +5039,7 @@ void isl_map_free(struct isl_map *map)
        isl_ctx_deref(map->ctx);
        for (i = 0; i < map->n; ++i)
                isl_basic_map_free(map->p[i]);
-       isl_dim_free(map->dim);
+       isl_space_free(map->dim);
        free(map);
 }
 
@@ -4587,12 +5052,12 @@ struct isl_map *isl_map_extend(struct isl_map *base,
        if (!base)
                return NULL;
 
-       base->dim = isl_dim_extend(base->dim, nparam, n_in, n_out);
+       base->dim = isl_space_extend(base->dim, nparam, n_in, n_out);
        if (!base->dim)
                goto error;
        for (i = 0; i < base->n; ++i) {
-               base->p[i] = isl_basic_map_extend_dim(base->p[i],
-                               isl_dim_copy(base->dim), 0, 0, 0);
+               base->p[i] = isl_basic_map_extend_space(base->p[i],
+                               isl_space_copy(base->dim), 0, 0, 0);
                if (!base->p[i])
                        goto error;
        }
@@ -4705,19 +5170,38 @@ struct isl_basic_set *isl_basic_set_fix_dim_si(struct isl_basic_set *bset,
                                        isl_dim_set, dim, value);
 }
 
-struct isl_map *isl_map_fix_si(struct isl_map *map,
-               enum isl_dim_type type, unsigned pos, int value)
+static int remove_if_empty(__isl_keep isl_map *map, int i)
 {
-       int i;
+       int empty = isl_basic_map_plain_is_empty(map->p[i]);
 
-       map = isl_map_cow(map);
-       if (!map)
+       if (empty < 0)
+               return -1;
+       if (!empty)
+               return 0;
+
+       isl_basic_map_free(map->p[i]);
+       if (i != map->n - 1) {
+               ISL_F_CLR(map, ISL_MAP_NORMALIZED);
+               map->p[i] = map->p[map->n - 1];
+       }
+       map->n--;
+
+       return 0;
+}
+
+struct isl_map *isl_map_fix_si(struct isl_map *map,
+               enum isl_dim_type type, unsigned pos, int value)
+{
+       int i;
+
+       map = isl_map_cow(map);
+       if (!map)
                return NULL;
 
        isl_assert(map->ctx, pos < isl_map_dim(map, type), goto error);
-       for (i = 0; i < map->n; ++i) {
+       for (i = map->n - 1; i >= 0; --i) {
                map->p[i] = isl_basic_map_fix_si(map->p[i], type, pos, value);
-               if (!map->p[i])
+               if (remove_if_empty(map, i) < 0)
                        goto error;
        }
        ISL_F_CLR(map, ISL_MAP_NORMALIZED);
@@ -4774,9 +5258,9 @@ struct isl_set *isl_set_fix_dim_si(struct isl_set *set, unsigned dim, int value)
                isl_map_fix_si((struct isl_map *)set, isl_dim_set, dim, value);
 }
 
-__isl_give isl_basic_map *isl_basic_map_lower_bound_si(
-               __isl_take isl_basic_map *bmap,
-               enum isl_dim_type type, unsigned pos, int value)
+static __isl_give isl_basic_map *basic_map_bound_si(
+       __isl_take isl_basic_map *bmap,
+       enum isl_dim_type type, unsigned pos, int value, int upper)
 {
        int j;
 
@@ -4790,8 +5274,13 @@ __isl_give isl_basic_map *isl_basic_map_lower_bound_si(
        if (j < 0)
                goto error;
        isl_seq_clr(bmap->ineq[j], 1 + isl_basic_map_total_dim(bmap));
-       isl_int_set_si(bmap->ineq[j][pos], 1);
-       isl_int_set_si(bmap->ineq[j][0], -value);
+       if (upper) {
+               isl_int_set_si(bmap->ineq[j][pos], -1);
+               isl_int_set_si(bmap->ineq[j][0], value);
+       } else {
+               isl_int_set_si(bmap->ineq[j][pos], 1);
+               isl_int_set_si(bmap->ineq[j][0], -value);
+       }
        bmap = isl_basic_map_simplify(bmap);
        return isl_basic_map_finalize(bmap);
 error:
@@ -4799,6 +5288,13 @@ error:
        return NULL;
 }
 
+__isl_give isl_basic_map *isl_basic_map_lower_bound_si(
+       __isl_take isl_basic_map *bmap,
+       enum isl_dim_type type, unsigned pos, int value)
+{
+       return basic_map_bound_si(bmap, type, pos, value, 0);
+}
+
 struct isl_basic_set *isl_basic_set_lower_bound_dim(struct isl_basic_set *bset,
        unsigned dim, isl_int value)
 {
@@ -4819,8 +5315,8 @@ error:
        return NULL;
 }
 
-__isl_give isl_map *isl_map_lower_bound_si(__isl_take isl_map *map,
-               enum isl_dim_type type, unsigned pos, int value)
+static __isl_give isl_map *map_bound_si(__isl_take isl_map *map,
+       enum isl_dim_type type, unsigned pos, int value, int upper)
 {
        int i;
 
@@ -4830,8 +5326,8 @@ __isl_give isl_map *isl_map_lower_bound_si(__isl_take isl_map *map,
 
        isl_assert(map->ctx, pos < isl_map_dim(map, type), goto error);
        for (i = 0; i < map->n; ++i) {
-               map->p[i] = isl_basic_map_lower_bound_si(map->p[i],
-                                                        type, pos, value);
+               map->p[i] = basic_map_bound_si(map->p[i],
+                                                type, pos, value, upper);
                if (!map->p[i])
                        goto error;
        }
@@ -4842,6 +5338,18 @@ error:
        return NULL;
 }
 
+__isl_give isl_map *isl_map_lower_bound_si(__isl_take isl_map *map,
+       enum isl_dim_type type, unsigned pos, int value)
+{
+       return map_bound_si(map, type, pos, value, 0);
+}
+
+__isl_give isl_map *isl_map_upper_bound_si(__isl_take isl_map *map,
+       enum isl_dim_type type, unsigned pos, int value)
+{
+       return map_bound_si(map, type, pos, value, 1);
+}
+
 __isl_give isl_set *isl_set_lower_bound_si(__isl_take isl_set *set,
                enum isl_dim_type type, unsigned pos, int value)
 {
@@ -4849,6 +5357,98 @@ __isl_give isl_set *isl_set_lower_bound_si(__isl_take isl_set *set,
                isl_map_lower_bound_si((struct isl_map *)set, type, pos, value);
 }
 
+__isl_give isl_set *isl_set_upper_bound_si(__isl_take isl_set *set,
+       enum isl_dim_type type, unsigned pos, int value)
+{
+       return isl_map_upper_bound_si(set, type, pos, value);
+}
+
+/* Bound the given variable of "bmap" from below (or above is "upper"
+ * is set) to "value".
+ */
+static __isl_give isl_basic_map *basic_map_bound(
+       __isl_take isl_basic_map *bmap,
+       enum isl_dim_type type, unsigned pos, isl_int value, int upper)
+{
+       int j;
+
+       if (!bmap)
+               return NULL;
+       if (pos >= isl_basic_map_dim(bmap, type))
+               isl_die(bmap->ctx, isl_error_invalid,
+                       "index out of bounds", goto error);
+       pos += isl_basic_map_offset(bmap, type);
+       bmap = isl_basic_map_cow(bmap);
+       bmap = isl_basic_map_extend_constraints(bmap, 0, 1);
+       j = isl_basic_map_alloc_inequality(bmap);
+       if (j < 0)
+               goto error;
+       isl_seq_clr(bmap->ineq[j], 1 + isl_basic_map_total_dim(bmap));
+       if (upper) {
+               isl_int_set_si(bmap->ineq[j][pos], -1);
+               isl_int_set(bmap->ineq[j][0], value);
+       } else {
+               isl_int_set_si(bmap->ineq[j][pos], 1);
+               isl_int_neg(bmap->ineq[j][0], value);
+       }
+       bmap = isl_basic_map_simplify(bmap);
+       return isl_basic_map_finalize(bmap);
+error:
+       isl_basic_map_free(bmap);
+       return NULL;
+}
+
+/* Bound the given variable of "map" from below (or above is "upper"
+ * is set) to "value".
+ */
+static __isl_give isl_map *map_bound(__isl_take isl_map *map,
+       enum isl_dim_type type, unsigned pos, isl_int value, int upper)
+{
+       int i;
+
+       map = isl_map_cow(map);
+       if (!map)
+               return NULL;
+
+       if (pos >= isl_map_dim(map, type))
+               isl_die(map->ctx, isl_error_invalid,
+                       "index out of bounds", goto error);
+       for (i = map->n - 1; i >= 0; --i) {
+               map->p[i] = basic_map_bound(map->p[i], type, pos, value, upper);
+               if (remove_if_empty(map, i) < 0)
+                       goto error;
+       }
+       ISL_F_CLR(map, ISL_MAP_NORMALIZED);
+       return map;
+error:
+       isl_map_free(map);
+       return NULL;
+}
+
+__isl_give isl_map *isl_map_lower_bound(__isl_take isl_map *map,
+       enum isl_dim_type type, unsigned pos, isl_int value)
+{
+       return map_bound(map, type, pos, value, 0);
+}
+
+__isl_give isl_map *isl_map_upper_bound(__isl_take isl_map *map,
+       enum isl_dim_type type, unsigned pos, isl_int value)
+{
+       return map_bound(map, type, pos, value, 1);
+}
+
+__isl_give isl_set *isl_set_lower_bound(__isl_take isl_set *set,
+       enum isl_dim_type type, unsigned pos, isl_int value)
+{
+       return isl_map_lower_bound(set, type, pos, value);
+}
+
+__isl_give isl_set *isl_set_upper_bound(__isl_take isl_set *set,
+       enum isl_dim_type type, unsigned pos, isl_int value)
+{
+       return isl_map_upper_bound(set, type, pos, value);
+}
+
 struct isl_set *isl_set_lower_bound_dim(struct isl_set *set, unsigned dim,
                                        isl_int value)
 {
@@ -4878,7 +5478,7 @@ struct isl_map *isl_map_reverse(struct isl_map *map)
        if (!map)
                return NULL;
 
-       map->dim = isl_dim_reverse(map->dim);
+       map->dim = isl_space_reverse(map->dim);
        if (!map->dim)
                goto error;
        for (i = 0; i < map->n; ++i) {
@@ -4943,6 +5543,56 @@ struct isl_set *isl_basic_set_partial_lexmax(
                        dom, empty);
 }
 
+__isl_give isl_pw_multi_aff *isl_basic_map_partial_lexmin_pw_multi_aff(
+       __isl_take isl_basic_map *bmap, __isl_take isl_basic_set *dom,
+       __isl_give isl_set **empty)
+{
+       return isl_basic_map_partial_lexopt_pw_multi_aff(bmap, dom, empty, 0);
+}
+
+__isl_give isl_pw_multi_aff *isl_basic_map_partial_lexmax_pw_multi_aff(
+       __isl_take isl_basic_map *bmap, __isl_take isl_basic_set *dom,
+       __isl_give isl_set **empty)
+{
+       return isl_basic_map_partial_lexopt_pw_multi_aff(bmap, dom, empty, 1);
+}
+
+__isl_give isl_pw_multi_aff *isl_basic_set_partial_lexmin_pw_multi_aff(
+       __isl_take isl_basic_set *bset, __isl_take isl_basic_set *dom,
+       __isl_give isl_set **empty)
+{
+       return isl_basic_map_partial_lexmin_pw_multi_aff(bset, dom, empty);
+}
+
+__isl_give isl_pw_multi_aff *isl_basic_set_partial_lexmax_pw_multi_aff(
+       __isl_take isl_basic_set *bset, __isl_take isl_basic_set *dom,
+       __isl_give isl_set **empty)
+{
+       return isl_basic_map_partial_lexmax_pw_multi_aff(bset, dom, empty);
+}
+
+__isl_give isl_pw_multi_aff *isl_basic_map_lexopt_pw_multi_aff(
+       __isl_take isl_basic_map *bmap, int max)
+{
+       isl_basic_set *dom = NULL;
+       isl_space *dom_space;
+
+       if (!bmap)
+               goto error;
+       dom_space = isl_space_domain(isl_space_copy(bmap->dim));
+       dom = isl_basic_set_universe(dom_space);
+       return isl_basic_map_partial_lexopt_pw_multi_aff(bmap, dom, NULL, max);
+error:
+       isl_basic_map_free(bmap);
+       return NULL;
+}
+
+__isl_give isl_pw_multi_aff *isl_basic_map_lexmin_pw_multi_aff(
+       __isl_take isl_basic_map *bmap)
+{
+       return isl_basic_map_lexopt_pw_multi_aff(bmap, 0);
+}
+
 /* Given a basic map "bmap", compute the lexicographically minimal
  * (or maximal) image element for each domain element in dom.
  * Set *empty to those elements in dom that do not have an image element.
@@ -5048,7 +5698,7 @@ error:
  * even when the domain of basic map i is disjoint from the domains of
  * the previous basic maps.
  */
-static __isl_give isl_map *isl_map_partial_lexopt(
+static __isl_give isl_map *isl_map_partial_lexopt_aligned(
                __isl_take isl_map *map, __isl_take isl_set *dom,
                __isl_give isl_set **empty, int max)
 {
@@ -5074,16 +5724,16 @@ static __isl_give isl_map *isl_map_partial_lexopt(
                isl_map *lt, *le;
                isl_map *res_i;
                isl_set *todo_i;
-               isl_dim *dim = isl_dim_range(isl_map_get_dim(res));
+               isl_space *dim = isl_space_range(isl_map_get_space(res));
 
                res_i = basic_map_partial_lexopt(isl_basic_map_copy(map->p[i]),
                                        isl_set_copy(dom), &todo_i, max);
 
                if (max) {
-                       lt = isl_map_lex_lt(isl_dim_copy(dim));
+                       lt = isl_map_lex_lt(isl_space_copy(dim));
                        le = isl_map_lex_le(dim);
                } else {
-                       lt = isl_map_lex_gt(isl_dim_copy(dim));
+                       lt = isl_map_lex_gt(isl_space_copy(dim));
                        le = isl_map_lex_ge(dim);
                }
                lt = isl_map_apply_range(isl_map_copy(res), lt);
@@ -5122,6 +5772,35 @@ error:
        return NULL;
 }
 
+/* Given a map "map", compute the lexicographically minimal
+ * (or maximal) image element for each domain element in dom.
+ * Set *empty to those elements in dom that do not have an image element.
+ *
+ * Align parameters if needed and then call isl_map_partial_lexopt_aligned.
+ */
+static __isl_give isl_map *isl_map_partial_lexopt(
+               __isl_take isl_map *map, __isl_take isl_set *dom,
+               __isl_give isl_set **empty, int max)
+{
+       if (!map || !dom)
+               goto error;
+       if (isl_space_match(map->dim, isl_dim_param, dom->dim, isl_dim_param))
+               return isl_map_partial_lexopt_aligned(map, dom, empty, max);
+       if (!isl_space_has_named_params(map->dim) ||
+           !isl_space_has_named_params(dom->dim))
+               isl_die(map->ctx, isl_error_invalid,
+                       "unaligned unnamed parameters", goto error);
+       map = isl_map_align_params(map, isl_map_get_space(dom));
+       dom = isl_map_align_params(dom, isl_map_get_space(map));
+       return isl_map_partial_lexopt_aligned(map, dom, empty, max);
+error:
+       if (empty)
+               *empty = NULL;
+       isl_set_free(dom);
+       isl_map_free(map);
+       return NULL;
+}
+
 __isl_give isl_map *isl_map_partial_lexmax(
                __isl_take isl_map *map, __isl_take isl_set *dom,
                __isl_give isl_set **empty)
@@ -5157,11 +5836,11 @@ __isl_give isl_set *isl_set_partial_lexmax(
 __isl_give isl_map *isl_basic_map_lexopt(__isl_take isl_basic_map *bmap, int max)
 {
        struct isl_basic_set *dom = NULL;
-       struct isl_dim *dom_dim;
+       isl_space *dom_dim;
 
        if (!bmap)
                goto error;
-       dom_dim = isl_dim_domain(isl_dim_copy(bmap->dim));
+       dom_dim = isl_space_domain(isl_space_copy(bmap->dim));
        dom = isl_basic_set_universe(dom_dim);
        return isl_basic_map_partial_lexopt(bmap, dom, NULL, max);
 error:
@@ -5192,11 +5871,11 @@ __isl_give isl_set *isl_basic_set_lexmax(__isl_take isl_basic_set *bset)
 __isl_give isl_map *isl_map_lexopt(__isl_take isl_map *map, int max)
 {
        struct isl_set *dom = NULL;
-       struct isl_dim *dom_dim;
+       isl_space *dom_dim;
 
        if (!map)
                goto error;
-       dom_dim = isl_dim_domain(isl_dim_copy(map->dim));
+       dom_dim = isl_space_domain(isl_space_copy(map->dim));
        dom = isl_set_universe(dom_dim);
        return isl_map_partial_lexopt(map, dom, NULL, max);
 error:
@@ -5224,37 +5903,12 @@ __isl_give isl_set *isl_set_lexmax(__isl_take isl_set *set)
        return (isl_set *)isl_map_lexmax((isl_map *)set);
 }
 
-/* Construct a map that equates the two given dimensions in the given space.
- */
-static __isl_give isl_map *equate(__isl_take isl_dim *dim,
-       enum isl_dim_type src_type, int src_pos,
-       enum isl_dim_type dst_type, int dst_pos)
-{
-       isl_basic_map *bmap;
-       int k;
-
-       bmap = isl_basic_map_alloc_dim(dim, 0, 1, 0);
-       k = isl_basic_map_alloc_equality(bmap);
-       if (k < 0)
-               goto error;
-       isl_seq_clr(bmap->eq[k], 1 + isl_basic_map_total_dim(bmap));
-       src_pos += isl_basic_map_offset(bmap, src_type);
-       dst_pos += isl_basic_map_offset(bmap, dst_type);
-       isl_int_set_si(bmap->eq[k][src_pos], 1);
-       isl_int_set_si(bmap->eq[k][dst_pos], -1);
-
-       return isl_map_from_basic_map(bmap);
-error:
-       isl_basic_map_free(bmap);
-       return NULL;
-}
-
 /* Extract the first and only affine expression from list
  * and then add it to *pwaff with the given dom.
  * This domain is known to be disjoint from other domains
- * because of the way isl_basic_set_foreach_lexmax works.
+ * because of the way isl_basic_map_foreach_lexmax works.
  */
-static int update_dim_max(__isl_take isl_basic_set *dom,
+static int update_dim_opt(__isl_take isl_basic_set *dom,
        __isl_take isl_aff_list *list, void *user)
 {
        isl_ctx *ctx = isl_basic_set_get_ctx(dom);
@@ -5280,70 +5934,106 @@ error:
        return -1;
 }
 
-/* Given a one-dimensional basic set, compute the maximum of that
- * dimension as an isl_pw_aff.
+/* Given a basic map with one output dimension, compute the minimum or
+ * maximum of that dimension as an isl_pw_aff.
  *
- * The isl_pw_aff is constructed by having isl_basic_set_foreach_lexmax
- * call update_dim_max on each leaf of the result.
+ * The isl_pw_aff is constructed by having isl_basic_map_foreach_lexopt
+ * call update_dim_opt on each leaf of the result.
  */
-static __isl_give isl_pw_aff *basic_set_dim_max(__isl_keep isl_basic_set *bset)
+static __isl_give isl_pw_aff *basic_map_dim_opt(__isl_keep isl_basic_map *bmap,
+       int max)
 {
-       isl_dim *dim = isl_basic_set_get_dim(bset);
+       isl_space *dim = isl_basic_map_get_space(bmap);
        isl_pw_aff *pwaff;
        int r;
 
-       dim = isl_dim_domain(isl_dim_from_range(dim));
+       dim = isl_space_from_domain(isl_space_domain(dim));
+       dim = isl_space_add_dims(dim, isl_dim_out, 1);
        pwaff = isl_pw_aff_empty(dim);
 
-       r = isl_basic_set_foreach_lexmax(bset, &update_dim_max, &pwaff);
+       r = isl_basic_map_foreach_lexopt(bmap, max, &update_dim_opt, &pwaff);
        if (r < 0)
                return isl_pw_aff_free(pwaff);
 
        return pwaff;
 }
 
-/* Compute the maximum of the given set dimension as a function of the
- * parameters, but independently of the other set dimensions.
+/* Compute the minimum or maximum of the given output dimension
+ * as a function of the parameters and the input dimensions,
+ * but independently of the other output dimensions.
  *
- * We first project the set onto the given dimension and then compute
- * the "lexicographic" maximum in each basic set, combining the results
+ * We first project out the other output dimension and then compute
+ * the "lexicographic" maximum in each basic map, combining the results
  * using isl_pw_aff_union_max.
  */
-__isl_give isl_pw_aff *isl_set_dim_max(__isl_take isl_set *set, int pos)
+static __isl_give isl_pw_aff *map_dim_opt(__isl_take isl_map *map, int pos,
+       int max)
 {
        int i;
-       isl_map *map;
        isl_pw_aff *pwaff;
+       unsigned n_out;
 
-       map = isl_map_from_domain(set);
-       map = isl_map_add_dims(map, isl_dim_out, 1);
-       map = isl_map_intersect(map,
-               equate(isl_map_get_dim(map), isl_dim_in, pos,
-                                            isl_dim_out, 0));
-       set = isl_map_range(map);
-       if (!set)
+       n_out = isl_map_dim(map, isl_dim_out);
+       map = isl_map_project_out(map, isl_dim_out, pos + 1, n_out - (pos + 1));
+       map = isl_map_project_out(map, isl_dim_out, 0, pos);
+       if (!map)
                return NULL;
 
-       if (set->n == 0) {
-               isl_dim *dim = isl_set_get_dim(set);
-               dim = isl_dim_domain(isl_dim_from_range(dim));
-               isl_set_free(set);
+       if (map->n == 0) {
+               isl_space *dim = isl_map_get_space(map);
+               dim = isl_space_domain(isl_space_from_range(dim));
+               isl_map_free(map);
                return isl_pw_aff_empty(dim);
        }
 
-       pwaff = basic_set_dim_max(set->p[0]);
-       for (i = 1; i < set->n; ++i) {
+       pwaff = basic_map_dim_opt(map->p[0], max);
+       for (i = 1; i < map->n; ++i) {
                isl_pw_aff *pwaff_i;
 
-               pwaff_i = basic_set_dim_max(set->p[i]);
-               pwaff = isl_pw_aff_union_max(pwaff, pwaff_i);
+               pwaff_i = basic_map_dim_opt(map->p[i], max);
+               pwaff = isl_pw_aff_union_opt(pwaff, pwaff_i, max);
        }
 
-       isl_set_free(set);
+       isl_map_free(map);
 
        return pwaff;
 }
 
+/* Compute the maximum of the given output dimension as a function of the
+ * parameters and input dimensions, but independently of
+ * the other output dimensions.
+ */
+__isl_give isl_pw_aff *isl_map_dim_max(__isl_take isl_map *map, int pos)
+{
+       return map_dim_opt(map, pos, 1);
+}
+
+/* Compute the minimum or maximum of the given set dimension
+ * as a function of the parameters,
+ * but independently of the other set dimensions.
+ */
+static __isl_give isl_pw_aff *set_dim_opt(__isl_take isl_set *set, int pos,
+       int max)
+{
+       return map_dim_opt(set, pos, max);
+}
+
+/* Compute the maximum of the given set dimension as a function of the
+ * parameters, but independently of the other set dimensions.
+ */
+__isl_give isl_pw_aff *isl_set_dim_max(__isl_take isl_set *set, int pos)
+{
+       return set_dim_opt(set, pos, 1);
+}
+
+/* Compute the minimum of the given set dimension as a function of the
+ * parameters, but independently of the other set dimensions.
+ */
+__isl_give isl_pw_aff *isl_set_dim_min(__isl_take isl_set *set, int pos)
+{
+       return set_dim_opt(set, pos, 0);
+}
+
 /* Apply a preimage specified by "mat" on the parameters of "bset".
  * bset is assumed to have only parameters and divs.
  */
@@ -5355,7 +6045,7 @@ static struct isl_basic_set *basic_set_parameter_preimage(
        if (!bset || !mat)
                goto error;
 
-       bset->dim = isl_dim_cow(bset->dim);
+       bset->dim = isl_space_cow(bset->dim);
        if (!bset->dim)
                goto error;
 
@@ -5383,14 +6073,14 @@ error:
 static struct isl_set *set_parameter_preimage(
        struct isl_set *set, struct isl_mat *mat)
 {
-       struct isl_dim *dim = NULL;
+       isl_space *dim = NULL;
        unsigned nparam;
 
        if (!set || !mat)
                goto error;
 
-       dim = isl_dim_copy(set->dim);
-       dim = isl_dim_cow(dim);
+       dim = isl_space_copy(set->dim);
+       dim = isl_space_cow(dim);
        if (!dim)
                goto error;
 
@@ -5400,20 +6090,20 @@ static struct isl_set *set_parameter_preimage(
 
        dim->nparam = 0;
        dim->n_out = nparam;
-       isl_set_reset_dim(set, dim);
+       isl_set_reset_space(set, dim);
        set = isl_set_preimage(set, mat);
        if (!set)
                goto error2;
-       dim = isl_dim_copy(set->dim);
-       dim = isl_dim_cow(dim);
+       dim = isl_space_copy(set->dim);
+       dim = isl_space_cow(dim);
        if (!dim)
                goto error2;
        dim->nparam = dim->n_out;
        dim->n_out = 0;
-       isl_set_reset_dim(set, dim);
+       isl_set_reset_space(set, dim);
        return set;
 error:
-       isl_dim_free(dim);
+       isl_space_free(dim);
        isl_mat_free(mat);
 error2:
        isl_set_free(set);
@@ -5432,12 +6122,12 @@ static struct isl_basic_set *basic_set_append_equalities(
        if (!bset || !eq)
                goto error;
 
-       bset = isl_basic_set_extend_dim(bset, isl_dim_copy(bset->dim), 0,
+       bset = isl_basic_set_extend_space(bset, isl_space_copy(bset->dim), 0,
                                        eq->n_row, 0);
        if (!bset)
                goto error;
 
-       len = 1 + isl_dim_total(bset->dim) + bset->extra;
+       len = 1 + isl_space_dim(bset->dim, isl_dim_all) + bset->extra;
        for (i = 0; i < eq->n_row; ++i) {
                k = isl_basic_set_alloc_equality(bset);
                if (k < 0)
@@ -5552,7 +6242,7 @@ static struct isl_map *compute_divs(struct isl_basic_map *bmap)
        struct isl_basic_set *bset;
        struct isl_set *set;
        struct isl_map *map;
-       struct isl_dim *dim, *orig_dim = NULL;
+       isl_space *dim, *orig_dim = NULL;
        unsigned         nparam;
        unsigned         n_in;
        unsigned         n_out;
@@ -5564,7 +6254,7 @@ static struct isl_map *compute_divs(struct isl_basic_map *bmap)
        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);
-       dim = isl_dim_set_alloc(bmap->ctx, nparam + n_in + n_out, 0);
+       dim = isl_space_set_alloc(bmap->ctx, nparam + n_in + n_out, 0);
        if (!dim)
                goto error;
 
@@ -5574,7 +6264,7 @@ static struct isl_map *compute_divs(struct isl_basic_map *bmap)
 
        set = parameter_compute_divs(bset);
        map = (struct isl_map *)set;
-       map = isl_map_reset_dim(map, orig_dim);
+       map = isl_map_reset_space(map, orig_dim);
 
        return map;
 error:
@@ -5590,7 +6280,7 @@ int isl_basic_map_divs_known(__isl_keep isl_basic_map *bmap)
        if (!bmap)
                return -1;
 
-       off = isl_dim_total(bmap->dim);
+       off = isl_space_dim(bmap->dim, isl_dim_all);
        for (i = 0; i < bmap->n_div; ++i) {
                if (isl_int_is_zero(bmap->div[i][0]))
                        return 0;
@@ -5705,7 +6395,7 @@ struct isl_set *isl_map_domain(struct isl_map *map)
                return NULL;
 
        set = (struct isl_set *)map;
-       set->dim = isl_dim_domain(set->dim);
+       set->dim = isl_space_domain(set->dim);
        if (!set->dim)
                goto error;
        for (i = 0; i < map->n; ++i) {
@@ -5740,13 +6430,13 @@ static __isl_give isl_map *map_union_disjoint(__isl_take isl_map *map1,
                return map1;
        }
 
-       isl_assert(map1->ctx, isl_dim_equal(map1->dim, map2->dim), goto error);
+       isl_assert(map1->ctx, isl_space_is_equal(map1->dim, map2->dim), goto error);
 
        if (ISL_F_ISSET(map1, ISL_MAP_DISJOINT) &&
            ISL_F_ISSET(map2, ISL_MAP_DISJOINT))
                ISL_FL_SET(flags, ISL_MAP_DISJOINT);
 
-       map = isl_map_alloc_dim(isl_dim_copy(map1->dim),
+       map = isl_map_alloc_space(isl_space_copy(map1->dim),
                                map1->n + map2->n, flags);
        if (!map)
                goto error;
@@ -5812,11 +6502,11 @@ static __isl_give isl_map *map_intersect_range(__isl_take isl_map *map,
        if (!map || !set)
                goto error;
 
-       if (!isl_dim_match(map->dim, isl_dim_param, set->dim, isl_dim_param))
+       if (!isl_space_match(map->dim, isl_dim_param, set->dim, isl_dim_param))
                isl_die(set->ctx, isl_error_invalid,
                        "parameters don't match", goto error);
 
-       if (isl_dim_size(set->dim, isl_dim_set) != 0 &&
+       if (isl_space_dim(set->dim, isl_dim_set) != 0 &&
            !isl_map_compatible_range(map, set))
                isl_die(set->ctx, isl_error_invalid,
                        "incompatible spaces", goto error);
@@ -5830,7 +6520,7 @@ static __isl_give isl_map *map_intersect_range(__isl_take isl_map *map,
            ISL_F_ISSET(set, ISL_MAP_DISJOINT))
                ISL_FL_SET(flags, ISL_MAP_DISJOINT);
 
-       result = isl_map_alloc_dim(isl_dim_copy(map->dim),
+       result = isl_map_alloc_space(isl_space_copy(map->dim),
                                        map->n * set->n, flags);
        if (!result)
                goto error;
@@ -5888,17 +6578,17 @@ __isl_give isl_map *isl_map_apply_domain(__isl_take isl_map *map1,
 static __isl_give isl_map *map_apply_range(__isl_take isl_map *map1,
        __isl_take isl_map *map2)
 {
-       struct isl_dim *dim_result;
+       isl_space *dim_result;
        struct isl_map *result;
        int i, j;
 
        if (!map1 || !map2)
                goto error;
 
-       dim_result = isl_dim_join(isl_dim_copy(map1->dim),
-                                 isl_dim_copy(map2->dim));
+       dim_result = isl_space_join(isl_space_copy(map1->dim),
+                                 isl_space_copy(map2->dim));
 
-       result = isl_map_alloc_dim(dim_result, map1->n * map2->n, 0);
+       result = isl_map_alloc_space(dim_result, map1->n * map2->n, 0);
        if (!result)
                goto error;
        for (i = 0; i < map1->n; ++i)
@@ -5932,7 +6622,7 @@ __isl_give isl_map *isl_map_apply_range(__isl_take isl_map *map1,
  */
 struct isl_basic_set *isl_basic_map_deltas(struct isl_basic_map *bmap)
 {
-       isl_dim *dims, *target_dim;
+       isl_space *dims, *target_dim;
        struct isl_basic_set *bset;
        unsigned dim;
        unsigned nparam;
@@ -5940,17 +6630,17 @@ struct isl_basic_set *isl_basic_map_deltas(struct isl_basic_map *bmap)
 
        if (!bmap)
                goto error;
-       isl_assert(bmap->ctx, isl_dim_tuple_match(bmap->dim, isl_dim_in,
+       isl_assert(bmap->ctx, isl_space_tuple_match(bmap->dim, isl_dim_in,
                                                  bmap->dim, isl_dim_out),
                   goto error);
-       target_dim = isl_dim_domain(isl_basic_map_get_dim(bmap));
+       target_dim = isl_space_domain(isl_basic_map_get_space(bmap));
        dim = isl_basic_map_n_in(bmap);
        nparam = isl_basic_map_n_param(bmap);
        bset = isl_basic_set_from_basic_map(bmap);
        bset = isl_basic_set_cow(bset);
-       dims = isl_basic_set_get_dim(bset);
-       dims = isl_dim_add(dims, isl_dim_set, dim);
-       bset = isl_basic_set_extend_dim(bset, dims, 0, dim, 0);
+       dims = isl_basic_set_get_space(bset);
+       dims = isl_space_add_dims(dims, isl_dim_set, dim);
+       bset = isl_basic_set_extend_space(bset, dims, 0, dim, 0);
        bset = isl_basic_set_swap_vars(bset, 2*dim);
        for (i = 0; i < dim; ++i) {
                int j = isl_basic_map_alloc_equality(
@@ -5963,7 +6653,7 @@ struct isl_basic_set *isl_basic_map_deltas(struct isl_basic_map *bmap)
                isl_int_set_si(bset->eq[j][1+nparam+2*dim+i], -1);
        }
        bset = isl_basic_set_project_out(bset, isl_dim_set, dim, 2*dim);
-       bset = isl_basic_set_reset_dim(bset, target_dim);
+       bset = isl_basic_set_reset_space(bset, target_dim);
        return bset;
 error:
        isl_basic_map_free(bmap);
@@ -5973,21 +6663,21 @@ error:
 /*
  * returns range - domain
  */
-struct isl_set *isl_map_deltas(struct isl_map *map)
+__isl_give isl_set *isl_map_deltas(__isl_take isl_map *map)
 {
        int i;
-       isl_dim *dim;
+       isl_space *dim;
        struct isl_set *result;
 
        if (!map)
                return NULL;
 
-       isl_assert(map->ctx, isl_dim_tuple_match(map->dim, isl_dim_in,
+       isl_assert(map->ctx, isl_space_tuple_match(map->dim, isl_dim_in,
                                                 map->dim, isl_dim_out),
                   goto error);
-       dim = isl_map_get_dim(map);
-       dim = isl_dim_domain(dim);
-       result = isl_set_alloc_dim(dim, map->n, 0);
+       dim = isl_map_get_space(map);
+       dim = isl_space_domain(dim);
+       result = isl_set_alloc_space(dim, map->n, 0);
        if (!result)
                goto error;
        for (i = 0; i < map->n; ++i)
@@ -6007,19 +6697,19 @@ __isl_give isl_basic_map *isl_basic_map_deltas_map(
        __isl_take isl_basic_map *bmap)
 {
        int i, k;
-       isl_dim *dim;
+       isl_space *dim;
        isl_basic_map *domain;
        int nparam, n;
        unsigned total;
 
-       if (!isl_dim_tuple_match(bmap->dim, isl_dim_in, bmap->dim, isl_dim_out))
+       if (!isl_space_tuple_match(bmap->dim, isl_dim_in, bmap->dim, isl_dim_out))
                isl_die(bmap->ctx, isl_error_invalid,
                        "domain and range don't match", goto error);
 
        nparam = isl_basic_map_dim(bmap, isl_dim_param);
        n = isl_basic_map_dim(bmap, isl_dim_in);
 
-       dim = isl_dim_from_range(isl_dim_domain(isl_basic_map_get_dim(bmap)));
+       dim = isl_space_from_range(isl_space_domain(isl_basic_map_get_space(bmap)));
        domain = isl_basic_map_universe(dim);
 
        bmap = isl_basic_map_from_domain(isl_basic_map_wrap(bmap));
@@ -6051,12 +6741,12 @@ error:
 __isl_give isl_map *isl_map_deltas_map(__isl_take isl_map *map)
 {
        int i;
-       isl_dim *domain_dim;
+       isl_space *domain_dim;
 
        if (!map)
                return NULL;
 
-       if (!isl_dim_tuple_match(map->dim, isl_dim_in, map->dim, isl_dim_out))
+       if (!isl_space_tuple_match(map->dim, isl_dim_in, map->dim, isl_dim_out))
                isl_die(map->ctx, isl_error_invalid,
                        "domain and range don't match", goto error);
 
@@ -6064,9 +6754,9 @@ __isl_give isl_map *isl_map_deltas_map(__isl_take isl_map *map)
        if (!map)
                return NULL;
 
-       domain_dim = isl_dim_from_range(isl_dim_domain(isl_map_get_dim(map)));
-       map->dim = isl_dim_from_domain(isl_dim_wrap(map->dim));
-       map->dim = isl_dim_join(map->dim, domain_dim);
+       domain_dim = isl_space_from_range(isl_space_domain(isl_map_get_space(map)));
+       map->dim = isl_space_from_domain(isl_space_wrap(map->dim));
+       map->dim = isl_space_join(map->dim, domain_dim);
        if (!map->dim)
                goto error;
        for (i = 0; i < map->n; ++i) {
@@ -6081,7 +6771,7 @@ error:
        return NULL;
 }
 
-static struct isl_basic_map *basic_map_identity(struct isl_dim *dims)
+__isl_give struct isl_basic_map *basic_map_identity(__isl_take isl_space *dims)
 {
        struct isl_basic_map *bmap;
        unsigned nparam;
@@ -6093,7 +6783,7 @@ static struct isl_basic_map *basic_map_identity(struct isl_dim *dims)
 
        nparam = dims->nparam;
        dim = dims->n_out;
-       bmap = isl_basic_map_alloc_dim(dims, 0, dim, 0);
+       bmap = isl_basic_map_alloc_space(dims, 0, dim, 0);
        if (!bmap)
                goto error;
 
@@ -6111,7 +6801,7 @@ error:
        return NULL;
 }
 
-__isl_give isl_basic_map *isl_basic_map_identity(__isl_take isl_dim *dim)
+__isl_give isl_basic_map *isl_basic_map_identity(__isl_take isl_space *dim)
 {
        if (!dim)
                return NULL;
@@ -6121,7 +6811,7 @@ __isl_give isl_basic_map *isl_basic_map_identity(__isl_take isl_dim *dim)
                        "the same", goto error);
        return basic_map_identity(dim);
 error:
-       isl_dim_free(dim);
+       isl_space_free(dim);
        return NULL;
 }
 
@@ -6129,10 +6819,10 @@ struct isl_basic_map *isl_basic_map_identity_like(struct isl_basic_map *model)
 {
        if (!model || !model->dim)
                return NULL;
-       return isl_basic_map_identity(isl_dim_copy(model->dim));
+       return isl_basic_map_identity(isl_space_copy(model->dim));
 }
 
-__isl_give isl_map *isl_map_identity(__isl_take isl_dim *dim)
+__isl_give isl_map *isl_map_identity(__isl_take isl_space *dim)
 {
        return isl_map_from_basic_map(isl_basic_map_identity(dim));
 }
@@ -6141,39 +6831,40 @@ struct isl_map *isl_map_identity_like(struct isl_map *model)
 {
        if (!model || !model->dim)
                return NULL;
-       return isl_map_identity(isl_dim_copy(model->dim));
+       return isl_map_identity(isl_space_copy(model->dim));
 }
 
 struct isl_map *isl_map_identity_like_basic_map(struct isl_basic_map *model)
 {
        if (!model || !model->dim)
                return NULL;
-       return isl_map_identity(isl_dim_copy(model->dim));
+       return isl_map_identity(isl_space_copy(model->dim));
 }
 
 __isl_give isl_map *isl_set_identity(__isl_take isl_set *set)
 {
-       isl_dim *dim = isl_set_get_dim(set);
+       isl_space *dim = isl_set_get_space(set);
        isl_map *id;
-       id = isl_map_identity(isl_dim_map_from_set(dim));
+       id = isl_map_identity(isl_space_map_from_set(dim));
        return isl_map_intersect_range(id, set);
 }
 
 /* Construct a basic set with all set dimensions having only non-negative
  * values.
  */
-struct isl_basic_set *isl_basic_set_positive_orthant(struct isl_dim *dims)
+__isl_give isl_basic_set *isl_basic_set_positive_orthant(
+       __isl_take isl_space *space)
 {
        int i;
        unsigned nparam;
        unsigned dim;
        struct isl_basic_set *bset;
 
-       if (!dims)
+       if (!space)
                return NULL;
-       nparam = dims->nparam;
-       dim = dims->n_out;
-       bset = isl_basic_set_alloc_dim(dims, 0, 0, dim);
+       nparam = space->nparam;
+       dim = space->n_out;
+       bset = isl_basic_set_alloc_space(space, 0, 0, dim);
        if (!bset)
                return NULL;
        for (i = 0; i < dim; ++i) {
@@ -6191,13 +6882,13 @@ error:
 
 /* Construct the half-space x_pos >= 0.
  */
-static __isl_give isl_basic_set *nonneg_halfspace(__isl_take isl_dim *dim,
+static __isl_give isl_basic_set *nonneg_halfspace(__isl_take isl_space *dim,
        int pos)
 {
        int k;
        isl_basic_set *nonneg;
 
-       nonneg = isl_basic_set_alloc_dim(dim, 0, 0, 1);
+       nonneg = isl_basic_set_alloc_space(dim, 0, 0, 1);
        k = isl_basic_set_alloc_inequality(nonneg);
        if (k < 0)
                goto error;
@@ -6212,12 +6903,12 @@ error:
 
 /* Construct the half-space x_pos <= -1.
  */
-static __isl_give isl_basic_set *neg_halfspace(__isl_take isl_dim *dim, int pos)
+static __isl_give isl_basic_set *neg_halfspace(__isl_take isl_space *dim, int pos)
 {
        int k;
        isl_basic_set *neg;
 
-       neg = isl_basic_set_alloc_dim(dim, 0, 0, 1);
+       neg = isl_basic_set_alloc_space(dim, 0, 0, 1);
        k = isl_basic_set_alloc_inequality(neg);
        if (k < 0)
                goto error;
@@ -6246,9 +6937,9 @@ __isl_give isl_set *isl_set_split_dims(__isl_take isl_set *set,
        isl_assert(set->ctx, first + n <= isl_set_dim(set, type), goto error);
 
        for (i = 0; i < n; ++i) {
-               nonneg = nonneg_halfspace(isl_set_get_dim(set),
+               nonneg = nonneg_halfspace(isl_set_get_space(set),
                                          pos(set->dim, type) + first + i);
-               neg = neg_halfspace(isl_set_get_dim(set),
+               neg = neg_halfspace(isl_set_get_space(set),
                                          pos(set->dim, type) + first + i);
 
                set = isl_set_intersect(set, isl_basic_set_union(nonneg, neg));
@@ -6276,14 +6967,14 @@ static int foreach_orthant(__isl_take isl_set *set, int *signs, int first,
                return fn(set, signs, user);
 
        signs[first] = 1;
-       half = isl_set_from_basic_set(nonneg_halfspace(isl_set_get_dim(set),
+       half = isl_set_from_basic_set(nonneg_halfspace(isl_set_get_space(set),
                                                        1 + first));
        half = isl_set_intersect(half, isl_set_copy(set));
        if (foreach_orthant(half, signs, first + 1, len, fn, user) < 0)
                goto error;
 
        signs[first] = -1;
-       half = isl_set_from_basic_set(neg_halfspace(isl_set_get_dim(set),
+       half = isl_set_from_basic_set(neg_halfspace(isl_set_get_space(set),
                                                        1 + first));
        half = isl_set_intersect(half, set);
        return foreach_orthant(half, signs, first + 1, len, fn, user);
@@ -6350,6 +7041,12 @@ int isl_basic_map_is_subset(
        return is_subset;
 }
 
+int isl_basic_set_is_subset(__isl_keep isl_basic_set *bset1,
+       __isl_keep isl_basic_set *bset2)
+{
+       return isl_basic_map_is_subset(bset1, bset2);
+}
+
 int isl_basic_map_is_equal(
                struct isl_basic_map *bmap1, struct isl_basic_map *bmap2)
 {
@@ -6413,20 +7110,20 @@ int isl_set_is_empty(struct isl_set *set)
        return isl_map_is_empty((struct isl_map *)set);
 }
 
-int isl_map_has_equal_dim(__isl_keep isl_map *map1, __isl_keep isl_map *map2)
+int isl_map_has_equal_space(__isl_keep isl_map *map1, __isl_keep isl_map *map2)
 {
        if (!map1 || !map2)
                return -1;
 
-       return isl_dim_equal(map1->dim, map2->dim);
+       return isl_space_is_equal(map1->dim, map2->dim);
 }
 
-int isl_set_has_equal_dim(__isl_keep isl_set *set1, __isl_keep isl_set *set2)
+int isl_set_has_equal_space(__isl_keep isl_set *set1, __isl_keep isl_set *set2)
 {
        if (!set1 || !set2)
                return -1;
 
-       return isl_dim_equal(set1->dim, set2->dim);
+       return isl_space_is_equal(set1->dim, set2->dim);
 }
 
 static int map_is_equal(__isl_keep isl_map *map1, __isl_keep isl_map *map2)
@@ -6444,7 +7141,7 @@ static int map_is_equal(__isl_keep isl_map *map1, __isl_keep isl_map *map2)
 
 int isl_map_is_equal(__isl_keep isl_map *map1, __isl_keep isl_map *map2)
 {
-       return align_params_map_map_and_test(map1, map2, &map_is_equal);
+       return isl_map_align_params_map_map_and_test(map1, map2, &map_is_equal);
 }
 
 int isl_basic_map_is_strict_subset(
@@ -6603,11 +7300,11 @@ struct isl_map *isl_basic_map_union(
 {
        struct isl_map *map;
        if (!bmap1 || !bmap2)
-               return NULL;
+               goto error;
 
-       isl_assert(bmap1->ctx, isl_dim_equal(bmap1->dim, bmap2->dim), goto error);
+       isl_assert(bmap1->ctx, isl_space_is_equal(bmap1->dim, bmap2->dim), goto error);
 
-       map = isl_map_alloc_dim(isl_dim_copy(bmap1->dim), 2, 0);
+       map = isl_map_alloc_space(isl_space_copy(bmap1->dim), 2, 0);
        if (!map)
                goto error;
        map = isl_map_add_basic_map(map, bmap1);
@@ -6636,7 +7333,7 @@ struct isl_basic_map *isl_basic_map_order_divs(struct isl_basic_map *bmap)
        if (!bmap)
                return NULL;
 
-       off = isl_dim_total(bmap->dim);
+       off = isl_space_dim(bmap->dim, isl_dim_all);
 
        for (i = 0; i < bmap->n_div; ++i) {
                int pos;
@@ -6695,7 +7392,7 @@ __isl_give isl_basic_set *isl_basic_set_expand_divs(
                isl_die(isl_mat_get_ctx(div), isl_error_invalid,
                        "not an expansion", goto error);
 
-       bset = isl_basic_map_extend_dim(bset, isl_dim_copy(bset->dim),
+       bset = isl_basic_map_extend_space(bset, isl_space_copy(bset->dim),
                                        div->n_row - bset->n_div, 0,
                                        2 * (div->n_row - bset->n_div));
 
@@ -6736,7 +7433,7 @@ static int find_div(struct isl_basic_map *dst,
 {
        int i;
 
-       unsigned total = isl_dim_total(src->dim);
+       unsigned total = isl_space_dim(src->dim, isl_dim_all);
 
        isl_assert(dst->ctx, div <= dst->n_div, return -1);
        for (i = div; i < dst->n_div; ++i)
@@ -6751,7 +7448,7 @@ struct isl_basic_map *isl_basic_map_align_divs(
                struct isl_basic_map *dst, struct isl_basic_map *src)
 {
        int i;
-       unsigned total = isl_dim_total(src->dim);
+       unsigned total = isl_space_dim(src->dim, isl_dim_all);
 
        if (!dst || !src)
                goto error;
@@ -6764,7 +7461,7 @@ struct isl_basic_map *isl_basic_map_align_divs(
 
        src = isl_basic_map_order_divs(src);
        dst = isl_basic_map_cow(dst);
-       dst = isl_basic_map_extend_dim(dst, isl_dim_copy(dst->dim),
+       dst = isl_basic_map_extend_space(dst, isl_space_copy(dst->dim),
                        src->n_div, 0, 2 * src->n_div);
        if (!dst)
                return NULL;
@@ -6853,16 +7550,8 @@ struct isl_map *isl_map_remove_empty_parts(struct isl_map *map)
        if (!map)
                return NULL;
 
-       for (i = map->n-1; i >= 0; --i) {
-               if (!ISL_F_ISSET(map->p[i], ISL_BASIC_MAP_EMPTY))
-                       continue;
-               isl_basic_map_free(map->p[i]);
-               if (i != map->n-1) {
-                       ISL_F_CLR(map, ISL_MAP_NORMALIZED);
-                       map->p[i] = map->p[map->n-1];
-               }
-               map->n--;
-       }
+       for (i = map->n - 1; i >= 0; --i)
+               remove_if_empty(map, i);
 
        return map;
 }
@@ -6931,7 +7620,7 @@ static enum isl_lp_result basic_set_maximal_difference_at(
        __isl_keep isl_basic_set *bset1, __isl_keep isl_basic_set *bset2,
        int pos, isl_int *opt)
 {
-       struct isl_dim *dims;
+       isl_space *dims;
        struct isl_basic_map *bmap1 = NULL;
        struct isl_basic_map *bmap2 = NULL;
        struct isl_ctx *ctx;
@@ -6947,9 +7636,9 @@ static enum isl_lp_result basic_set_maximal_difference_at(
        nparam = isl_basic_set_n_param(bset1);
        dim1 = isl_basic_set_n_dim(bset1);
        dim2 = isl_basic_set_n_dim(bset2);
-       dims = isl_dim_alloc(bset1->ctx, nparam, pos, dim1 - pos);
+       dims = isl_space_alloc(bset1->ctx, nparam, pos, dim1 - pos);
        bmap1 = isl_basic_map_from_basic_set(isl_basic_set_copy(bset1), dims);
-       dims = isl_dim_alloc(bset2->ctx, nparam, pos, dim2 - pos);
+       dims = isl_space_alloc(bset2->ctx, nparam, pos, dim2 - pos);
        bmap2 = isl_basic_map_from_basic_set(isl_basic_set_copy(bset2), dims);
        if (!bmap1 || !bmap2)
                goto error;
@@ -7175,6 +7864,12 @@ int isl_map_plain_is_fixed(__isl_keep isl_map *map,
                map_offset(map, type) - 1 + pos, val);
 }
 
+int isl_set_plain_is_fixed(__isl_keep isl_set *set,
+       enum isl_dim_type type, unsigned pos, isl_int *val)
+{
+       return isl_map_plain_is_fixed(set, type, pos, val);
+}
+
 int isl_map_fast_is_fixed(__isl_keep isl_map *map,
        enum isl_dim_type type, unsigned pos, isl_int *val)
 {
@@ -7417,6 +8112,31 @@ int isl_basic_map_plain_cmp(const __isl_keep isl_basic_map *bmap1,
        return 0;
 }
 
+int isl_basic_set_plain_cmp(const __isl_keep isl_basic_set *bset1,
+       const __isl_keep isl_basic_set *bset2)
+{
+       return isl_basic_map_plain_cmp(bset1, bset2);
+}
+
+int isl_set_plain_cmp(const __isl_keep isl_set *set1,
+       const __isl_keep isl_set *set2)
+{
+       int i, cmp;
+
+       if (set1 == set2)
+               return 0;
+       if (set1->n != set2->n)
+               return set1->n - set2->n;
+
+       for (i = 0; i < set1->n; ++i) {
+               cmp = isl_basic_set_plain_cmp(set1->p[i], set2->p[i]);
+               if (cmp)
+                       return cmp;
+       }
+
+       return 0;
+}
+
 int isl_basic_map_plain_is_equal(__isl_keep isl_basic_map *bmap1,
        __isl_keep isl_basic_map *bmap2)
 {
@@ -7493,7 +8213,7 @@ int isl_map_plain_is_equal(__isl_keep isl_map *map1, __isl_keep isl_map *map2)
 
        if (map1 == map2)
                return 1;
-       if (!isl_dim_equal(map1->dim, map2->dim))
+       if (!isl_space_is_equal(map1->dim, map2->dim))
                return 0;
 
        map1 = isl_map_copy(map1);
@@ -7615,7 +8335,7 @@ error:
 struct isl_basic_map *isl_basic_map_product(
                struct isl_basic_map *bmap1, struct isl_basic_map *bmap2)
 {
-       struct isl_dim *dim_result = NULL;
+       isl_space *dim_result = NULL;
        struct isl_basic_map *bmap;
        unsigned in1, in2, out1, out2, nparam, total, pos;
        struct isl_dim_map *dim_map1, *dim_map2;
@@ -7623,10 +8343,10 @@ struct isl_basic_map *isl_basic_map_product(
        if (!bmap1 || !bmap2)
                goto error;
 
-       isl_assert(bmap1->ctx, isl_dim_match(bmap1->dim, isl_dim_param,
+       isl_assert(bmap1->ctx, isl_space_match(bmap1->dim, isl_dim_param,
                                     bmap2->dim, isl_dim_param), goto error);
-       dim_result = isl_dim_product(isl_dim_copy(bmap1->dim),
-                                                  isl_dim_copy(bmap2->dim));
+       dim_result = isl_space_product(isl_space_copy(bmap1->dim),
+                                                  isl_space_copy(bmap2->dim));
 
        in1 = isl_basic_map_n_in(bmap1);
        in2 = isl_basic_map_n_in(bmap2);
@@ -7646,7 +8366,7 @@ struct isl_basic_map *isl_basic_map_product(
        isl_dim_map_div(dim_map1, bmap1, pos += out2);
        isl_dim_map_div(dim_map2, bmap2, pos += bmap1->n_div);
 
-       bmap = isl_basic_map_alloc_dim(dim_result,
+       bmap = isl_basic_map_alloc_space(dim_result,
                        bmap1->n_div + bmap2->n_div,
                        bmap1->n_eq + bmap2->n_eq,
                        bmap1->n_ineq + bmap2->n_ineq);
@@ -7673,41 +8393,41 @@ __isl_give isl_basic_map *isl_basic_map_flat_product(
 __isl_give isl_basic_set *isl_basic_set_flat_product(
        __isl_take isl_basic_set *bset1, __isl_take isl_basic_set *bset2)
 {
-       return isl_basic_map_flat_product(bset1, bset2);
+       return isl_basic_map_flat_range_product(bset1, bset2);
 }
 
-__isl_give isl_basic_map *isl_basic_map_range_product(
+__isl_give isl_basic_map *isl_basic_map_domain_product(
        __isl_take isl_basic_map *bmap1, __isl_take isl_basic_map *bmap2)
 {
-       isl_dim *dim_result = NULL;
+       isl_space *space_result = NULL;
        isl_basic_map *bmap;
-       unsigned in, out1, out2, nparam, total, pos;
+       unsigned in1, in2, out, nparam, total, pos;
        struct isl_dim_map *dim_map1, *dim_map2;
 
        if (!bmap1 || !bmap2)
                goto error;
 
-       dim_result = isl_dim_range_product(isl_dim_copy(bmap1->dim),
-                                          isl_dim_copy(bmap2->dim));
+       space_result = isl_space_domain_product(isl_space_copy(bmap1->dim),
+                                               isl_space_copy(bmap2->dim));
 
-       in = isl_basic_map_dim(bmap1, isl_dim_in);
-       out1 = isl_basic_map_n_out(bmap1);
-       out2 = isl_basic_map_n_out(bmap2);
-       nparam = isl_basic_map_n_param(bmap1);
+       in1 = isl_basic_map_dim(bmap1, isl_dim_in);
+       in2 = isl_basic_map_dim(bmap2, isl_dim_in);
+       out = isl_basic_map_dim(bmap1, isl_dim_out);
+       nparam = isl_basic_map_dim(bmap1, isl_dim_param);
 
-       total = nparam + in + out1 + out2 + bmap1->n_div + bmap2->n_div;
+       total = nparam + in1 + in2 + out + bmap1->n_div + bmap2->n_div;
        dim_map1 = isl_dim_map_alloc(bmap1->ctx, total);
        dim_map2 = isl_dim_map_alloc(bmap1->ctx, total);
        isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_param, pos = 0);
        isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_param, pos = 0);
        isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_in, pos += nparam);
-       isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_in, pos);
-       isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_out, pos += in);
-       isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_out, pos += out1);
-       isl_dim_map_div(dim_map1, bmap1, pos += out2);
+       isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_in, pos += in1);
+       isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_out, pos += in2);
+       isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_out, pos);
+       isl_dim_map_div(dim_map1, bmap1, pos += out);
        isl_dim_map_div(dim_map2, bmap2, pos += bmap1->n_div);
 
-       bmap = isl_basic_map_alloc_dim(dim_result,
+       bmap = isl_basic_map_alloc_space(space_result,
                        bmap1->n_div + bmap2->n_div,
                        bmap1->n_eq + bmap2->n_eq,
                        bmap1->n_ineq + bmap2->n_ineq);
@@ -7721,20 +8441,70 @@ error:
        return NULL;
 }
 
-__isl_give isl_basic_map *isl_basic_map_flat_range_product(
+__isl_give isl_basic_map *isl_basic_map_range_product(
        __isl_take isl_basic_map *bmap1, __isl_take isl_basic_map *bmap2)
 {
-       isl_basic_map *prod;
+       isl_space *dim_result = NULL;
+       isl_basic_map *bmap;
+       unsigned in, out1, out2, nparam, total, pos;
+       struct isl_dim_map *dim_map1, *dim_map2;
 
-       prod = isl_basic_map_range_product(bmap1, bmap2);
-       prod = isl_basic_map_flatten_range(prod);
-       return prod;
-}
+       if (!bmap1 || !bmap2)
+               goto error;
 
-static __isl_give isl_map *map_product(__isl_take isl_map *map1,
-       __isl_take isl_map *map2,
-       __isl_give isl_dim *(*dim_product)(__isl_take isl_dim *left,
-                                          __isl_take isl_dim *right),
+       if (!isl_space_match(bmap1->dim, isl_dim_param,
+                           bmap2->dim, isl_dim_param))
+               isl_die(isl_basic_map_get_ctx(bmap1), isl_error_invalid,
+                       "parameters don't match", goto error);
+
+       dim_result = isl_space_range_product(isl_space_copy(bmap1->dim),
+                                          isl_space_copy(bmap2->dim));
+
+       in = isl_basic_map_dim(bmap1, isl_dim_in);
+       out1 = isl_basic_map_n_out(bmap1);
+       out2 = isl_basic_map_n_out(bmap2);
+       nparam = isl_basic_map_n_param(bmap1);
+
+       total = nparam + in + out1 + out2 + bmap1->n_div + bmap2->n_div;
+       dim_map1 = isl_dim_map_alloc(bmap1->ctx, total);
+       dim_map2 = isl_dim_map_alloc(bmap1->ctx, total);
+       isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_param, pos = 0);
+       isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_param, pos = 0);
+       isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_in, pos += nparam);
+       isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_in, pos);
+       isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_out, pos += in);
+       isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_out, pos += out1);
+       isl_dim_map_div(dim_map1, bmap1, pos += out2);
+       isl_dim_map_div(dim_map2, bmap2, pos += bmap1->n_div);
+
+       bmap = isl_basic_map_alloc_space(dim_result,
+                       bmap1->n_div + bmap2->n_div,
+                       bmap1->n_eq + bmap2->n_eq,
+                       bmap1->n_ineq + bmap2->n_ineq);
+       bmap = isl_basic_map_add_constraints_dim_map(bmap, bmap1, dim_map1);
+       bmap = isl_basic_map_add_constraints_dim_map(bmap, bmap2, dim_map2);
+       bmap = isl_basic_map_simplify(bmap);
+       return isl_basic_map_finalize(bmap);
+error:
+       isl_basic_map_free(bmap1);
+       isl_basic_map_free(bmap2);
+       return NULL;
+}
+
+__isl_give isl_basic_map *isl_basic_map_flat_range_product(
+       __isl_take isl_basic_map *bmap1, __isl_take isl_basic_map *bmap2)
+{
+       isl_basic_map *prod;
+
+       prod = isl_basic_map_range_product(bmap1, bmap2);
+       prod = isl_basic_map_flatten_range(prod);
+       return prod;
+}
+
+static __isl_give isl_map *map_product(__isl_take isl_map *map1,
+       __isl_take isl_map *map2,
+       __isl_give isl_space *(*dim_product)(__isl_take isl_space *left,
+                                          __isl_take isl_space *right),
        __isl_give isl_basic_map *(*basic_map_product)(
                __isl_take isl_basic_map *left, __isl_take isl_basic_map *right))
 {
@@ -7745,15 +8515,15 @@ static __isl_give isl_map *map_product(__isl_take isl_map *map1,
        if (!map1 || !map2)
                goto error;
 
-       isl_assert(map1->ctx, isl_dim_match(map1->dim, isl_dim_param,
+       isl_assert(map1->ctx, isl_space_match(map1->dim, isl_dim_param,
                                         map2->dim, isl_dim_param), goto error);
 
        if (ISL_F_ISSET(map1, ISL_MAP_DISJOINT) &&
            ISL_F_ISSET(map2, ISL_MAP_DISJOINT))
                ISL_FL_SET(flags, ISL_MAP_DISJOINT);
 
-       result = isl_map_alloc_dim(dim_product(isl_dim_copy(map1->dim),
-                                              isl_dim_copy(map2->dim)),
+       result = isl_map_alloc_space(dim_product(isl_space_copy(map1->dim),
+                                              isl_space_copy(map2->dim)),
                                map1->n * map2->n, flags);
        if (!result)
                goto error;
@@ -7783,7 +8553,7 @@ error:
 static __isl_give isl_map *map_product_aligned(__isl_take isl_map *map1,
        __isl_take isl_map *map2)
 {
-       return map_product(map1, map2, &isl_dim_product, &isl_basic_map_product);
+       return map_product(map1, map2, &isl_space_product, &isl_basic_map_product);
 }
 
 __isl_give isl_map *isl_map_product(__isl_take isl_map *map1,
@@ -7814,7 +8584,16 @@ struct isl_set *isl_set_product(struct isl_set *set1, struct isl_set *set2)
 __isl_give isl_set *isl_set_flat_product(__isl_take isl_set *set1,
        __isl_take isl_set *set2)
 {
-       return (isl_set *)isl_map_flat_product((isl_map *)set1, (isl_map *)set2);
+       return isl_map_flat_range_product(set1, set2);
+}
+
+/* Given two maps A -> B and C -> D, construct a map [A -> C] -> (B * D)
+ */
+static __isl_give isl_map *map_domain_product_aligned(__isl_take isl_map *map1,
+       __isl_take isl_map *map2)
+{
+       return map_product(map1, map2, &isl_space_domain_product,
+                               &isl_basic_map_domain_product);
 }
 
 /* Given two maps A -> B and C -> D, construct a map (A * C) -> [B -> D]
@@ -7822,10 +8601,17 @@ __isl_give isl_set *isl_set_flat_product(__isl_take isl_set *set1,
 static __isl_give isl_map *map_range_product_aligned(__isl_take isl_map *map1,
        __isl_take isl_map *map2)
 {
-       return map_product(map1, map2, &isl_dim_range_product,
+       return map_product(map1, map2, &isl_space_range_product,
                                &isl_basic_map_range_product);
 }
 
+__isl_give isl_map *isl_map_domain_product(__isl_take isl_map *map1,
+       __isl_take isl_map *map2)
+{
+       return isl_map_align_params_map_map_and(map1, map2,
+                                               &map_domain_product_aligned);
+}
+
 __isl_give isl_map *isl_map_range_product(__isl_take isl_map *map1,
        __isl_take isl_map *map2)
 {
@@ -7833,6 +8619,18 @@ __isl_give isl_map *isl_map_range_product(__isl_take isl_map *map1,
                                                &map_range_product_aligned);
 }
 
+/* Given two maps A -> B and C -> D, construct a map (A, C) -> (B * D)
+ */
+__isl_give isl_map *isl_map_flat_domain_product(__isl_take isl_map *map1,
+       __isl_take isl_map *map2)
+{
+       isl_map *prod;
+
+       prod = isl_map_domain_product(map1, map2);
+       prod = isl_map_flatten_domain(prod);
+       return prod;
+}
+
 /* Given two maps A -> B and C -> D, construct a map (A * C) -> (B, D)
  */
 __isl_give isl_map *isl_map_flat_range_product(__isl_take isl_map *map1,
@@ -7992,7 +8790,7 @@ int isl_set_foreach_basic_set(__isl_keep isl_set *set,
 
 __isl_give isl_basic_set *isl_basic_set_lift(__isl_take isl_basic_set *bset)
 {
-       struct isl_dim *dim;
+       isl_space *dim;
 
        if (!bset)
                return NULL;
@@ -8001,11 +8799,11 @@ __isl_give isl_basic_set *isl_basic_set_lift(__isl_take isl_basic_set *bset)
        if (!bset)
                return NULL;
 
-       dim = isl_basic_set_get_dim(bset);
-       dim = isl_dim_lift(dim, bset->n_div);
+       dim = isl_basic_set_get_space(bset);
+       dim = isl_space_lift(dim, bset->n_div);
        if (!dim)
                goto error;
-       isl_dim_free(bset->dim);
+       isl_space_free(bset->dim);
        bset->dim = dim;
        bset->extra -= bset->n_div;
        bset->n_div = 0;
@@ -8021,7 +8819,7 @@ error:
 __isl_give isl_set *isl_set_lift(__isl_take isl_set *set)
 {
        int i;
-       struct isl_dim *dim;
+       isl_space *dim;
        unsigned n_div;
 
        set = isl_set_align_divs(set);
@@ -8034,11 +8832,11 @@ __isl_give isl_set *isl_set_lift(__isl_take isl_set *set)
                return NULL;
 
        n_div = set->p[0]->n_div;
-       dim = isl_set_get_dim(set);
-       dim = isl_dim_lift(dim, n_div);
+       dim = isl_set_get_space(set);
+       dim = isl_space_lift(dim, n_div);
        if (!dim)
                goto error;
-       isl_dim_free(set->dim);
+       isl_space_free(set->dim);
        set->dim = dim;
 
        for (i = 0; i < set->n; ++i) {
@@ -8055,7 +8853,7 @@ error:
 
 __isl_give isl_map *isl_set_lifting(__isl_take isl_set *set)
 {
-       struct isl_dim *dim;
+       isl_space *dim;
        struct isl_basic_map *bmap;
        unsigned n_set;
        unsigned n_div;
@@ -8068,18 +8866,18 @@ __isl_give isl_map *isl_set_lifting(__isl_take isl_set *set)
        if (!set)
                return NULL;
 
-       dim = isl_set_get_dim(set);
+       dim = isl_set_get_space(set);
        if (set->n == 0 || set->p[0]->n_div == 0) {
                isl_set_free(set);
-               return isl_map_identity(isl_dim_map_from_set(dim));
+               return isl_map_identity(isl_space_map_from_set(dim));
        }
 
        n_div = set->p[0]->n_div;
-       dim = isl_dim_map_from_set(dim);
-       n_param = isl_dim_size(dim, isl_dim_param);
-       n_set = isl_dim_size(dim, isl_dim_in);
-       dim = isl_dim_extend(dim, n_param, n_set, n_set + n_div);
-       bmap = isl_basic_map_alloc_dim(dim, 0, n_set, 2 * n_div);
+       dim = isl_space_map_from_set(dim);
+       n_param = isl_space_dim(dim, isl_dim_param);
+       n_set = isl_space_dim(dim, isl_dim_in);
+       dim = isl_space_extend(dim, n_param, n_set, n_set + n_div);
+       bmap = isl_basic_map_alloc_space(dim, 0, n_set, 2 * n_div);
        for (i = 0; i < n_set; ++i)
                bmap = var_equal(bmap, i);
 
@@ -8282,7 +9080,7 @@ int isl_basic_set_vars_get_sign(__isl_keep isl_basic_set *bset,
                return -1;
 
        bound = isl_vec_alloc(bset->ctx, 1 + isl_basic_set_total_dim(bset));
-       tab = isl_tab_from_basic_set(bset);
+       tab = isl_tab_from_basic_set(bset, 0);
        if (!bound || !tab)
                goto error;
 
@@ -8372,6 +9170,39 @@ int isl_basic_map_plain_is_single_valued(__isl_keep isl_basic_map *bmap)
        return 1;
 }
 
+/* Check if the given basic map is single-valued.
+ * We simply compute
+ *
+ *     M \circ M^-1
+ *
+ * and check if the result is a subset of the identity mapping.
+ */
+int isl_basic_map_is_single_valued(__isl_keep isl_basic_map *bmap)
+{
+       isl_space *space;
+       isl_basic_map *test;
+       isl_basic_map *id;
+       int sv;
+
+       sv = isl_basic_map_plain_is_single_valued(bmap);
+       if (sv < 0 || sv)
+               return sv;
+
+       test = isl_basic_map_reverse(isl_basic_map_copy(bmap));
+       test = isl_basic_map_apply_range(test, isl_basic_map_copy(bmap));
+
+       space = isl_basic_map_get_space(bmap);
+       space = isl_space_map_from_set(isl_space_range(space));
+       id = isl_basic_map_identity(space);
+
+       sv = isl_basic_map_is_subset(test, id);
+
+       isl_basic_map_free(test);
+       isl_basic_map_free(id);
+
+       return sv;
+}
+
 /* Check if the given map is obviously single-valued.
  */
 int isl_map_plain_is_single_valued(__isl_keep isl_map *map)
@@ -8395,7 +9226,7 @@ int isl_map_plain_is_single_valued(__isl_keep isl_map *map)
  */
 int isl_map_is_single_valued(__isl_keep isl_map *map)
 {
-       isl_dim *dim;
+       isl_space *dim;
        isl_map *test;
        isl_map *id;
        int sv;
@@ -8407,7 +9238,7 @@ int isl_map_is_single_valued(__isl_keep isl_map *map)
        test = isl_map_reverse(isl_map_copy(map));
        test = isl_map_apply_range(test, isl_map_copy(map));
 
-       dim = isl_dim_map_from_set(isl_dim_range(isl_map_get_dim(map)));
+       dim = isl_space_map_from_set(isl_space_range(isl_map_get_space(map)));
        id = isl_map_identity(dim);
 
        sv = isl_map_is_subset(test, id);
@@ -8494,7 +9325,7 @@ int isl_basic_set_is_box(__isl_keep isl_basic_set *bset)
                return 0;
 
        nvar = isl_basic_set_dim(bset, isl_dim_set);
-       ovar = isl_dim_offset(bset->dim, isl_dim_set);
+       ovar = isl_space_offset(bset->dim, isl_dim_set);
        for (j = 0; j < nvar; ++j) {
                int lower = 0, upper = 0;
                for (i = 0; i < bset->n_eq; ++i) {
@@ -8538,7 +9369,7 @@ int isl_basic_set_is_wrapping(__isl_keep isl_basic_set *bset)
        if (!bset)
                return -1;
        
-       return isl_dim_is_wrapping(bset->dim);
+       return isl_space_is_wrapping(bset->dim);
 }
 
 int isl_set_is_wrapping(__isl_keep isl_set *set)
@@ -8546,7 +9377,7 @@ int isl_set_is_wrapping(__isl_keep isl_set *set)
        if (!set)
                return -1;
        
-       return isl_dim_is_wrapping(set->dim);
+       return isl_space_is_wrapping(set->dim);
 }
 
 __isl_give isl_basic_set *isl_basic_map_wrap(__isl_take isl_basic_map *bmap)
@@ -8555,7 +9386,7 @@ __isl_give isl_basic_set *isl_basic_map_wrap(__isl_take isl_basic_map *bmap)
        if (!bmap)
                return NULL;
 
-       bmap->dim = isl_dim_wrap(bmap->dim);
+       bmap->dim = isl_space_wrap(bmap->dim);
        if (!bmap->dim)
                goto error;
 
@@ -8580,7 +9411,7 @@ __isl_give isl_set *isl_map_wrap(__isl_take isl_map *map)
                if (!map->p[i])
                        goto error;
        }
-       map->dim = isl_dim_wrap(map->dim);
+       map->dim = isl_space_wrap(map->dim);
        if (!map->dim)
                goto error;
 
@@ -8596,7 +9427,7 @@ __isl_give isl_basic_map *isl_basic_set_unwrap(__isl_take isl_basic_set *bset)
        if (!bset)
                return NULL;
 
-       bset->dim = isl_dim_unwrap(bset->dim);
+       bset->dim = isl_space_unwrap(bset->dim);
        if (!bset->dim)
                goto error;
 
@@ -8629,7 +9460,7 @@ __isl_give isl_map *isl_set_unwrap(__isl_take isl_set *set)
                        goto error;
        }
 
-       set->dim = isl_dim_unwrap(set->dim);
+       set->dim = isl_space_unwrap(set->dim);
        if (!set->dim)
                goto error;
 
@@ -8645,14 +9476,14 @@ __isl_give isl_basic_map *isl_basic_map_reset(__isl_take isl_basic_map *bmap,
        if (!bmap)
                return NULL;
 
-       if (!isl_dim_is_named_or_nested(bmap->dim, type))
+       if (!isl_space_is_named_or_nested(bmap->dim, type))
                return bmap;
 
        bmap = isl_basic_map_cow(bmap);
        if (!bmap)
                return NULL;
 
-       bmap->dim = isl_dim_reset(bmap->dim, type);
+       bmap->dim = isl_space_reset(bmap->dim, type);
        if (!bmap->dim)
                goto error;
 
@@ -8672,7 +9503,7 @@ __isl_give isl_map *isl_map_reset(__isl_take isl_map *map,
        if (!map)
                return NULL;
 
-       if (!isl_dim_is_named_or_nested(map->dim, type))
+       if (!isl_space_is_named_or_nested(map->dim, type))
                return map;
 
        map = isl_map_cow(map);
@@ -8684,7 +9515,7 @@ __isl_give isl_map *isl_map_reset(__isl_take isl_map *map,
                if (!map->p[i])
                        goto error;
        }
-       map->dim = isl_dim_reset(map->dim, type);
+       map->dim = isl_space_reset(map->dim, type);
        if (!map->dim)
                goto error;
 
@@ -8706,7 +9537,7 @@ __isl_give isl_basic_map *isl_basic_map_flatten(__isl_take isl_basic_map *bmap)
        if (!bmap)
                return NULL;
 
-       bmap->dim = isl_dim_flatten(bmap->dim);
+       bmap->dim = isl_space_flatten(bmap->dim);
        if (!bmap->dim)
                goto error;
 
@@ -8723,6 +9554,31 @@ __isl_give isl_basic_set *isl_basic_set_flatten(__isl_take isl_basic_set *bset)
        return (isl_basic_set *)isl_basic_map_flatten((isl_basic_map *)bset);
 }
 
+__isl_give isl_basic_map *isl_basic_map_flatten_domain(
+       __isl_take isl_basic_map *bmap)
+{
+       if (!bmap)
+               return NULL;
+
+       if (!bmap->dim->nested[0])
+               return bmap;
+
+       bmap = isl_basic_map_cow(bmap);
+       if (!bmap)
+               return NULL;
+
+       bmap->dim = isl_space_flatten_domain(bmap->dim);
+       if (!bmap->dim)
+               goto error;
+
+       bmap = isl_basic_map_finalize(bmap);
+
+       return bmap;
+error:
+       isl_basic_map_free(bmap);
+       return NULL;
+}
+
 __isl_give isl_basic_map *isl_basic_map_flatten_range(
        __isl_take isl_basic_map *bmap)
 {
@@ -8736,7 +9592,7 @@ __isl_give isl_basic_map *isl_basic_map_flatten_range(
        if (!bmap)
                return NULL;
 
-       bmap->dim = isl_dim_flatten_range(bmap->dim);
+       bmap->dim = isl_space_flatten_range(bmap->dim);
        if (!bmap->dim)
                goto error;
 
@@ -8767,7 +9623,7 @@ __isl_give isl_map *isl_map_flatten(__isl_take isl_map *map)
                if (!map->p[i])
                        goto error;
        }
-       map->dim = isl_dim_flatten(map->dim);
+       map->dim = isl_space_flatten(map->dim);
        if (!map->dim)
                goto error;
 
@@ -8784,17 +9640,46 @@ __isl_give isl_set *isl_set_flatten(__isl_take isl_set *set)
 
 __isl_give isl_map *isl_set_flatten_map(__isl_take isl_set *set)
 {
-       isl_dim *dim, *flat_dim;
+       isl_space *dim, *flat_dim;
        isl_map *map;
 
-       dim = isl_set_get_dim(set);
-       flat_dim = isl_dim_flatten(isl_dim_copy(dim));
-       map = isl_map_identity(isl_dim_join(isl_dim_reverse(dim), flat_dim));
+       dim = isl_set_get_space(set);
+       flat_dim = isl_space_flatten(isl_space_copy(dim));
+       map = isl_map_identity(isl_space_join(isl_space_reverse(dim), flat_dim));
        map = isl_map_intersect_domain(map, set);
 
        return map;
 }
 
+__isl_give isl_map *isl_map_flatten_domain(__isl_take isl_map *map)
+{
+       int i;
+
+       if (!map)
+               return NULL;
+
+       if (!map->dim->nested[0])
+               return map;
+
+       map = isl_map_cow(map);
+       if (!map)
+               return NULL;
+
+       for (i = 0; i < map->n; ++i) {
+               map->p[i] = isl_basic_map_flatten_domain(map->p[i]);
+               if (!map->p[i])
+                       goto error;
+       }
+       map->dim = isl_space_flatten_domain(map->dim);
+       if (!map->dim)
+               goto error;
+
+       return map;
+error:
+       isl_map_free(map);
+       return NULL;
+}
+
 __isl_give isl_map *isl_map_flatten_range(__isl_take isl_map *map)
 {
        int i;
@@ -8814,7 +9699,7 @@ __isl_give isl_map *isl_map_flatten_range(__isl_take isl_map *map)
                if (!map->p[i])
                        goto error;
        }
-       map->dim = isl_dim_flatten_range(map->dim);
+       map->dim = isl_space_flatten_range(map->dim);
        if (!map->dim)
                goto error;
 
@@ -8828,23 +9713,30 @@ error:
  * and set the dimension specification to "dim".
  */
 __isl_give isl_basic_map *isl_basic_map_realign(__isl_take isl_basic_map *bmap,
-       __isl_take isl_dim *dim, __isl_take struct isl_dim_map *dim_map)
+       __isl_take isl_space *dim, __isl_take struct isl_dim_map *dim_map)
 {
        isl_basic_map *res;
+       unsigned flags;
 
        bmap = isl_basic_map_cow(bmap);
        if (!bmap || !dim || !dim_map)
                goto error;
 
-       res = isl_basic_map_alloc_dim(dim,
+       flags = bmap->flags;
+       ISL_FL_CLR(flags, ISL_BASIC_MAP_FINAL);
+       ISL_FL_CLR(flags, ISL_BASIC_MAP_NORMALIZED);
+       ISL_FL_CLR(flags, ISL_BASIC_MAP_NORMALIZED_DIVS);
+       res = isl_basic_map_alloc_space(dim,
                        bmap->n_div, bmap->n_eq, bmap->n_ineq);
        res = isl_basic_map_add_constraints_dim_map(res, bmap, dim_map);
+       if (res)
+               res->flags = flags;
        res = isl_basic_map_finalize(res);
        return res;
 error:
        free(dim_map);
        isl_basic_map_free(bmap);
-       isl_dim_free(dim);
+       isl_space_free(dim);
        return NULL;
 }
 
@@ -8867,13 +9759,13 @@ __isl_give isl_map *isl_map_realign(__isl_take isl_map *map,
                dim_map_i = isl_dim_map_extend(dim_map, map->p[i]);
 
                map->p[i] = isl_basic_map_realign(map->p[i],
-                                           isl_dim_copy(r->dim), dim_map_i);
+                                           isl_space_copy(r->dim), dim_map_i);
 
                if (!map->p[i])
                        goto error;
        }
 
-       map = isl_map_reset_dim(map, isl_dim_copy(r->dim));
+       map = isl_map_reset_space(map, isl_space_copy(r->dim));
 
        isl_reordering_free(r);
        free(dim_map);
@@ -8892,42 +9784,42 @@ __isl_give isl_set *isl_set_realign(__isl_take isl_set *set,
 }
 
 __isl_give isl_map *isl_map_align_params(__isl_take isl_map *map,
-       __isl_take isl_dim *model)
+       __isl_take isl_space *model)
 {
        isl_ctx *ctx;
 
        if (!map || !model)
                goto error;
 
-       ctx = isl_dim_get_ctx(model);
-       if (!isl_dim_has_named_params(model))
+       ctx = isl_space_get_ctx(model);
+       if (!isl_space_has_named_params(model))
                isl_die(ctx, isl_error_invalid,
                        "model has unnamed parameters", goto error);
-       if (!isl_dim_has_named_params(map->dim))
+       if (!isl_space_has_named_params(map->dim))
                isl_die(ctx, isl_error_invalid,
                        "relation has unnamed parameters", goto error);
-       if (!isl_dim_match(map->dim, isl_dim_param, model, isl_dim_param)) {
+       if (!isl_space_match(map->dim, isl_dim_param, model, isl_dim_param)) {
                isl_reordering *exp;
 
-               model = isl_dim_drop(model, isl_dim_in,
-                                       0, isl_dim_size(model, isl_dim_in));
-               model = isl_dim_drop(model, isl_dim_out,
-                                       0, isl_dim_size(model, isl_dim_out));
+               model = isl_space_drop_dims(model, isl_dim_in,
+                                       0, isl_space_dim(model, isl_dim_in));
+               model = isl_space_drop_dims(model, isl_dim_out,
+                                       0, isl_space_dim(model, isl_dim_out));
                exp = isl_parameter_alignment_reordering(map->dim, model);
-               exp = isl_reordering_extend_dim(exp, isl_map_get_dim(map));
+               exp = isl_reordering_extend_space(exp, isl_map_get_space(map));
                map = isl_map_realign(map, exp);
        }
 
-       isl_dim_free(model);
+       isl_space_free(model);
        return map;
 error:
-       isl_dim_free(model);
+       isl_space_free(model);
        isl_map_free(map);
        return NULL;
 }
 
 __isl_give isl_set *isl_set_align_params(__isl_take isl_set *set,
-       __isl_take isl_dim *model)
+       __isl_take isl_space *model)
 {
        return isl_map_align_params(set, model);
 }
@@ -8991,7 +9883,7 @@ __isl_give isl_mat *isl_basic_map_inequalities_matrix(
 }
 
 __isl_give isl_basic_map *isl_basic_map_from_constraint_matrices(
-       __isl_take isl_dim *dim,
+       __isl_take isl_space *dim,
        __isl_take isl_mat *eq, __isl_take isl_mat *ineq, enum isl_dim_type c1,
        enum isl_dim_type c2, enum isl_dim_type c3,
        enum isl_dim_type c4, enum isl_dim_type c5)
@@ -9011,7 +9903,7 @@ __isl_give isl_basic_map *isl_basic_map_from_constraint_matrices(
                        "equalities and inequalities matrices should have "
                        "same number of columns", goto error);
 
-       total = 1 + isl_dim_total(dim);
+       total = 1 + isl_space_dim(dim, isl_dim_all);
 
        if (eq->n_col < total)
                isl_die(dim->ctx, isl_error_invalid,
@@ -9019,7 +9911,7 @@ __isl_give isl_basic_map *isl_basic_map_from_constraint_matrices(
 
        extra = eq->n_col - total;
 
-       bmap = isl_basic_map_alloc_dim(isl_dim_copy(dim), extra,
+       bmap = isl_basic_map_alloc_space(isl_space_copy(dim), extra,
                                       eq->n_row, ineq->n_row);
        if (!bmap)
                goto error;
@@ -9056,13 +9948,13 @@ __isl_give isl_basic_map *isl_basic_map_from_constraint_matrices(
                }
        }
 
-       isl_dim_free(dim);
+       isl_space_free(dim);
        isl_mat_free(eq);
        isl_mat_free(ineq);
 
        return bmap;
 error:
-       isl_dim_free(dim);
+       isl_space_free(dim);
        isl_mat_free(eq);
        isl_mat_free(ineq);
        return NULL;
@@ -9085,7 +9977,7 @@ __isl_give isl_mat *isl_basic_set_inequalities_matrix(
 }
 
 __isl_give isl_basic_set *isl_basic_set_from_constraint_matrices(
-       __isl_take isl_dim *dim,
+       __isl_take isl_space *dim,
        __isl_take isl_mat *eq, __isl_take isl_mat *ineq, enum isl_dim_type c1,
        enum isl_dim_type c2, enum isl_dim_type c3, enum isl_dim_type c4)
 {
@@ -9099,7 +9991,7 @@ int isl_basic_map_can_zip(__isl_keep isl_basic_map *bmap)
        if (!bmap)
                return -1;
        
-       return isl_dim_can_zip(bmap->dim);
+       return isl_space_can_zip(bmap->dim);
 }
 
 int isl_map_can_zip(__isl_keep isl_map *map)
@@ -9107,7 +9999,7 @@ int isl_map_can_zip(__isl_keep isl_map *map)
        if (!map)
                return -1;
        
-       return isl_dim_can_zip(map->dim);
+       return isl_space_can_zip(map->dim);
 }
 
 /* Given a basic map (A -> B) -> (C -> D), return the corresponding basic map
@@ -9126,13 +10018,14 @@ __isl_give isl_basic_map *isl_basic_map_zip(__isl_take isl_basic_map *bmap)
                isl_die(bmap->ctx, isl_error_invalid,
                        "basic map cannot be zipped", goto error);
        pos = isl_basic_map_offset(bmap, isl_dim_in) +
-               isl_dim_size(bmap->dim->nested[0], isl_dim_in);
-       n1 = isl_dim_size(bmap->dim->nested[0], isl_dim_out);
-       n2 = isl_dim_size(bmap->dim->nested[1], isl_dim_in);
+               isl_space_dim(bmap->dim->nested[0], isl_dim_in);
+       n1 = isl_space_dim(bmap->dim->nested[0], isl_dim_out);
+       n2 = isl_space_dim(bmap->dim->nested[1], isl_dim_in);
+       bmap = isl_basic_map_cow(bmap);
        bmap = isl_basic_map_swap_vars(bmap, pos, n1, n2);
        if (!bmap)
                return NULL;
-       bmap->dim = isl_dim_zip(bmap->dim);
+       bmap->dim = isl_space_zip(bmap->dim);
        if (!bmap->dim)
                goto error;
        return bmap;
@@ -9165,7 +10058,84 @@ __isl_give isl_map *isl_map_zip(__isl_take isl_map *map)
                        goto error;
        }
 
-       map->dim = isl_dim_zip(map->dim);
+       map->dim = isl_space_zip(map->dim);
+       if (!map->dim)
+               goto error;
+
+       return map;
+error:
+       isl_map_free(map);
+       return NULL;
+}
+
+/* Can we apply isl_basic_map_curry to "bmap"?
+ * That is, does it have a nested relation in its domain?
+ */
+int isl_basic_map_can_curry(__isl_keep isl_basic_map *bmap)
+{
+       if (!bmap)
+               return -1;
+
+       return isl_space_can_curry(bmap->dim);
+}
+
+/* Can we apply isl_map_curry to "map"?
+ * That is, does it have a nested relation in its domain?
+ */
+int isl_map_can_curry(__isl_keep isl_map *map)
+{
+       if (!map)
+               return -1;
+
+       return isl_space_can_curry(map->dim);
+}
+
+/* Given a basic map (A -> B) -> C, return the corresponding basic map
+ * A -> (B -> C).
+ */
+__isl_give isl_basic_map *isl_basic_map_curry(__isl_take isl_basic_map *bmap)
+{
+
+       if (!bmap)
+               return NULL;
+
+       if (!isl_basic_map_can_curry(bmap))
+               isl_die(bmap->ctx, isl_error_invalid,
+                       "basic map cannot be curried", goto error);
+       bmap->dim = isl_space_curry(bmap->dim);
+       if (!bmap->dim)
+               goto error;
+       return bmap;
+error:
+       isl_basic_map_free(bmap);
+       return NULL;
+}
+
+/* Given a map (A -> B) -> C, return the corresponding map
+ * A -> (B -> C).
+ */
+__isl_give isl_map *isl_map_curry(__isl_take isl_map *map)
+{
+       int i;
+
+       if (!map)
+               return NULL;
+
+       if (!isl_map_can_curry(map))
+               isl_die(map->ctx, isl_error_invalid, "map cannot be curried",
+                       goto error);
+
+       map = isl_map_cow(map);
+       if (!map)
+               return NULL;
+
+       for (i = 0; i < map->n; ++i) {
+               map->p[i] = isl_basic_map_curry(map->p[i]);
+               if (!map->p[i])
+                       goto error;
+       }
+
+       map->dim = isl_space_curry(map->dim);
        if (!map->dim)
                goto error;
 
@@ -9189,8 +10159,6 @@ __isl_give isl_basic_map *isl_basic_map_from_aff(__isl_take isl_aff *aff)
                return NULL;
 
        ls = isl_aff_get_local_space(aff);
-       ls = isl_local_space_from_domain(ls);
-       ls = isl_local_space_add_dims(ls, isl_dim_out, 1);
        bmap = isl_basic_map_from_local_space(ls);
        bmap = isl_basic_map_extend_constraints(bmap, 1, 0);
        k = isl_basic_map_alloc_equality(bmap);
@@ -9212,6 +10180,66 @@ error:
        return NULL;
 }
 
+/* Construct a map mapping the domain of the affine expression
+ * to a one-dimensional range prescribed by the affine expression.
+ */
+__isl_give isl_map *isl_map_from_aff(__isl_take isl_aff *aff)
+{
+       isl_basic_map *bmap;
+
+       bmap = isl_basic_map_from_aff(aff);
+       return isl_map_from_basic_map(bmap);
+}
+
+/* Construct a basic map mapping the domain the multi-affine expression
+ * to its range, with each dimension in the range equated to the
+ * corresponding affine expression.
+ */
+__isl_give isl_basic_map *isl_basic_map_from_multi_aff(
+       __isl_take isl_multi_aff *maff)
+{
+       int i;
+       isl_space *space;
+       isl_basic_map *bmap;
+
+       if (!maff)
+               return NULL;
+
+       if (isl_space_dim(maff->space, isl_dim_out) != maff->n)
+               isl_die(isl_multi_aff_get_ctx(maff), isl_error_internal,
+                       "invalid space", return isl_multi_aff_free(maff));
+
+       space = isl_space_domain(isl_multi_aff_get_space(maff));
+       bmap = isl_basic_map_universe(isl_space_from_domain(space));
+
+       for (i = 0; i < maff->n; ++i) {
+               isl_aff *aff;
+               isl_basic_map *bmap_i;
+
+               aff = isl_aff_copy(maff->p[i]);
+               bmap_i = isl_basic_map_from_aff(aff);
+
+               bmap = isl_basic_map_flat_range_product(bmap, bmap_i);
+       }
+
+       bmap = isl_basic_map_reset_space(bmap, isl_multi_aff_get_space(maff));
+
+       isl_multi_aff_free(maff);
+       return bmap;
+}
+
+/* Construct a map mapping the domain the multi-affine expression
+ * to its range, with each dimension in the range equated to the
+ * corresponding affine expression.
+ */
+__isl_give isl_map *isl_map_from_multi_aff(__isl_take isl_multi_aff *maff)
+{
+       isl_basic_map *bmap;
+
+       bmap = isl_basic_map_from_multi_aff(maff);
+       return isl_map_from_basic_map(bmap);
+}
+
 /* Construct a basic map mapping a domain in the given space to
  * to an n-dimensional range, with n the number of elements in the list,
  * where each coordinate in the range is prescribed by the
@@ -9220,16 +10248,16 @@ error:
  * domain_dim.
  */
 __isl_give isl_basic_map *isl_basic_map_from_aff_list(
-       __isl_take isl_dim *domain_dim, __isl_take isl_aff_list *list)
+       __isl_take isl_space *domain_dim, __isl_take isl_aff_list *list)
 {
        int i;
-       isl_dim *dim;
+       isl_space *dim;
        isl_basic_map *bmap;
 
        if (!list)
                return NULL;
 
-       dim = isl_dim_from_domain(domain_dim);
+       dim = isl_space_from_domain(domain_dim);
        bmap = isl_basic_map_universe(dim);
 
        for (i = 0; i < list->n; ++i) {
@@ -9252,11 +10280,78 @@ __isl_give isl_set *isl_set_equate(__isl_take isl_set *set,
        return isl_map_equate(set, type1, pos1, type2, pos2);
 }
 
+/* Construct a basic map where the given dimensions are equal to each other.
+ */
+static __isl_give isl_basic_map *equator(__isl_take isl_space *space,
+       enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2)
+{
+       isl_basic_map *bmap = NULL;
+       int i;
+
+       if (!space)
+               return NULL;
+
+       if (pos1 >= isl_space_dim(space, type1))
+               isl_die(isl_space_get_ctx(space), isl_error_invalid,
+                       "index out of bounds", goto error);
+       if (pos2 >= isl_space_dim(space, type2))
+               isl_die(isl_space_get_ctx(space), isl_error_invalid,
+                       "index out of bounds", goto error);
+
+       if (type1 == type2 && pos1 == pos2)
+               return isl_basic_map_universe(space);
+
+       bmap = isl_basic_map_alloc_space(isl_space_copy(space), 0, 1, 0);
+       i = isl_basic_map_alloc_equality(bmap);
+       if (i < 0)
+               goto error;
+       isl_seq_clr(bmap->eq[i], 1 + isl_basic_map_total_dim(bmap));
+       pos1 += isl_basic_map_offset(bmap, type1);
+       pos2 += isl_basic_map_offset(bmap, type2);
+       isl_int_set_si(bmap->eq[i][pos1], -1);
+       isl_int_set_si(bmap->eq[i][pos2], 1);
+       bmap = isl_basic_map_finalize(bmap);
+       isl_space_free(space);
+       return bmap;
+error:
+       isl_space_free(space);
+       isl_basic_map_free(bmap);
+       return NULL;
+}
+
+/* Add a constraint imposing that the given two dimensions are equal.
+ */
+__isl_give isl_basic_map *isl_basic_map_equate(__isl_take isl_basic_map *bmap,
+       enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2)
+{
+       isl_basic_map *eq;
+
+       eq = equator(isl_basic_map_get_space(bmap), type1, pos1, type2, pos2);
+
+       bmap = isl_basic_map_intersect(bmap, eq);
+
+       return bmap;
+}
+
 /* Add a constraint imposing that the given two dimensions are equal.
  */
 __isl_give isl_map *isl_map_equate(__isl_take isl_map *map,
        enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2)
 {
+       isl_basic_map *bmap;
+
+       bmap = equator(isl_map_get_space(map), type1, pos1, type2, pos2);
+
+       map = isl_map_intersect(map, isl_map_from_basic_map(bmap));
+
+       return map;
+}
+
+/* Add a constraint imposing that the given two dimensions have opposite values.
+ */
+__isl_give isl_map *isl_map_oppose(__isl_take isl_map *map,
+       enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2)
+{
        isl_basic_map *bmap = NULL;
        int i;
 
@@ -9270,14 +10365,14 @@ __isl_give isl_map *isl_map_equate(__isl_take isl_map *map,
                isl_die(map->ctx, isl_error_invalid,
                        "index out of bounds", goto error);
 
-       bmap = isl_basic_map_alloc_dim(isl_map_get_dim(map), 0, 1, 0);
+       bmap = isl_basic_map_alloc_space(isl_map_get_space(map), 0, 1, 0);
        i = isl_basic_map_alloc_equality(bmap);
        if (i < 0)
                goto error;
        isl_seq_clr(bmap->eq[i], 1 + isl_basic_map_total_dim(bmap));
        pos1 += isl_basic_map_offset(bmap, type1);
        pos2 += isl_basic_map_offset(bmap, type2);
-       isl_int_set_si(bmap->eq[i][pos1], -1);
+       isl_int_set_si(bmap->eq[i][pos1], 1);
        isl_int_set_si(bmap->eq[i][pos2], 1);
        bmap = isl_basic_map_finalize(bmap);
 
@@ -9290,9 +10385,10 @@ error:
        return NULL;
 }
 
-/* Add a constraint imposing that the given two dimensions have opposite values.
+/* Add a constraint imposing that the value of the first dimension is
+ * greater than that of the second.
  */
-__isl_give isl_map *isl_map_oppose(__isl_take isl_map *map,
+__isl_give isl_map *isl_map_order_gt(__isl_take isl_map *map,
        enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2)
 {
        isl_basic_map *bmap = NULL;
@@ -9308,15 +10404,22 @@ __isl_give isl_map *isl_map_oppose(__isl_take isl_map *map,
                isl_die(map->ctx, isl_error_invalid,
                        "index out of bounds", goto error);
 
-       bmap = isl_basic_map_alloc_dim(isl_map_get_dim(map), 0, 1, 0);
-       i = isl_basic_map_alloc_equality(bmap);
+       if (type1 == type2 && pos1 == pos2) {
+               isl_space *space = isl_map_get_space(map);
+               isl_map_free(map);
+               return isl_map_empty(space);
+       }
+
+       bmap = isl_basic_map_alloc_space(isl_map_get_space(map), 0, 0, 1);
+       i = isl_basic_map_alloc_inequality(bmap);
        if (i < 0)
                goto error;
-       isl_seq_clr(bmap->eq[i], 1 + isl_basic_map_total_dim(bmap));
+       isl_seq_clr(bmap->ineq[i], 1 + isl_basic_map_total_dim(bmap));
        pos1 += isl_basic_map_offset(bmap, type1);
        pos2 += isl_basic_map_offset(bmap, type2);
-       isl_int_set_si(bmap->eq[i][pos1], 1);
-       isl_int_set_si(bmap->eq[i][pos2], 1);
+       isl_int_set_si(bmap->ineq[i][pos1], 1);
+       isl_int_set_si(bmap->ineq[i][pos2], -1);
+       isl_int_set_si(bmap->ineq[i][0], -1);
        bmap = isl_basic_map_finalize(bmap);
 
        map = isl_map_intersect(map, isl_map_from_basic_map(bmap));
@@ -9327,3 +10430,151 @@ error:
        isl_map_free(map);
        return NULL;
 }
+
+/* Add a constraint imposing that the value of the first dimension is
+ * smaller than that of the second.
+ */
+__isl_give isl_map *isl_map_order_lt(__isl_take isl_map *map,
+       enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2)
+{
+       return isl_map_order_gt(map, type2, pos2, type1, pos1);
+}
+
+__isl_give isl_aff *isl_basic_map_get_div(__isl_keep isl_basic_map *bmap,
+       int pos)
+{
+       isl_aff *div;
+       isl_local_space *ls;
+
+       if (!bmap)
+               return NULL;
+
+       if (!isl_basic_map_divs_known(bmap))
+               isl_die(isl_basic_map_get_ctx(bmap), isl_error_invalid,
+                       "some divs are unknown", return NULL);
+
+       ls = isl_basic_map_get_local_space(bmap);
+       div = isl_local_space_get_div(ls, pos);
+       isl_local_space_free(ls);
+
+       return div;
+}
+
+__isl_give isl_aff *isl_basic_set_get_div(__isl_keep isl_basic_set *bset,
+       int pos)
+{
+       return isl_basic_map_get_div(bset, pos);
+}
+
+/* Plug in "subs" for dimension "type", "pos" of "bset".
+ *
+ * Let i be the dimension to replace and let "subs" be of the form
+ *
+ *     f/d
+ *
+ * Any integer division with a non-zero coefficient for i,
+ *
+ *     floor((a i + g)/m)
+ *
+ * is replaced by
+ *
+ *     floor((a f + d g)/(m d))
+ *
+ * Constraints of the form
+ *
+ *     a i + g
+ *
+ * are replaced by
+ *
+ *     a f + d g
+ */
+__isl_give isl_basic_set *isl_basic_set_substitute(
+       __isl_take isl_basic_set *bset,
+       enum isl_dim_type type, unsigned pos, __isl_keep isl_aff *subs)
+{
+       int i;
+       isl_int v;
+       isl_ctx *ctx;
+
+       if (bset && isl_basic_set_plain_is_empty(bset))
+               return bset;
+
+       bset = isl_basic_set_cow(bset);
+       if (!bset || !subs)
+               goto error;
+
+       ctx = isl_basic_set_get_ctx(bset);
+       if (!isl_space_is_equal(bset->dim, subs->ls->dim))
+               isl_die(ctx, isl_error_invalid,
+                       "spaces don't match", goto error);
+       if (isl_local_space_dim(subs->ls, isl_dim_div) != 0)
+               isl_die(ctx, isl_error_unsupported,
+                       "cannot handle divs yet", goto error);
+
+       pos += isl_basic_set_offset(bset, type);
+
+       isl_int_init(v);
+
+       for (i = 0; i < bset->n_eq; ++i) {
+               if (isl_int_is_zero(bset->eq[i][pos]))
+                       continue;
+               isl_int_set(v, bset->eq[i][pos]);
+               isl_int_set_si(bset->eq[i][pos], 0);
+               isl_seq_combine(bset->eq[i], subs->v->el[0], bset->eq[i],
+                               v, subs->v->el + 1, subs->v->size - 1);
+       }
+
+       for (i = 0; i < bset->n_ineq; ++i) {
+               if (isl_int_is_zero(bset->ineq[i][pos]))
+                       continue;
+               isl_int_set(v, bset->ineq[i][pos]);
+               isl_int_set_si(bset->ineq[i][pos], 0);
+               isl_seq_combine(bset->ineq[i], subs->v->el[0], bset->ineq[i],
+                               v, subs->v->el + 1, subs->v->size - 1);
+       }
+
+       for (i = 0; i < bset->n_div; ++i) {
+               if (isl_int_is_zero(bset->div[i][1 + pos]))
+                       continue;
+               isl_int_set(v, bset->div[i][1 + pos]);
+               isl_int_set_si(bset->div[i][1 + pos], 0);
+               isl_seq_combine(bset->div[i] + 1,
+                               subs->v->el[0], bset->div[i] + 1,
+                               v, subs->v->el + 1, subs->v->size - 1);
+               isl_int_mul(bset->div[i][0], bset->div[i][0], subs->v->el[0]);
+       }
+
+       isl_int_clear(v);
+
+       bset = isl_basic_set_simplify(bset);
+       return isl_basic_set_finalize(bset);
+error:
+       isl_basic_set_free(bset);
+       return NULL;
+}
+
+/* Plug in "subs" for dimension "type", "pos" of "set".
+ */
+__isl_give isl_set *isl_set_substitute(__isl_take isl_set *set,
+       enum isl_dim_type type, unsigned pos, __isl_keep isl_aff *subs)
+{
+       int i;
+
+       if (set && isl_set_plain_is_empty(set))
+               return set;
+
+       set = isl_set_cow(set);
+       if (!set || !subs)
+               goto error;
+
+       for (i = set->n - 1; i >= 0; --i) {
+               set->p[i] = isl_basic_set_substitute(set->p[i], type, pos, subs);
+               if (remove_if_empty(set, i) < 0)
+                       goto error;
+       }
+
+       return set;
+error:
+       isl_set_free(set);
+       return NULL;
+}