1 /*
2  * Copyright 2010      INRIA Saclay
3  * Copyright 2013      Ecole Normale Superieure
4  * Copyright 2015      Sven Verdoolaege
5  * Copyright 2019      Cerebras Systems
6  *
7  * Use of this software is governed by the MIT license
8  *
9  * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
10  * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
11  * 91893 Orsay, France
12  * and Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France
13  * and Cerebras Systems, 175 S San Antonio Rd, Los Altos, CA, USA
14  */
15 
16 #include <isl_map_private.h>
17 #include <isl_point_private.h>
18 #include <isl/set.h>
19 #include <isl/union_set.h>
20 #include <isl_sample.h>
21 #include <isl_scan.h>
22 #include <isl_seq.h>
23 #include <isl_space_private.h>
24 #include <isl_local_private.h>
25 #include <isl_val_private.h>
26 #include <isl_vec_private.h>
27 #include <isl_output_private.h>
28 
29 #include <set_to_map.c>
30 
isl_point_get_ctx(__isl_keep isl_point * pnt)31 isl_ctx *isl_point_get_ctx(__isl_keep isl_point *pnt)
32 {
33 	return pnt ? isl_space_get_ctx(pnt->dim) : NULL;
34 }
35 
36 /* Return the space of "pnt".
37  */
isl_point_peek_space(__isl_keep isl_point * pnt)38 __isl_keep isl_space *isl_point_peek_space(__isl_keep isl_point *pnt)
39 {
40 	return pnt ? pnt->dim : NULL;
41 }
42 
isl_point_get_space(__isl_keep isl_point * pnt)43 __isl_give isl_space *isl_point_get_space(__isl_keep isl_point *pnt)
44 {
45 	return isl_space_copy(isl_point_peek_space(pnt));
46 }
47 
48 #undef TYPE1
49 #define TYPE1		isl_basic_map
50 #undef TYPE2
51 #define TYPE2		isl_point
52 #undef TYPE_PAIR
53 #define TYPE_PAIR	isl_basic_map_point
54 
55 static
56 #include "isl_type_has_equal_space_templ.c"
57 static
58 #include "isl_type_check_equal_space_templ.c"
59 
isl_point_alloc(__isl_take isl_space * space,__isl_take isl_vec * vec)60 __isl_give isl_point *isl_point_alloc(__isl_take isl_space *space,
61 	__isl_take isl_vec *vec)
62 {
63 	struct isl_point *pnt;
64 	isl_size dim;
65 
66 	dim = isl_space_dim(space, isl_dim_all);
67 	if (dim < 0 || !vec)
68 		goto error;
69 
70 	if (vec->size > 1 + dim) {
71 		vec = isl_vec_cow(vec);
72 		if (!vec)
73 			goto error;
74 		vec->size = 1 + dim;
75 	}
76 
77 	pnt = isl_alloc_type(space->ctx, struct isl_point);
78 	if (!pnt)
79 		goto error;
80 
81 	pnt->ref = 1;
82 	pnt->dim = space;
83 	pnt->vec = vec;
84 
85 	return pnt;
86 error:
87 	isl_space_free(space);
88 	isl_vec_free(vec);
89 	return NULL;
90 }
91 
isl_point_zero(__isl_take isl_space * space)92 __isl_give isl_point *isl_point_zero(__isl_take isl_space *space)
93 {
94 	isl_vec *vec;
95 	isl_size dim;
96 
97 	dim = isl_space_dim(space, isl_dim_all);
98 	if (dim < 0)
99 		goto error;
100 	vec = isl_vec_alloc(space->ctx, 1 + dim);
101 	if (!vec)
102 		goto error;
103 	isl_int_set_si(vec->el[0], 1);
104 	isl_seq_clr(vec->el + 1, vec->size - 1);
105 	return isl_point_alloc(space, vec);
106 error:
107 	isl_space_free(space);
108 	return NULL;
109 }
110 
isl_point_dup(__isl_keep isl_point * pnt)111 __isl_give isl_point *isl_point_dup(__isl_keep isl_point *pnt)
112 {
113 	struct isl_point *pnt2;
114 
115 	if (!pnt)
116 		return NULL;
117 	pnt2 = isl_point_alloc(isl_space_copy(pnt->dim), isl_vec_copy(pnt->vec));
118 	return pnt2;
119 }
120 
isl_point_cow(__isl_take isl_point * pnt)121 __isl_give isl_point *isl_point_cow(__isl_take isl_point *pnt)
122 {
123 	struct isl_point *pnt2;
124 	if (!pnt)
125 		return NULL;
126 
127 	if (pnt->ref == 1)
128 		return pnt;
129 
130 	pnt2 = isl_point_dup(pnt);
131 	isl_point_free(pnt);
132 	return pnt2;
133 }
134 
isl_point_copy(__isl_keep isl_point * pnt)135 __isl_give isl_point *isl_point_copy(__isl_keep isl_point *pnt)
136 {
137 	if (!pnt)
138 		return NULL;
139 
140 	pnt->ref++;
141 	return pnt;
142 }
143 
isl_point_free(__isl_take isl_point * pnt)144 __isl_null isl_point *isl_point_free(__isl_take isl_point *pnt)
145 {
146 	if (!pnt)
147 		return NULL;
148 
149 	if (--pnt->ref > 0)
150 		return NULL;
151 
152 	isl_space_free(pnt->dim);
153 	isl_vec_free(pnt->vec);
154 	free(pnt);
155 	return NULL;
156 }
157 
isl_point_void(__isl_take isl_space * space)158 __isl_give isl_point *isl_point_void(__isl_take isl_space *space)
159 {
160 	if (!space)
161 		return NULL;
162 
163 	return isl_point_alloc(space, isl_vec_alloc(space->ctx, 0));
164 }
165 
isl_point_is_void(__isl_keep isl_point * pnt)166 isl_bool isl_point_is_void(__isl_keep isl_point *pnt)
167 {
168 	if (!pnt)
169 		return isl_bool_error;
170 
171 	return isl_bool_ok(pnt->vec->size == 0);
172 }
173 
174 /* Return the space of "pnt".
175  * This may be either a copy or the space itself
176  * if there is only one reference to "pnt".
177  * This allows the space to be modified inplace
178  * if both the point and its space have only a single reference.
179  * The caller is not allowed to modify "pnt" between this call and
180  * a subsequent call to isl_point_restore_space.
181  * The only exception is that isl_point_free can be called instead.
182  */
isl_point_take_space(__isl_keep isl_point * pnt)183 __isl_give isl_space *isl_point_take_space(__isl_keep isl_point *pnt)
184 {
185 	isl_space *space;
186 
187 	if (!pnt)
188 		return NULL;
189 	if (pnt->ref != 1)
190 		return isl_point_get_space(pnt);
191 	space = pnt->dim;
192 	pnt->dim = NULL;
193 	return space;
194 }
195 
196 /* Set the space of "pnt" to "space", where the space of "pnt" may be missing
197  * due to a preceding call to isl_point_take_space.
198  * However, in this case, "pnt" only has a single reference and
199  * then the call to isl_point_cow has no effect.
200  */
isl_point_restore_space(__isl_take isl_point * pnt,__isl_take isl_space * space)201 __isl_give isl_point *isl_point_restore_space(__isl_take isl_point *pnt,
202 	__isl_take isl_space *space)
203 {
204 	if (!pnt || !space)
205 		goto error;
206 
207 	if (pnt->dim == space) {
208 		isl_space_free(space);
209 		return pnt;
210 	}
211 
212 	pnt = isl_point_cow(pnt);
213 	if (!pnt)
214 		goto error;
215 	isl_space_free(pnt->dim);
216 	pnt->dim = space;
217 
218 	return pnt;
219 error:
220 	isl_point_free(pnt);
221 	isl_space_free(space);
222 	return NULL;
223 }
224 
225 /* Return the coordinate vector of "pnt".
226  */
isl_point_peek_vec(__isl_keep isl_point * pnt)227 __isl_keep isl_vec *isl_point_peek_vec(__isl_keep isl_point *pnt)
228 {
229 	return pnt ? pnt->vec : NULL;
230 }
231 
232 /* Return a copy of the coordinate vector of "pnt".
233  */
isl_point_get_vec(__isl_keep isl_point * pnt)234 __isl_give isl_vec *isl_point_get_vec(__isl_keep isl_point *pnt)
235 {
236 	return isl_vec_copy(isl_point_peek_vec(pnt));
237 }
238 
239 /* Return the coordinate vector of "pnt".
240  * This may be either a copy or the coordinate vector itself
241  * if there is only one reference to "pnt".
242  * This allows the coordinate vector to be modified inplace
243  * if both the point and its coordinate vector have only a single reference.
244  * The caller is not allowed to modify "pnt" between this call and
245  * a subsequent call to isl_point_restore_vec.
246  * The only exception is that isl_point_free can be called instead.
247  */
isl_point_take_vec(__isl_keep isl_point * pnt)248 __isl_give isl_vec *isl_point_take_vec(__isl_keep isl_point *pnt)
249 {
250 	isl_vec *vec;
251 
252 	if (!pnt)
253 		return NULL;
254 	if (pnt->ref != 1)
255 		return isl_point_get_vec(pnt);
256 	vec = pnt->vec;
257 	pnt->vec = NULL;
258 	return vec;
259 }
260 
261 /* Set the coordinate vector of "pnt" to "vec",
262  * where the coordinate vector of "pnt" may be missing
263  * due to a preceding call to isl_point_take_vec.
264  * However, in this case, "pnt" only has a single reference and
265  * then the call to isl_point_cow has no effect.
266  */
isl_point_restore_vec(__isl_take isl_point * pnt,__isl_take isl_vec * vec)267 __isl_give isl_point *isl_point_restore_vec(__isl_take isl_point *pnt,
268 	__isl_take isl_vec *vec)
269 {
270 	if (!pnt || !vec)
271 		goto error;
272 
273 	if (pnt->vec == vec) {
274 		isl_vec_free(vec);
275 		return pnt;
276 	}
277 
278 	pnt = isl_point_cow(pnt);
279 	if (!pnt)
280 		goto error;
281 	isl_vec_free(pnt->vec);
282 	pnt->vec = vec;
283 
284 	return pnt;
285 error:
286 	isl_point_free(pnt);
287 	isl_vec_free(vec);
288 	return NULL;
289 }
290 
291 /* Return the number of variables of the given type.
292  */
isl_point_dim(__isl_keep isl_point * pnt,enum isl_dim_type type)293 static isl_size isl_point_dim(__isl_keep isl_point *pnt, enum isl_dim_type type)
294 {
295 	return isl_space_dim(isl_point_peek_space(pnt), type);
296 }
297 
298 /* Return the position of the coordinates of the given type
299  * within the sequence of coordinates of "pnt".
300  */
isl_point_var_offset(__isl_keep isl_point * pnt,enum isl_dim_type type)301 static isl_size isl_point_var_offset(__isl_keep isl_point *pnt,
302 	enum isl_dim_type type)
303 {
304 	return pnt ? isl_space_offset(pnt->dim, type) : isl_size_error;
305 }
306 
307 #undef TYPE
308 #define TYPE	isl_point
309 static
310 #include "check_type_range_templ.c"
311 
312 /* Return the value of coordinate "pos" of type "type" of "pnt".
313  */
isl_point_get_coordinate_val(__isl_keep isl_point * pnt,enum isl_dim_type type,int pos)314 __isl_give isl_val *isl_point_get_coordinate_val(__isl_keep isl_point *pnt,
315 	enum isl_dim_type type, int pos)
316 {
317 	isl_ctx *ctx;
318 	isl_val *v;
319 	isl_size off;
320 
321 	if (!pnt)
322 		return NULL;
323 
324 	ctx = isl_point_get_ctx(pnt);
325 	if (isl_point_is_void(pnt))
326 		isl_die(ctx, isl_error_invalid,
327 			"void point does not have coordinates", return NULL);
328 	if (isl_point_check_range(pnt, type, pos, 1) < 0)
329 		return NULL;
330 
331 	off = isl_point_var_offset(pnt, type);
332 	if (off < 0)
333 		return NULL;
334 	pos += off;
335 
336 	v = isl_val_rat_from_isl_int(ctx, pnt->vec->el[1 + pos],
337 						pnt->vec->el[0]);
338 	return isl_val_normalize(v);
339 }
340 
341 /* Set all entries of "mv" to NaN.
342  */
set_nan(__isl_take isl_multi_val * mv)343 static __isl_give isl_multi_val *set_nan(__isl_take isl_multi_val *mv)
344 {
345 	int i;
346 	isl_size n;
347 	isl_val *v;
348 
349 	n = isl_multi_val_size(mv);
350 	if (n < 0)
351 		return isl_multi_val_free(mv);
352 	v = isl_val_nan(isl_multi_val_get_ctx(mv));
353 	for (i = 0; i < n; ++i)
354 		mv = isl_multi_val_set_at(mv, i, isl_val_copy(v));
355 	isl_val_free(v);
356 
357 	return mv;
358 }
359 
360 /* Return the values of the set dimensions of "pnt".
361  * Return a sequence of NaNs in case of a void point.
362  */
isl_point_get_multi_val(__isl_keep isl_point * pnt)363 __isl_give isl_multi_val *isl_point_get_multi_val(__isl_keep isl_point *pnt)
364 {
365 	int i;
366 	isl_bool is_void;
367 	isl_size n;
368 	isl_multi_val *mv;
369 
370 	is_void = isl_point_is_void(pnt);
371 	if (is_void < 0)
372 		return NULL;
373 
374 	mv = isl_multi_val_alloc(isl_point_get_space(pnt));
375 	if (is_void)
376 		return set_nan(mv);
377 	n = isl_multi_val_size(mv);
378 	if (n < 0)
379 		return isl_multi_val_free(mv);
380 	for (i = 0; i < n; ++i) {
381 		isl_val *v;
382 
383 		v = isl_point_get_coordinate_val(pnt, isl_dim_set, i);
384 		mv = isl_multi_val_set_at(mv, i, v);
385 	}
386 
387 	return mv;
388 }
389 
390 /* Replace coordinate "pos" of type "type" of "pnt" by "v".
391  */
isl_point_set_coordinate_val(__isl_take isl_point * pnt,enum isl_dim_type type,int pos,__isl_take isl_val * v)392 __isl_give isl_point *isl_point_set_coordinate_val(__isl_take isl_point *pnt,
393 	enum isl_dim_type type, int pos, __isl_take isl_val *v)
394 {
395 	if (!pnt || !v)
396 		goto error;
397 	if (isl_point_is_void(pnt))
398 		isl_die(isl_point_get_ctx(pnt), isl_error_invalid,
399 			"void point does not have coordinates", goto error);
400 	if (isl_point_check_range(pnt, type, pos, 1) < 0)
401 		goto error;
402 	if (!isl_val_is_rat(v))
403 		isl_die(isl_point_get_ctx(pnt), isl_error_invalid,
404 			"expecting rational value", goto error);
405 
406 	pos += isl_space_offset(isl_point_peek_space(pnt), type);
407 	if (isl_int_eq(pnt->vec->el[1 + pos], v->n) &&
408 	    isl_int_eq(pnt->vec->el[0], v->d)) {
409 		isl_val_free(v);
410 		return pnt;
411 	}
412 
413 	pnt = isl_point_cow(pnt);
414 	if (!pnt)
415 		goto error;
416 	pnt->vec = isl_vec_cow(pnt->vec);
417 	if (!pnt->vec)
418 		goto error;
419 
420 	if (isl_int_eq(pnt->vec->el[0], v->d)) {
421 		isl_int_set(pnt->vec->el[1 + pos], v->n);
422 	} else if (isl_int_is_one(v->d)) {
423 		isl_int_mul(pnt->vec->el[1 + pos], pnt->vec->el[0], v->n);
424 	} else {
425 		isl_seq_scale(pnt->vec->el + 1,
426 				pnt->vec->el + 1, v->d, pnt->vec->size - 1);
427 		isl_int_mul(pnt->vec->el[1 + pos], pnt->vec->el[0], v->n);
428 		isl_int_mul(pnt->vec->el[0], pnt->vec->el[0], v->d);
429 		pnt->vec = isl_vec_normalize(pnt->vec);
430 		if (!pnt->vec)
431 			goto error;
432 	}
433 
434 	isl_val_free(v);
435 	return pnt;
436 error:
437 	isl_val_free(v);
438 	isl_point_free(pnt);
439 	return NULL;
440 }
441 
isl_point_add_ui(__isl_take isl_point * pnt,enum isl_dim_type type,int pos,unsigned val)442 __isl_give isl_point *isl_point_add_ui(__isl_take isl_point *pnt,
443 	enum isl_dim_type type, int pos, unsigned val)
444 {
445 	isl_size off;
446 
447 	if (!pnt || isl_point_is_void(pnt))
448 		return pnt;
449 
450 	pnt = isl_point_cow(pnt);
451 	if (!pnt)
452 		return NULL;
453 	pnt->vec = isl_vec_cow(pnt->vec);
454 	if (!pnt->vec)
455 		goto error;
456 
457 	off = isl_point_var_offset(pnt, type);
458 	if (off < 0)
459 		goto error;
460 	pos += off;
461 
462 	isl_int_add_ui(pnt->vec->el[1 + pos], pnt->vec->el[1 + pos], val);
463 
464 	return pnt;
465 error:
466 	isl_point_free(pnt);
467 	return NULL;
468 }
469 
isl_point_sub_ui(__isl_take isl_point * pnt,enum isl_dim_type type,int pos,unsigned val)470 __isl_give isl_point *isl_point_sub_ui(__isl_take isl_point *pnt,
471 	enum isl_dim_type type, int pos, unsigned val)
472 {
473 	isl_size off;
474 
475 	if (!pnt || isl_point_is_void(pnt))
476 		return pnt;
477 
478 	pnt = isl_point_cow(pnt);
479 	if (!pnt)
480 		return NULL;
481 	pnt->vec = isl_vec_cow(pnt->vec);
482 	if (!pnt->vec)
483 		goto error;
484 
485 	off = isl_point_var_offset(pnt, type);
486 	if (off < 0)
487 		goto error;
488 	pos += off;
489 
490 	isl_int_sub_ui(pnt->vec->el[1 + pos], pnt->vec->el[1 + pos], val);
491 
492 	return pnt;
493 error:
494 	isl_point_free(pnt);
495 	return NULL;
496 }
497 
498 struct isl_foreach_point {
499 	struct isl_scan_callback callback;
500 	isl_stat (*fn)(__isl_take isl_point *pnt, void *user);
501 	void *user;
502 	isl_space *dim;
503 };
504 
foreach_point(struct isl_scan_callback * cb,__isl_take isl_vec * sample)505 static isl_stat foreach_point(struct isl_scan_callback *cb,
506 	__isl_take isl_vec *sample)
507 {
508 	struct isl_foreach_point *fp = (struct isl_foreach_point *)cb;
509 	isl_point *pnt;
510 
511 	pnt = isl_point_alloc(isl_space_copy(fp->dim), sample);
512 
513 	return fp->fn(pnt, fp->user);
514 }
515 
isl_set_foreach_point(__isl_keep isl_set * set,isl_stat (* fn)(__isl_take isl_point * pnt,void * user),void * user)516 isl_stat isl_set_foreach_point(__isl_keep isl_set *set,
517 	isl_stat (*fn)(__isl_take isl_point *pnt, void *user), void *user)
518 {
519 	struct isl_foreach_point fp = { { &foreach_point }, fn, user };
520 	int i;
521 
522 	if (!set)
523 		return isl_stat_error;
524 
525 	fp.dim = isl_set_get_space(set);
526 	if (!fp.dim)
527 		return isl_stat_error;
528 
529 	set = isl_set_copy(set);
530 	set = isl_set_cow(set);
531 	set = isl_set_make_disjoint(set);
532 	set = isl_set_compute_divs(set);
533 	if (!set)
534 		goto error;
535 
536 	for (i = 0; i < set->n; ++i)
537 		if (isl_basic_set_scan(isl_basic_set_copy(set->p[i]),
538 					&fp.callback) < 0)
539 			goto error;
540 
541 	isl_set_free(set);
542 	isl_space_free(fp.dim);
543 
544 	return isl_stat_ok;
545 error:
546 	isl_set_free(set);
547 	isl_space_free(fp.dim);
548 	return isl_stat_error;
549 }
550 
551 /* Return 1 if "bmap" contains the point "point".
552  * "bmap" is assumed to have known divs.
553  * The point is first extended with the divs and then passed
554  * to basic_map_contains.
555  */
isl_basic_map_contains_point(__isl_keep isl_basic_map * bmap,__isl_keep isl_point * point)556 isl_bool isl_basic_map_contains_point(__isl_keep isl_basic_map *bmap,
557 	__isl_keep isl_point *point)
558 {
559 	isl_local *local;
560 	isl_vec *vec;
561 	isl_bool contains;
562 
563 	if (isl_basic_map_point_check_equal_space(bmap, point) < 0)
564 		return isl_bool_error;
565 	if (bmap->n_div == 0)
566 		return isl_basic_map_contains(bmap, point->vec);
567 
568 	local = isl_local_alloc_from_mat(isl_basic_map_get_divs(bmap));
569 	vec = isl_point_get_vec(point);
570 	vec = isl_local_extend_point_vec(local, vec);
571 	isl_local_free(local);
572 
573 	contains = isl_basic_map_contains(bmap, vec);
574 
575 	isl_vec_free(vec);
576 	return contains;
577 }
578 
isl_map_contains_point(__isl_keep isl_map * map,__isl_keep isl_point * point)579 isl_bool isl_map_contains_point(__isl_keep isl_map *map,
580 	__isl_keep isl_point *point)
581 {
582 	int i;
583 	isl_bool found = isl_bool_false;
584 
585 	if (!map || !point)
586 		return isl_bool_error;
587 
588 	map = isl_map_copy(map);
589 	map = isl_map_compute_divs(map);
590 	if (!map)
591 		return isl_bool_error;
592 
593 	for (i = 0; i < map->n; ++i) {
594 		found = isl_basic_map_contains_point(map->p[i], point);
595 		if (found < 0)
596 			goto error;
597 		if (found)
598 			break;
599 	}
600 	isl_map_free(map);
601 
602 	return found;
603 error:
604 	isl_map_free(map);
605 	return isl_bool_error;
606 }
607 
isl_set_contains_point(__isl_keep isl_set * set,__isl_keep isl_point * point)608 isl_bool isl_set_contains_point(__isl_keep isl_set *set,
609 	__isl_keep isl_point *point)
610 {
611 	return isl_map_contains_point(set_to_map(set), point);
612 }
613 
isl_basic_set_from_point(__isl_take isl_point * pnt)614 __isl_give isl_basic_set *isl_basic_set_from_point(__isl_take isl_point *pnt)
615 {
616 	isl_basic_set *bset;
617 	isl_basic_set *model;
618 
619 	if (!pnt)
620 		return NULL;
621 
622 	model = isl_basic_set_empty(isl_space_copy(pnt->dim));
623 	bset = isl_basic_set_from_vec(isl_vec_copy(pnt->vec));
624 	bset = isl_basic_set_from_underlying_set(bset, model);
625 	isl_point_free(pnt);
626 
627 	return bset;
628 }
629 
isl_set_from_point(__isl_take isl_point * pnt)630 __isl_give isl_set *isl_set_from_point(__isl_take isl_point *pnt)
631 {
632 	isl_basic_set *bset;
633 	bset = isl_basic_set_from_point(pnt);
634 	return isl_set_from_basic_set(bset);
635 }
636 
637 /* This function performs the same operation as isl_set_from_point,
638  * but is considered as a function on an isl_point when exported.
639  */
isl_point_to_set(__isl_take isl_point * pnt)640 __isl_give isl_set *isl_point_to_set(__isl_take isl_point *pnt)
641 {
642 	return isl_set_from_point(pnt);
643 }
644 
645 /* Construct a union set, containing the single element "pnt".
646  * If "pnt" is void, then return an empty union set.
647  */
isl_union_set_from_point(__isl_take isl_point * pnt)648 __isl_give isl_union_set *isl_union_set_from_point(__isl_take isl_point *pnt)
649 {
650 	if (!pnt)
651 		return NULL;
652 	if (isl_point_is_void(pnt)) {
653 		isl_space *space;
654 
655 		space = isl_point_get_space(pnt);
656 		isl_point_free(pnt);
657 		return isl_union_set_empty(space);
658 	}
659 
660 	return isl_union_set_from_set(isl_set_from_point(pnt));
661 }
662 
isl_basic_set_box_from_points(__isl_take isl_point * pnt1,__isl_take isl_point * pnt2)663 __isl_give isl_basic_set *isl_basic_set_box_from_points(
664 	__isl_take isl_point *pnt1, __isl_take isl_point *pnt2)
665 {
666 	isl_basic_set *bset = NULL;
667 	isl_size total;
668 	int i;
669 	int k;
670 	isl_int t;
671 
672 	isl_int_init(t);
673 
674 	if (!pnt1 || !pnt2)
675 		goto error;
676 
677 	isl_assert(pnt1->dim->ctx,
678 			isl_space_is_equal(pnt1->dim, pnt2->dim), goto error);
679 
680 	if (isl_point_is_void(pnt1) && isl_point_is_void(pnt2)) {
681 		isl_space *space = isl_space_copy(pnt1->dim);
682 		isl_point_free(pnt1);
683 		isl_point_free(pnt2);
684 		isl_int_clear(t);
685 		return isl_basic_set_empty(space);
686 	}
687 	if (isl_point_is_void(pnt1)) {
688 		isl_point_free(pnt1);
689 		isl_int_clear(t);
690 		return isl_basic_set_from_point(pnt2);
691 	}
692 	if (isl_point_is_void(pnt2)) {
693 		isl_point_free(pnt2);
694 		isl_int_clear(t);
695 		return isl_basic_set_from_point(pnt1);
696 	}
697 
698 	total = isl_point_dim(pnt1, isl_dim_all);
699 	if (total < 0)
700 		goto error;
701 	bset = isl_basic_set_alloc_space(isl_space_copy(pnt1->dim), 0, 0, 2 * total);
702 
703 	for (i = 0; i < total; ++i) {
704 		isl_int_mul(t, pnt1->vec->el[1 + i], pnt2->vec->el[0]);
705 		isl_int_submul(t, pnt2->vec->el[1 + i], pnt1->vec->el[0]);
706 
707 		k = isl_basic_set_alloc_inequality(bset);
708 		if (k < 0)
709 			goto error;
710 		isl_seq_clr(bset->ineq[k] + 1, total);
711 		if (isl_int_is_pos(t)) {
712 			isl_int_set_si(bset->ineq[k][1 + i], -1);
713 			isl_int_set(bset->ineq[k][0], pnt1->vec->el[1 + i]);
714 		} else {
715 			isl_int_set_si(bset->ineq[k][1 + i], 1);
716 			isl_int_neg(bset->ineq[k][0], pnt1->vec->el[1 + i]);
717 		}
718 		isl_int_fdiv_q(bset->ineq[k][0], bset->ineq[k][0], pnt1->vec->el[0]);
719 
720 		k = isl_basic_set_alloc_inequality(bset);
721 		if (k < 0)
722 			goto error;
723 		isl_seq_clr(bset->ineq[k] + 1, total);
724 		if (isl_int_is_pos(t)) {
725 			isl_int_set_si(bset->ineq[k][1 + i], 1);
726 			isl_int_neg(bset->ineq[k][0], pnt2->vec->el[1 + i]);
727 		} else {
728 			isl_int_set_si(bset->ineq[k][1 + i], -1);
729 			isl_int_set(bset->ineq[k][0], pnt2->vec->el[1 + i]);
730 		}
731 		isl_int_fdiv_q(bset->ineq[k][0], bset->ineq[k][0], pnt2->vec->el[0]);
732 	}
733 
734 	bset = isl_basic_set_finalize(bset);
735 
736 	isl_point_free(pnt1);
737 	isl_point_free(pnt2);
738 
739 	isl_int_clear(t);
740 
741 	return bset;
742 error:
743 	isl_point_free(pnt1);
744 	isl_point_free(pnt2);
745 	isl_int_clear(t);
746 	isl_basic_set_free(bset);
747 	return NULL;
748 }
749 
isl_set_box_from_points(__isl_take isl_point * pnt1,__isl_take isl_point * pnt2)750 __isl_give isl_set *isl_set_box_from_points(__isl_take isl_point *pnt1,
751 	__isl_take isl_point *pnt2)
752 {
753 	isl_basic_set *bset;
754 	bset = isl_basic_set_box_from_points(pnt1, pnt2);
755 	return isl_set_from_basic_set(bset);
756 }
757 
758 /* Print the coordinate at position "pos" of the point "pnt".
759  */
print_coordinate(__isl_take isl_printer * p,struct isl_print_space_data * data,unsigned pos)760 static __isl_give isl_printer *print_coordinate(__isl_take isl_printer *p,
761 	struct isl_print_space_data *data, unsigned pos)
762 {
763 	isl_point *pnt = data->user;
764 
765 	pos += isl_space_offset(data->space, data->type);
766 	p = isl_printer_print_isl_int(p, pnt->vec->el[1 + pos]);
767 	if (!isl_int_is_one(pnt->vec->el[0])) {
768 		p = isl_printer_print_str(p, "/");
769 		p = isl_printer_print_isl_int(p, pnt->vec->el[0]);
770 	}
771 
772 	return p;
773 }
774 
isl_printer_print_point(__isl_take isl_printer * p,__isl_keep isl_point * pnt)775 __isl_give isl_printer *isl_printer_print_point(
776 	__isl_take isl_printer *p, __isl_keep isl_point *pnt)
777 {
778 	struct isl_print_space_data data = { 0 };
779 	int i;
780 	isl_size nparam;
781 
782 	if (!pnt)
783 		return p;
784 	if (isl_point_is_void(pnt)) {
785 		p = isl_printer_print_str(p, "void");
786 		return p;
787 	}
788 
789 	nparam = isl_point_dim(pnt, isl_dim_param);
790 	if (nparam < 0)
791 		return isl_printer_free(p);
792 	if (nparam > 0) {
793 		p = isl_printer_print_str(p, "[");
794 		for (i = 0; i < nparam; ++i) {
795 			const char *name;
796 			if (i)
797 				p = isl_printer_print_str(p, ", ");
798 			name = isl_space_get_dim_name(pnt->dim, isl_dim_param, i);
799 			if (name) {
800 				p = isl_printer_print_str(p, name);
801 				p = isl_printer_print_str(p, " = ");
802 			}
803 			p = isl_printer_print_isl_int(p, pnt->vec->el[1 + i]);
804 			if (!isl_int_is_one(pnt->vec->el[0])) {
805 				p = isl_printer_print_str(p, "/");
806 				p = isl_printer_print_isl_int(p, pnt->vec->el[0]);
807 			}
808 		}
809 		p = isl_printer_print_str(p, "]");
810 		p = isl_printer_print_str(p, " -> ");
811 	}
812 	data.print_dim = &print_coordinate;
813 	data.user = pnt;
814 	p = isl_printer_print_str(p, "{ ");
815 	p = isl_print_space(pnt->dim, p, 0, &data);
816 	p = isl_printer_print_str(p, " }");
817 	return p;
818 }
819