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 off
= isl_space_offset(isl_point_peek_space(pnt
), type
);
460 if (isl_point_is_void(pnt
))
461 isl_die(isl_point_get_ctx(pnt
), isl_error_invalid
,
462 "void point does not have coordinates", goto error
);
463 if (isl_point_check_range(pnt
, type
, pos
, 1) < 0)
465 if (!isl_val_is_rat(v
))
466 isl_die(isl_point_get_ctx(pnt
), isl_error_invalid
,
467 "expecting rational value", goto error
);
470 if (isl_int_eq(pnt
->vec
->el
[1 + pos
], v
->n
) &&
471 isl_int_eq(pnt
->vec
->el
[0], v
->d
)) {
476 pnt
= isl_point_cow(pnt
);
479 pnt
->vec
= isl_vec_cow(pnt
->vec
);
483 if (isl_int_eq(pnt
->vec
->el
[0], v
->d
)) {
484 isl_int_set(pnt
->vec
->el
[1 + pos
], v
->n
);
485 } else if (isl_int_is_one(v
->d
)) {
486 isl_int_mul(pnt
->vec
->el
[1 + pos
], pnt
->vec
->el
[0], v
->n
);
488 isl_seq_scale(pnt
->vec
->el
+ 1,
489 pnt
->vec
->el
+ 1, v
->d
, pnt
->vec
->size
- 1);
490 isl_int_mul(pnt
->vec
->el
[1 + pos
], pnt
->vec
->el
[0], v
->n
);
491 isl_int_mul(pnt
->vec
->el
[0], pnt
->vec
->el
[0], v
->d
);
492 pnt
->vec
= isl_vec_normalize(pnt
->vec
);
505 __isl_give isl_point
*isl_point_add_ui(__isl_take isl_point
*pnt
,
506 enum isl_dim_type type
, int pos
, unsigned val
)
510 if (!pnt
|| isl_point_is_void(pnt
))
513 pnt
= isl_point_cow(pnt
);
516 pnt
->vec
= isl_vec_cow(pnt
->vec
);
520 off
= isl_point_var_offset(pnt
, type
);
525 isl_int_add_ui(pnt
->vec
->el
[1 + pos
], pnt
->vec
->el
[1 + pos
], val
);
533 __isl_give isl_point
*isl_point_sub_ui(__isl_take isl_point
*pnt
,
534 enum isl_dim_type type
, int pos
, unsigned val
)
538 if (!pnt
|| isl_point_is_void(pnt
))
541 pnt
= isl_point_cow(pnt
);
544 pnt
->vec
= isl_vec_cow(pnt
->vec
);
548 off
= isl_point_var_offset(pnt
, type
);
553 isl_int_sub_ui(pnt
->vec
->el
[1 + pos
], pnt
->vec
->el
[1 + pos
], val
);
561 struct isl_foreach_point
{
562 struct isl_scan_callback callback
;
563 isl_stat (*fn
)(__isl_take isl_point
*pnt
, void *user
);
568 static isl_stat
foreach_point(struct isl_scan_callback
*cb
,
569 __isl_take isl_vec
*sample
)
571 struct isl_foreach_point
*fp
= (struct isl_foreach_point
*)cb
;
574 pnt
= isl_point_alloc(isl_space_copy(fp
->dim
), sample
);
576 return fp
->fn(pnt
, fp
->user
);
579 isl_stat
isl_set_foreach_point(__isl_keep isl_set
*set
,
580 isl_stat (*fn
)(__isl_take isl_point
*pnt
, void *user
), void *user
)
582 struct isl_foreach_point fp
= { { &foreach_point
}, fn
, user
};
586 return isl_stat_error
;
588 fp
.dim
= isl_set_get_space(set
);
590 return isl_stat_error
;
592 set
= isl_set_copy(set
);
593 set
= isl_set_cow(set
);
594 set
= isl_set_make_disjoint(set
);
595 set
= isl_set_compute_divs(set
);
599 for (i
= 0; i
< set
->n
; ++i
)
600 if (isl_basic_set_scan(isl_basic_set_copy(set
->p
[i
]),
605 isl_space_free(fp
.dim
);
610 isl_space_free(fp
.dim
);
611 return isl_stat_error
;
614 /* Return 1 if "bmap" contains the point "point".
615 * "bmap" is assumed to have known divs.
616 * The point is first extended with the divs and then passed
617 * to basic_map_contains.
619 isl_bool
isl_basic_map_contains_point(__isl_keep isl_basic_map
*bmap
,
620 __isl_keep isl_point
*point
)
626 if (isl_basic_map_point_check_equal_space(bmap
, point
) < 0)
627 return isl_bool_error
;
628 if (bmap
->n_div
== 0)
629 return isl_basic_map_contains(bmap
, point
->vec
);
631 local
= isl_local_alloc_from_mat(isl_basic_map_get_divs(bmap
));
632 vec
= isl_point_get_vec(point
);
633 vec
= isl_local_extend_point_vec(local
, vec
);
634 isl_local_free(local
);
636 contains
= isl_basic_map_contains(bmap
, vec
);
642 isl_bool
isl_map_contains_point(__isl_keep isl_map
*map
,
643 __isl_keep isl_point
*point
)
646 isl_bool found
= isl_bool_false
;
649 return isl_bool_error
;
651 map
= isl_map_copy(map
);
652 map
= isl_map_compute_divs(map
);
654 return isl_bool_error
;
656 for (i
= 0; i
< map
->n
; ++i
) {
657 found
= isl_basic_map_contains_point(map
->p
[i
], point
);
668 return isl_bool_error
;
671 isl_bool
isl_set_contains_point(__isl_keep isl_set
*set
,
672 __isl_keep isl_point
*point
)
674 return isl_map_contains_point(set_to_map(set
), point
);
677 __isl_give isl_basic_set
*isl_basic_set_from_point(__isl_take isl_point
*pnt
)
680 isl_basic_set
*model
;
685 model
= isl_basic_set_empty(isl_space_copy(pnt
->dim
));
686 bset
= isl_basic_set_from_vec(isl_vec_copy(pnt
->vec
));
687 bset
= isl_basic_set_from_underlying_set(bset
, model
);
693 __isl_give isl_set
*isl_set_from_point(__isl_take isl_point
*pnt
)
696 bset
= isl_basic_set_from_point(pnt
);
697 return isl_set_from_basic_set(bset
);
700 /* This function performs the same operation as isl_set_from_point,
701 * but is considered as a function on an isl_point when exported.
703 __isl_give isl_set
*isl_point_to_set(__isl_take isl_point
*pnt
)
705 return isl_set_from_point(pnt
);
708 /* Construct a union set, containing the single element "pnt".
709 * If "pnt" is void, then return an empty union set.
711 __isl_give isl_union_set
*isl_union_set_from_point(__isl_take isl_point
*pnt
)
715 if (isl_point_is_void(pnt
)) {
718 space
= isl_point_get_space(pnt
);
720 return isl_union_set_empty(space
);
723 return isl_union_set_from_set(isl_set_from_point(pnt
));
726 __isl_give isl_basic_set
*isl_basic_set_box_from_points(
727 __isl_take isl_point
*pnt1
, __isl_take isl_point
*pnt2
)
729 isl_basic_set
*bset
= NULL
;
740 isl_assert(pnt1
->dim
->ctx
,
741 isl_space_is_equal(pnt1
->dim
, pnt2
->dim
), goto error
);
743 if (isl_point_is_void(pnt1
) && isl_point_is_void(pnt2
)) {
744 isl_space
*space
= isl_space_copy(pnt1
->dim
);
745 isl_point_free(pnt1
);
746 isl_point_free(pnt2
);
748 return isl_basic_set_empty(space
);
750 if (isl_point_is_void(pnt1
)) {
751 isl_point_free(pnt1
);
753 return isl_basic_set_from_point(pnt2
);
755 if (isl_point_is_void(pnt2
)) {
756 isl_point_free(pnt2
);
758 return isl_basic_set_from_point(pnt1
);
761 total
= isl_point_dim(pnt1
, isl_dim_all
);
764 bset
= isl_basic_set_alloc_space(isl_space_copy(pnt1
->dim
), 0, 0, 2 * total
);
766 for (i
= 0; i
< total
; ++i
) {
767 isl_int_mul(t
, pnt1
->vec
->el
[1 + i
], pnt2
->vec
->el
[0]);
768 isl_int_submul(t
, pnt2
->vec
->el
[1 + i
], pnt1
->vec
->el
[0]);
770 k
= isl_basic_set_alloc_inequality(bset
);
773 isl_seq_clr(bset
->ineq
[k
] + 1, total
);
774 if (isl_int_is_pos(t
)) {
775 isl_int_set_si(bset
->ineq
[k
][1 + i
], -1);
776 isl_int_set(bset
->ineq
[k
][0], pnt1
->vec
->el
[1 + i
]);
778 isl_int_set_si(bset
->ineq
[k
][1 + i
], 1);
779 isl_int_neg(bset
->ineq
[k
][0], pnt1
->vec
->el
[1 + i
]);
781 isl_int_fdiv_q(bset
->ineq
[k
][0], bset
->ineq
[k
][0], pnt1
->vec
->el
[0]);
783 k
= isl_basic_set_alloc_inequality(bset
);
786 isl_seq_clr(bset
->ineq
[k
] + 1, total
);
787 if (isl_int_is_pos(t
)) {
788 isl_int_set_si(bset
->ineq
[k
][1 + i
], 1);
789 isl_int_neg(bset
->ineq
[k
][0], pnt2
->vec
->el
[1 + i
]);
791 isl_int_set_si(bset
->ineq
[k
][1 + i
], -1);
792 isl_int_set(bset
->ineq
[k
][0], pnt2
->vec
->el
[1 + i
]);
794 isl_int_fdiv_q(bset
->ineq
[k
][0], bset
->ineq
[k
][0], pnt2
->vec
->el
[0]);
797 bset
= isl_basic_set_finalize(bset
);
799 isl_point_free(pnt1
);
800 isl_point_free(pnt2
);
806 isl_point_free(pnt1
);
807 isl_point_free(pnt2
);
809 isl_basic_set_free(bset
);
813 __isl_give isl_set
*isl_set_box_from_points(__isl_take isl_point
*pnt1
,
814 __isl_take isl_point
*pnt2
)
817 bset
= isl_basic_set_box_from_points(pnt1
, pnt2
);
818 return isl_set_from_basic_set(bset
);
821 /* Print the coordinate at position "pos" of the point "pnt".
823 static __isl_give isl_printer
*print_coordinate(__isl_take isl_printer
*p
,
824 struct isl_print_space_data
*data
, unsigned pos
)
826 isl_point
*pnt
= data
->user
;
829 off
= isl_space_offset(data
->space
, data
->type
);
831 return isl_printer_free(p
);
833 p
= isl_printer_print_isl_int(p
, pnt
->vec
->el
[1 + pos
]);
834 if (!isl_int_is_one(pnt
->vec
->el
[0])) {
835 p
= isl_printer_print_str(p
, "/");
836 p
= isl_printer_print_isl_int(p
, pnt
->vec
->el
[0]);
842 __isl_give isl_printer
*isl_printer_print_point(
843 __isl_take isl_printer
*p
, __isl_keep isl_point
*pnt
)
845 struct isl_print_space_data data
= { 0 };
851 if (isl_point_is_void(pnt
)) {
852 p
= isl_printer_print_str(p
, "void");
856 nparam
= isl_point_dim(pnt
, isl_dim_param
);
858 return isl_printer_free(p
);
860 p
= isl_printer_print_str(p
, "[");
861 for (i
= 0; i
< nparam
; ++i
) {
864 p
= isl_printer_print_str(p
, ", ");
865 name
= isl_space_get_dim_name(pnt
->dim
, isl_dim_param
, i
);
867 p
= isl_printer_print_str(p
, name
);
868 p
= isl_printer_print_str(p
, " = ");
870 p
= isl_printer_print_isl_int(p
, pnt
->vec
->el
[1 + i
]);
871 if (!isl_int_is_one(pnt
->vec
->el
[0])) {
872 p
= isl_printer_print_str(p
, "/");
873 p
= isl_printer_print_isl_int(p
, pnt
->vec
->el
[0]);
876 p
= isl_printer_print_str(p
, "]");
877 p
= isl_printer_print_str(p
, " -> ");
879 data
.print_dim
= &print_coordinate
;
881 p
= isl_printer_print_str(p
, "{ ");
882 p
= isl_print_space(pnt
->dim
, p
, 0, &data
);
883 p
= isl_printer_print_str(p
, " }");