2 * Copyright 2010 INRIA Saclay
3 * Copyright 2013 Ecole Normale Superieure
4 * Copyright 2015 Sven Verdoolaege
5 * Copyright 2019,2022 Cerebras Systems
7 * Use of this software is governed by the MIT license
9 * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
10 * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
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 * and Cerebras Systems, 1237 E Arques Ave, Sunnyvale, CA, USA
17 #include <isl_map_private.h>
18 #include <isl_point_private.h>
20 #include <isl/union_set.h>
21 #include <isl_sample.h>
24 #include <isl_space_private.h>
25 #include <isl_local_private.h>
26 #include <isl_val_private.h>
27 #include <isl_vec_private.h>
28 #include <isl_output_private.h>
30 #include <set_to_map.c>
32 isl_ctx
*isl_point_get_ctx(__isl_keep isl_point
*pnt
)
34 return pnt
? isl_space_get_ctx(pnt
->dim
) : NULL
;
37 /* Return the space of "pnt".
39 __isl_keep isl_space
*isl_point_peek_space(__isl_keep isl_point
*pnt
)
41 return pnt
? pnt
->dim
: NULL
;
44 __isl_give isl_space
*isl_point_get_space(__isl_keep isl_point
*pnt
)
46 return isl_space_copy(isl_point_peek_space(pnt
));
50 #define TYPE1 isl_basic_map
52 #define TYPE2 isl_point
54 #define TYPE_PAIR isl_basic_map_point
57 #include "isl_type_has_equal_space_templ.c"
59 #include "isl_type_check_equal_space_templ.c"
62 #define TYPE isl_point
64 #include "isl_check_named_params_templ.c"
66 __isl_give isl_point
*isl_point_alloc(__isl_take isl_space
*space
,
67 __isl_take isl_vec
*vec
)
69 struct isl_point
*pnt
;
72 dim
= isl_space_dim(space
, isl_dim_all
);
76 if (vec
->size
> 1 + dim
) {
77 vec
= isl_vec_cow(vec
);
83 pnt
= isl_alloc_type(space
->ctx
, struct isl_point
);
93 isl_space_free(space
);
98 __isl_give isl_point
*isl_point_zero(__isl_take isl_space
*space
)
103 dim
= isl_space_dim(space
, isl_dim_all
);
106 vec
= isl_vec_alloc(space
->ctx
, 1 + dim
);
109 isl_int_set_si(vec
->el
[0], 1);
110 isl_seq_clr(vec
->el
+ 1, vec
->size
- 1);
111 return isl_point_alloc(space
, vec
);
113 isl_space_free(space
);
117 __isl_give isl_point
*isl_point_dup(__isl_keep isl_point
*pnt
)
119 struct isl_point
*pnt2
;
123 pnt2
= isl_point_alloc(isl_space_copy(pnt
->dim
), isl_vec_copy(pnt
->vec
));
127 __isl_give isl_point
*isl_point_cow(__isl_take isl_point
*pnt
)
129 struct isl_point
*pnt2
;
136 pnt2
= isl_point_dup(pnt
);
141 __isl_give isl_point
*isl_point_copy(__isl_keep isl_point
*pnt
)
150 __isl_null isl_point
*isl_point_free(__isl_take isl_point
*pnt
)
158 isl_space_free(pnt
->dim
);
159 isl_vec_free(pnt
->vec
);
164 __isl_give isl_point
*isl_point_void(__isl_take isl_space
*space
)
169 return isl_point_alloc(space
, isl_vec_alloc(space
->ctx
, 0));
172 isl_bool
isl_point_is_void(__isl_keep isl_point
*pnt
)
175 return isl_bool_error
;
177 return isl_bool_ok(pnt
->vec
->size
== 0);
180 /* Return the space of "pnt".
181 * This may be either a copy or the space itself
182 * if there is only one reference to "pnt".
183 * This allows the space to be modified inplace
184 * if both the point and its space have only a single reference.
185 * The caller is not allowed to modify "pnt" between this call and
186 * a subsequent call to isl_point_restore_space.
187 * The only exception is that isl_point_free can be called instead.
189 __isl_give isl_space
*isl_point_take_space(__isl_keep isl_point
*pnt
)
196 return isl_point_get_space(pnt
);
202 /* Set the space of "pnt" to "space", where the space of "pnt" may be missing
203 * due to a preceding call to isl_point_take_space.
204 * However, in this case, "pnt" only has a single reference and
205 * then the call to isl_point_cow has no effect.
207 __isl_give isl_point
*isl_point_restore_space(__isl_take isl_point
*pnt
,
208 __isl_take isl_space
*space
)
213 if (pnt
->dim
== space
) {
214 isl_space_free(space
);
218 pnt
= isl_point_cow(pnt
);
221 isl_space_free(pnt
->dim
);
227 isl_space_free(space
);
231 /* Return the coordinate vector of "pnt".
233 __isl_keep isl_vec
*isl_point_peek_vec(__isl_keep isl_point
*pnt
)
235 return pnt
? pnt
->vec
: NULL
;
238 /* Return a copy of the coordinate vector of "pnt".
240 __isl_give isl_vec
*isl_point_get_vec(__isl_keep isl_point
*pnt
)
242 return isl_vec_copy(isl_point_peek_vec(pnt
));
245 /* Return the coordinate vector of "pnt".
246 * This may be either a copy or the coordinate vector itself
247 * if there is only one reference to "pnt".
248 * This allows the coordinate vector to be modified inplace
249 * if both the point and its coordinate vector have only a single reference.
250 * The caller is not allowed to modify "pnt" between this call and
251 * a subsequent call to isl_point_restore_vec.
252 * The only exception is that isl_point_free can be called instead.
254 __isl_give isl_vec
*isl_point_take_vec(__isl_keep isl_point
*pnt
)
261 return isl_point_get_vec(pnt
);
267 /* Set the coordinate vector of "pnt" to "vec",
268 * where the coordinate vector of "pnt" may be missing
269 * due to a preceding call to isl_point_take_vec.
270 * However, in this case, "pnt" only has a single reference and
271 * then the call to isl_point_cow has no effect.
273 __isl_give isl_point
*isl_point_restore_vec(__isl_take isl_point
*pnt
,
274 __isl_take isl_vec
*vec
)
279 if (pnt
->vec
== vec
) {
284 pnt
= isl_point_cow(pnt
);
287 isl_vec_free(pnt
->vec
);
297 /* Return the number of variables of the given type.
299 static isl_size
isl_point_dim(__isl_keep isl_point
*pnt
, enum isl_dim_type type
)
301 return isl_space_dim(isl_point_peek_space(pnt
), type
);
304 /* Return the position of the coordinates of the given type
305 * within the sequence of coordinates of "pnt".
307 static isl_size
isl_point_var_offset(__isl_keep isl_point
*pnt
,
308 enum isl_dim_type type
)
310 return pnt
? isl_space_offset(pnt
->dim
, type
) : isl_size_error
;
313 /* Reorder the coordinates of "pnt" based on the given reordering.
315 static __isl_give isl_point
*isl_point_reorder(__isl_take isl_point
*pnt
,
316 __isl_take isl_reordering
*r
)
320 isl_space_free(isl_point_take_space(pnt
));
321 pnt
= isl_point_restore_space(pnt
, isl_reordering_get_space(r
));
323 vec
= isl_point_take_vec(pnt
);
324 vec
= isl_vec_reorder(vec
, 1, isl_reordering_copy(r
));
325 pnt
= isl_point_restore_vec(pnt
, vec
);
330 /* Align the parameters of "pnt" along those of "model".
332 * Note that "model" is not allowed to have any parameters
333 * that do not already appear in "pnt" since "pnt" does not specify
334 * any value for such parameters.
336 __isl_give isl_point
*isl_point_align_params(__isl_take isl_point
*pnt
,
337 __isl_take isl_space
*model
)
340 isl_bool equal_params
;
342 space
= isl_point_peek_space(pnt
);
343 equal_params
= isl_space_has_equal_params(space
, model
);
344 if (equal_params
< 0)
349 r
= isl_parameter_alignment_reordering(space
, model
);
352 if (r
->src_len
!= r
->dst_len
)
353 isl_die(isl_point_get_ctx(pnt
), isl_error_invalid
,
354 "no value specified for some parameters",
355 r
= isl_reordering_free(r
));
356 pnt
= isl_point_reorder(pnt
, r
);
359 isl_space_free(model
);
362 isl_space_free(model
);
368 #define TYPE isl_point
370 #include "check_type_range_templ.c"
372 /* Return the value of coordinate "pos" of type "type" of "pnt".
374 __isl_give isl_val
*isl_point_get_coordinate_val(__isl_keep isl_point
*pnt
,
375 enum isl_dim_type type
, int pos
)
384 ctx
= isl_point_get_ctx(pnt
);
385 if (isl_point_is_void(pnt
))
386 isl_die(ctx
, isl_error_invalid
,
387 "void point does not have coordinates", return NULL
);
388 if (isl_point_check_range(pnt
, type
, pos
, 1) < 0)
391 off
= isl_point_var_offset(pnt
, type
);
396 v
= isl_val_rat_from_isl_int(ctx
, pnt
->vec
->el
[1 + pos
],
398 return isl_val_normalize(v
);
401 /* Set all entries of "mv" to NaN.
403 static __isl_give isl_multi_val
*set_nan(__isl_take isl_multi_val
*mv
)
409 n
= isl_multi_val_size(mv
);
411 return isl_multi_val_free(mv
);
412 v
= isl_val_nan(isl_multi_val_get_ctx(mv
));
413 for (i
= 0; i
< n
; ++i
)
414 mv
= isl_multi_val_set_at(mv
, i
, isl_val_copy(v
));
420 /* Return the values of the set dimensions of "pnt".
421 * Return a sequence of NaNs in case of a void point.
423 __isl_give isl_multi_val
*isl_point_get_multi_val(__isl_keep isl_point
*pnt
)
430 is_void
= isl_point_is_void(pnt
);
434 mv
= isl_multi_val_alloc(isl_point_get_space(pnt
));
437 n
= isl_multi_val_size(mv
);
439 return isl_multi_val_free(mv
);
440 for (i
= 0; i
< n
; ++i
) {
443 v
= isl_point_get_coordinate_val(pnt
, isl_dim_set
, i
);
444 mv
= isl_multi_val_set_at(mv
, i
, v
);
450 /* Replace coordinate "pos" of type "type" of "pnt" by "v".
452 __isl_give isl_point
*isl_point_set_coordinate_val(__isl_take isl_point
*pnt
,
453 enum isl_dim_type type
, int pos
, __isl_take isl_val
*v
)
457 if (isl_point_is_void(pnt
))
458 isl_die(isl_point_get_ctx(pnt
), isl_error_invalid
,
459 "void point does not have coordinates", goto error
);
460 if (isl_point_check_range(pnt
, type
, pos
, 1) < 0)
462 if (!isl_val_is_rat(v
))
463 isl_die(isl_point_get_ctx(pnt
), isl_error_invalid
,
464 "expecting rational value", goto error
);
466 pos
+= isl_space_offset(isl_point_peek_space(pnt
), type
);
467 if (isl_int_eq(pnt
->vec
->el
[1 + pos
], v
->n
) &&
468 isl_int_eq(pnt
->vec
->el
[0], v
->d
)) {
473 pnt
= isl_point_cow(pnt
);
476 pnt
->vec
= isl_vec_cow(pnt
->vec
);
480 if (isl_int_eq(pnt
->vec
->el
[0], v
->d
)) {
481 isl_int_set(pnt
->vec
->el
[1 + pos
], v
->n
);
482 } else if (isl_int_is_one(v
->d
)) {
483 isl_int_mul(pnt
->vec
->el
[1 + pos
], pnt
->vec
->el
[0], v
->n
);
485 isl_seq_scale(pnt
->vec
->el
+ 1,
486 pnt
->vec
->el
+ 1, v
->d
, pnt
->vec
->size
- 1);
487 isl_int_mul(pnt
->vec
->el
[1 + pos
], pnt
->vec
->el
[0], v
->n
);
488 isl_int_mul(pnt
->vec
->el
[0], pnt
->vec
->el
[0], v
->d
);
489 pnt
->vec
= isl_vec_normalize(pnt
->vec
);
502 __isl_give isl_point
*isl_point_add_ui(__isl_take isl_point
*pnt
,
503 enum isl_dim_type type
, int pos
, unsigned val
)
507 if (!pnt
|| isl_point_is_void(pnt
))
510 pnt
= isl_point_cow(pnt
);
513 pnt
->vec
= isl_vec_cow(pnt
->vec
);
517 off
= isl_point_var_offset(pnt
, type
);
522 isl_int_add_ui(pnt
->vec
->el
[1 + pos
], pnt
->vec
->el
[1 + pos
], val
);
530 __isl_give isl_point
*isl_point_sub_ui(__isl_take isl_point
*pnt
,
531 enum isl_dim_type type
, int pos
, unsigned val
)
535 if (!pnt
|| isl_point_is_void(pnt
))
538 pnt
= isl_point_cow(pnt
);
541 pnt
->vec
= isl_vec_cow(pnt
->vec
);
545 off
= isl_point_var_offset(pnt
, type
);
550 isl_int_sub_ui(pnt
->vec
->el
[1 + pos
], pnt
->vec
->el
[1 + pos
], val
);
558 struct isl_foreach_point
{
559 struct isl_scan_callback callback
;
560 isl_stat (*fn
)(__isl_take isl_point
*pnt
, void *user
);
565 static isl_stat
foreach_point(struct isl_scan_callback
*cb
,
566 __isl_take isl_vec
*sample
)
568 struct isl_foreach_point
*fp
= (struct isl_foreach_point
*)cb
;
571 pnt
= isl_point_alloc(isl_space_copy(fp
->dim
), sample
);
573 return fp
->fn(pnt
, fp
->user
);
576 isl_stat
isl_set_foreach_point(__isl_keep isl_set
*set
,
577 isl_stat (*fn
)(__isl_take isl_point
*pnt
, void *user
), void *user
)
579 struct isl_foreach_point fp
= { { &foreach_point
}, fn
, user
};
583 return isl_stat_error
;
585 fp
.dim
= isl_set_get_space(set
);
587 return isl_stat_error
;
589 set
= isl_set_copy(set
);
590 set
= isl_set_cow(set
);
591 set
= isl_set_make_disjoint(set
);
592 set
= isl_set_compute_divs(set
);
596 for (i
= 0; i
< set
->n
; ++i
)
597 if (isl_basic_set_scan(isl_basic_set_copy(set
->p
[i
]),
602 isl_space_free(fp
.dim
);
607 isl_space_free(fp
.dim
);
608 return isl_stat_error
;
611 /* Return 1 if "bmap" contains the point "point".
612 * "bmap" is assumed to have known divs.
613 * The point is first extended with the divs and then passed
614 * to basic_map_contains.
616 isl_bool
isl_basic_map_contains_point(__isl_keep isl_basic_map
*bmap
,
617 __isl_keep isl_point
*point
)
623 if (isl_basic_map_point_check_equal_space(bmap
, point
) < 0)
624 return isl_bool_error
;
625 if (bmap
->n_div
== 0)
626 return isl_basic_map_contains(bmap
, point
->vec
);
628 local
= isl_local_alloc_from_mat(isl_basic_map_get_divs(bmap
));
629 vec
= isl_point_get_vec(point
);
630 vec
= isl_local_extend_point_vec(local
, vec
);
631 isl_local_free(local
);
633 contains
= isl_basic_map_contains(bmap
, vec
);
639 isl_bool
isl_map_contains_point(__isl_keep isl_map
*map
,
640 __isl_keep isl_point
*point
)
643 isl_bool found
= isl_bool_false
;
646 return isl_bool_error
;
648 map
= isl_map_copy(map
);
649 map
= isl_map_compute_divs(map
);
651 return isl_bool_error
;
653 for (i
= 0; i
< map
->n
; ++i
) {
654 found
= isl_basic_map_contains_point(map
->p
[i
], point
);
665 return isl_bool_error
;
668 isl_bool
isl_set_contains_point(__isl_keep isl_set
*set
,
669 __isl_keep isl_point
*point
)
671 return isl_map_contains_point(set_to_map(set
), point
);
674 __isl_give isl_basic_set
*isl_basic_set_from_point(__isl_take isl_point
*pnt
)
677 isl_basic_set
*model
;
682 model
= isl_basic_set_empty(isl_space_copy(pnt
->dim
));
683 bset
= isl_basic_set_from_vec(isl_vec_copy(pnt
->vec
));
684 bset
= isl_basic_set_from_underlying_set(bset
, model
);
690 __isl_give isl_set
*isl_set_from_point(__isl_take isl_point
*pnt
)
693 bset
= isl_basic_set_from_point(pnt
);
694 return isl_set_from_basic_set(bset
);
697 /* This function performs the same operation as isl_set_from_point,
698 * but is considered as a function on an isl_point when exported.
700 __isl_give isl_set
*isl_point_to_set(__isl_take isl_point
*pnt
)
702 return isl_set_from_point(pnt
);
705 /* Construct a union set, containing the single element "pnt".
706 * If "pnt" is void, then return an empty union set.
708 __isl_give isl_union_set
*isl_union_set_from_point(__isl_take isl_point
*pnt
)
712 if (isl_point_is_void(pnt
)) {
715 space
= isl_point_get_space(pnt
);
717 return isl_union_set_empty(space
);
720 return isl_union_set_from_set(isl_set_from_point(pnt
));
723 __isl_give isl_basic_set
*isl_basic_set_box_from_points(
724 __isl_take isl_point
*pnt1
, __isl_take isl_point
*pnt2
)
726 isl_basic_set
*bset
= NULL
;
737 isl_assert(pnt1
->dim
->ctx
,
738 isl_space_is_equal(pnt1
->dim
, pnt2
->dim
), goto error
);
740 if (isl_point_is_void(pnt1
) && isl_point_is_void(pnt2
)) {
741 isl_space
*space
= isl_space_copy(pnt1
->dim
);
742 isl_point_free(pnt1
);
743 isl_point_free(pnt2
);
745 return isl_basic_set_empty(space
);
747 if (isl_point_is_void(pnt1
)) {
748 isl_point_free(pnt1
);
750 return isl_basic_set_from_point(pnt2
);
752 if (isl_point_is_void(pnt2
)) {
753 isl_point_free(pnt2
);
755 return isl_basic_set_from_point(pnt1
);
758 total
= isl_point_dim(pnt1
, isl_dim_all
);
761 bset
= isl_basic_set_alloc_space(isl_space_copy(pnt1
->dim
), 0, 0, 2 * total
);
763 for (i
= 0; i
< total
; ++i
) {
764 isl_int_mul(t
, pnt1
->vec
->el
[1 + i
], pnt2
->vec
->el
[0]);
765 isl_int_submul(t
, pnt2
->vec
->el
[1 + i
], pnt1
->vec
->el
[0]);
767 k
= isl_basic_set_alloc_inequality(bset
);
770 isl_seq_clr(bset
->ineq
[k
] + 1, total
);
771 if (isl_int_is_pos(t
)) {
772 isl_int_set_si(bset
->ineq
[k
][1 + i
], -1);
773 isl_int_set(bset
->ineq
[k
][0], pnt1
->vec
->el
[1 + i
]);
775 isl_int_set_si(bset
->ineq
[k
][1 + i
], 1);
776 isl_int_neg(bset
->ineq
[k
][0], pnt1
->vec
->el
[1 + i
]);
778 isl_int_fdiv_q(bset
->ineq
[k
][0], bset
->ineq
[k
][0], pnt1
->vec
->el
[0]);
780 k
= isl_basic_set_alloc_inequality(bset
);
783 isl_seq_clr(bset
->ineq
[k
] + 1, total
);
784 if (isl_int_is_pos(t
)) {
785 isl_int_set_si(bset
->ineq
[k
][1 + i
], 1);
786 isl_int_neg(bset
->ineq
[k
][0], pnt2
->vec
->el
[1 + i
]);
788 isl_int_set_si(bset
->ineq
[k
][1 + i
], -1);
789 isl_int_set(bset
->ineq
[k
][0], pnt2
->vec
->el
[1 + i
]);
791 isl_int_fdiv_q(bset
->ineq
[k
][0], bset
->ineq
[k
][0], pnt2
->vec
->el
[0]);
794 bset
= isl_basic_set_finalize(bset
);
796 isl_point_free(pnt1
);
797 isl_point_free(pnt2
);
803 isl_point_free(pnt1
);
804 isl_point_free(pnt2
);
806 isl_basic_set_free(bset
);
810 __isl_give isl_set
*isl_set_box_from_points(__isl_take isl_point
*pnt1
,
811 __isl_take isl_point
*pnt2
)
814 bset
= isl_basic_set_box_from_points(pnt1
, pnt2
);
815 return isl_set_from_basic_set(bset
);
818 /* Print the coordinate at position "pos" of the point "pnt".
820 static __isl_give isl_printer
*print_coordinate(__isl_take isl_printer
*p
,
821 struct isl_print_space_data
*data
, unsigned pos
)
823 isl_point
*pnt
= data
->user
;
825 pos
+= isl_space_offset(data
->space
, data
->type
);
826 p
= isl_printer_print_isl_int(p
, pnt
->vec
->el
[1 + pos
]);
827 if (!isl_int_is_one(pnt
->vec
->el
[0])) {
828 p
= isl_printer_print_str(p
, "/");
829 p
= isl_printer_print_isl_int(p
, pnt
->vec
->el
[0]);
835 __isl_give isl_printer
*isl_printer_print_point(
836 __isl_take isl_printer
*p
, __isl_keep isl_point
*pnt
)
838 struct isl_print_space_data data
= { 0 };
844 if (isl_point_is_void(pnt
)) {
845 p
= isl_printer_print_str(p
, "void");
849 nparam
= isl_point_dim(pnt
, isl_dim_param
);
851 return isl_printer_free(p
);
853 p
= isl_printer_print_str(p
, "[");
854 for (i
= 0; i
< nparam
; ++i
) {
857 p
= isl_printer_print_str(p
, ", ");
858 name
= isl_space_get_dim_name(pnt
->dim
, isl_dim_param
, i
);
860 p
= isl_printer_print_str(p
, name
);
861 p
= isl_printer_print_str(p
, " = ");
863 p
= isl_printer_print_isl_int(p
, pnt
->vec
->el
[1 + i
]);
864 if (!isl_int_is_one(pnt
->vec
->el
[0])) {
865 p
= isl_printer_print_str(p
, "/");
866 p
= isl_printer_print_isl_int(p
, pnt
->vec
->el
[0]);
869 p
= isl_printer_print_str(p
, "]");
870 p
= isl_printer_print_str(p
, " -> ");
872 data
.print_dim
= &print_coordinate
;
874 p
= isl_printer_print_str(p
, "{ ");
875 p
= isl_print_space(pnt
->dim
, p
, 0, &data
);
876 p
= isl_printer_print_str(p
, " }");