Home | History | Annotate | Line # | Download | only in dist
      1 /*
      2  * Copyright 2008-2009 Katholieke Universiteit Leuven
      3  *
      4  * Use of this software is governed by the MIT license
      5  *
      6  * Written by Sven Verdoolaege, K.U.Leuven, Departement
      7  * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
      8  */
      9 
     10 #include <isl_ctx_private.h>
     11 #include <isl_map_private.h>
     12 #include "isl_basis_reduction.h"
     13 #include "isl_scan.h"
     14 #include <isl_seq.h>
     15 #include "isl_tab.h"
     16 #include <isl_val_private.h>
     17 #include <isl_vec_private.h>
     18 
     19 struct isl_counter {
     20 	struct isl_scan_callback callback;
     21 	isl_int count;
     22 	isl_int max;
     23 };
     24 
     25 static isl_stat increment_counter(struct isl_scan_callback *cb,
     26 	__isl_take isl_vec *sample)
     27 {
     28 	struct isl_counter *cnt = (struct isl_counter *)cb;
     29 
     30 	isl_int_add_ui(cnt->count, cnt->count, 1);
     31 
     32 	isl_vec_free(sample);
     33 
     34 	if (isl_int_is_zero(cnt->max) || isl_int_lt(cnt->count, cnt->max))
     35 		return isl_stat_ok;
     36 	return isl_stat_error;
     37 }
     38 
     39 static int increment_range(struct isl_scan_callback *cb, isl_int min, isl_int max)
     40 {
     41 	struct isl_counter *cnt = (struct isl_counter *)cb;
     42 
     43 	isl_int_add(cnt->count, cnt->count, max);
     44 	isl_int_sub(cnt->count, cnt->count, min);
     45 	isl_int_add_ui(cnt->count, cnt->count, 1);
     46 
     47 	if (isl_int_is_zero(cnt->max) || isl_int_lt(cnt->count, cnt->max))
     48 		return 0;
     49 	isl_int_set(cnt->count, cnt->max);
     50 	return -1;
     51 }
     52 
     53 /* Call callback->add with the current sample value of the tableau "tab".
     54  */
     55 static int add_solution(struct isl_tab *tab, struct isl_scan_callback *callback)
     56 {
     57 	struct isl_vec *sample;
     58 
     59 	if (!tab)
     60 		return -1;
     61 	sample = isl_tab_get_sample_value(tab);
     62 	if (!sample)
     63 		return -1;
     64 
     65 	return callback->add(callback, sample);
     66 }
     67 
     68 static isl_stat scan_0D(__isl_take isl_basic_set *bset,
     69 	struct isl_scan_callback *callback)
     70 {
     71 	struct isl_vec *sample;
     72 
     73 	sample = isl_vec_alloc(bset->ctx, 1);
     74 	isl_basic_set_free(bset);
     75 
     76 	if (!sample)
     77 		return isl_stat_error;
     78 
     79 	isl_int_set_si(sample->el[0], 1);
     80 
     81 	return callback->add(callback, sample);
     82 }
     83 
     84 /* Look for all integer points in "bset", which is assumed to be bounded,
     85  * and call callback->add on each of them.
     86  *
     87  * We first compute a reduced basis for the set and then scan
     88  * the set in the directions of this basis.
     89  * We basically perform a depth first search, where in each level i
     90  * we compute the range in the i-th basis vector direction, given
     91  * fixed values in the directions of the previous basis vector.
     92  * We then add an equality to the tableau fixing the value in the
     93  * direction of the current basis vector to each value in the range
     94  * in turn and then continue to the next level.
     95  *
     96  * The search is implemented iteratively.  "level" identifies the current
     97  * basis vector.  "init" is true if we want the first value at the current
     98  * level and false if we want the next value.
     99  * Solutions are added in the leaves of the search tree, i.e., after
    100  * we have fixed a value in each direction of the basis.
    101  */
    102 isl_stat isl_basic_set_scan(__isl_take isl_basic_set *bset,
    103 	struct isl_scan_callback *callback)
    104 {
    105 	isl_size dim;
    106 	struct isl_mat *B = NULL;
    107 	struct isl_tab *tab = NULL;
    108 	struct isl_vec *min;
    109 	struct isl_vec *max;
    110 	struct isl_tab_undo **snap;
    111 	int level;
    112 	int init;
    113 	enum isl_lp_result res;
    114 
    115 	dim = isl_basic_set_dim(bset, isl_dim_all);
    116 	if (dim < 0) {
    117 		bset = isl_basic_set_free(bset);
    118 		return isl_stat_error;
    119 	}
    120 
    121 	if (dim == 0)
    122 		return scan_0D(bset, callback);
    123 
    124 	min = isl_vec_alloc(bset->ctx, dim);
    125 	max = isl_vec_alloc(bset->ctx, dim);
    126 	snap = isl_alloc_array(bset->ctx, struct isl_tab_undo *, dim);
    127 
    128 	if (!min || !max || !snap)
    129 		goto error;
    130 
    131 	tab = isl_tab_from_basic_set(bset, 0);
    132 	if (!tab)
    133 		goto error;
    134 	if (isl_tab_extend_cons(tab, dim + 1) < 0)
    135 		goto error;
    136 
    137 	tab->basis = isl_mat_identity(bset->ctx, 1 + dim);
    138 	if (1)
    139 		tab = isl_tab_compute_reduced_basis(tab);
    140 	if (!tab)
    141 		goto error;
    142 	B = isl_mat_copy(tab->basis);
    143 	if (!B)
    144 		goto error;
    145 
    146 	level = 0;
    147 	init = 1;
    148 
    149 	while (level >= 0) {
    150 		int empty = 0;
    151 		if (init) {
    152 			res = isl_tab_min(tab, B->row[1 + level],
    153 				    bset->ctx->one, &min->el[level], NULL, 0);
    154 			if (res == isl_lp_empty)
    155 				empty = 1;
    156 			if (res == isl_lp_error || res == isl_lp_unbounded)
    157 				goto error;
    158 			isl_seq_neg(B->row[1 + level] + 1,
    159 				    B->row[1 + level] + 1, dim);
    160 			res = isl_tab_min(tab, B->row[1 + level],
    161 				    bset->ctx->one, &max->el[level], NULL, 0);
    162 			isl_seq_neg(B->row[1 + level] + 1,
    163 				    B->row[1 + level] + 1, dim);
    164 			isl_int_neg(max->el[level], max->el[level]);
    165 			if (res == isl_lp_empty)
    166 				empty = 1;
    167 			if (res == isl_lp_error || res == isl_lp_unbounded)
    168 				goto error;
    169 			snap[level] = isl_tab_snap(tab);
    170 		} else
    171 			isl_int_add_ui(min->el[level], min->el[level], 1);
    172 
    173 		if (empty || isl_int_gt(min->el[level], max->el[level])) {
    174 			level--;
    175 			init = 0;
    176 			if (level >= 0)
    177 				if (isl_tab_rollback(tab, snap[level]) < 0)
    178 					goto error;
    179 			continue;
    180 		}
    181 		if (level == dim - 1 && callback->add == increment_counter) {
    182 			if (increment_range(callback,
    183 					    min->el[level], max->el[level]))
    184 				goto error;
    185 			level--;
    186 			init = 0;
    187 			if (level >= 0)
    188 				if (isl_tab_rollback(tab, snap[level]) < 0)
    189 					goto error;
    190 			continue;
    191 		}
    192 		isl_int_neg(B->row[1 + level][0], min->el[level]);
    193 		if (isl_tab_add_valid_eq(tab, B->row[1 + level]) < 0)
    194 			goto error;
    195 		isl_int_set_si(B->row[1 + level][0], 0);
    196 		if (level < dim - 1) {
    197 			++level;
    198 			init = 1;
    199 			continue;
    200 		}
    201 		if (add_solution(tab, callback) < 0)
    202 			goto error;
    203 		init = 0;
    204 		if (isl_tab_rollback(tab, snap[level]) < 0)
    205 			goto error;
    206 	}
    207 
    208 	isl_tab_free(tab);
    209 	free(snap);
    210 	isl_vec_free(min);
    211 	isl_vec_free(max);
    212 	isl_basic_set_free(bset);
    213 	isl_mat_free(B);
    214 	return isl_stat_ok;
    215 error:
    216 	isl_tab_free(tab);
    217 	free(snap);
    218 	isl_vec_free(min);
    219 	isl_vec_free(max);
    220 	isl_basic_set_free(bset);
    221 	isl_mat_free(B);
    222 	return isl_stat_error;
    223 }
    224 
    225 isl_stat isl_set_scan(__isl_take isl_set *set,
    226 	struct isl_scan_callback *callback)
    227 {
    228 	int i;
    229 
    230 	if (!set || !callback)
    231 		goto error;
    232 
    233 	set = isl_set_cow(set);
    234 	set = isl_set_make_disjoint(set);
    235 	set = isl_set_compute_divs(set);
    236 	if (!set)
    237 		goto error;
    238 
    239 	for (i = 0; i < set->n; ++i)
    240 		if (isl_basic_set_scan(isl_basic_set_copy(set->p[i]),
    241 					callback) < 0)
    242 			goto error;
    243 
    244 	isl_set_free(set);
    245 	return isl_stat_ok;
    246 error:
    247 	isl_set_free(set);
    248 	return isl_stat_error;
    249 }
    250 
    251 int isl_basic_set_count_upto(__isl_keep isl_basic_set *bset,
    252 	isl_int max, isl_int *count)
    253 {
    254 	struct isl_counter cnt = { { &increment_counter } };
    255 
    256 	if (!bset)
    257 		return -1;
    258 
    259 	isl_int_init(cnt.count);
    260 	isl_int_init(cnt.max);
    261 
    262 	isl_int_set_si(cnt.count, 0);
    263 	isl_int_set(cnt.max, max);
    264 	if (isl_basic_set_scan(isl_basic_set_copy(bset), &cnt.callback) < 0 &&
    265 	    isl_int_lt(cnt.count, cnt.max))
    266 		goto error;
    267 
    268 	isl_int_set(*count, cnt.count);
    269 	isl_int_clear(cnt.max);
    270 	isl_int_clear(cnt.count);
    271 
    272 	return 0;
    273 error:
    274 	isl_int_clear(cnt.count);
    275 	return -1;
    276 }
    277 
    278 int isl_set_count_upto(__isl_keep isl_set *set, isl_int max, isl_int *count)
    279 {
    280 	struct isl_counter cnt = { { &increment_counter } };
    281 
    282 	if (!set)
    283 		return -1;
    284 
    285 	isl_int_init(cnt.count);
    286 	isl_int_init(cnt.max);
    287 
    288 	isl_int_set_si(cnt.count, 0);
    289 	isl_int_set(cnt.max, max);
    290 	if (isl_set_scan(isl_set_copy(set), &cnt.callback) < 0 &&
    291 	    isl_int_lt(cnt.count, cnt.max))
    292 		goto error;
    293 
    294 	isl_int_set(*count, cnt.count);
    295 	isl_int_clear(cnt.max);
    296 	isl_int_clear(cnt.count);
    297 
    298 	return 0;
    299 error:
    300 	isl_int_clear(cnt.count);
    301 	return -1;
    302 }
    303 
    304 int isl_set_count(__isl_keep isl_set *set, isl_int *count)
    305 {
    306 	if (!set)
    307 		return -1;
    308 	return isl_set_count_upto(set, set->ctx->zero, count);
    309 }
    310 
    311 /* Count the total number of elements in "set" (in an inefficient way) and
    312  * return the result.
    313  */
    314 __isl_give isl_val *isl_set_count_val(__isl_keep isl_set *set)
    315 {
    316 	isl_val *v;
    317 
    318 	if (!set)
    319 		return NULL;
    320 	v = isl_val_zero(isl_set_get_ctx(set));
    321 	v = isl_val_cow(v);
    322 	if (!v)
    323 		return NULL;
    324 	if (isl_set_count(set, &v->n) < 0)
    325 		v = isl_val_free(v);
    326 	return v;
    327 }
    328