xref: /netbsd-src/external/mit/isl/dist/isl_test2.cc (revision 5971e316fdea024efff6be8f03536623db06833e)
1 /*
2  * Copyright 2008-2009 Katholieke Universiteit Leuven
3  * Copyright 2010      INRIA Saclay
4  * Copyright 2012-2013 Ecole Normale Superieure
5  * Copyright 2014      INRIA Rocquencourt
6  * Copyright 2021-2022 Cerebras Systems
7  *
8  * Use of this software is governed by the MIT license
9  *
10  * Written by Sven Verdoolaege, K.U.Leuven, Departement
11  * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
12  * and INRIA Saclay - Ile-de-France, Parc Club Orsay Universite,
13  * ZAC des vignes, 4 rue Jacques Monod, 91893 Orsay, France
14  * and Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France
15  * and Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt,
16  * B.P. 105 - 78153 Le Chesnay, France
17  * and Cerebras Systems, 1237 E Arques Ave, Sunnyvale, CA, USA
18  */
19 
20 #include <assert.h>
21 #include <stdlib.h>
22 
23 #include <functional>
24 #include <iostream>
25 #include <sstream>
26 #include <string>
27 #include <type_traits>
28 #include <utility>
29 #include <vector>
30 
31 #include <isl/cpp.h>
32 
33 /* A binary isl function that appears in the C++ bindings
34  * as a unary method in a class T, taking an extra argument
35  * of type A1 and returning an object of type R.
36  */
37 template <typename A1, typename R, typename T>
38 using binary_fn = R (T::*)(A1) const;
39 
40 /* A function for selecting an overload of a pointer to a unary C++ method
41  * based on the single argument type.
42  * The object type and the return type are meant to be deduced.
43  */
44 template <typename A1, typename R, typename T>
arg(const binary_fn<A1,R,T> & fn)45 static binary_fn<A1, R, T> const arg(const binary_fn<A1, R, T> &fn)
46 {
47 	return fn;
48 }
49 
50 /* A ternary isl function that appears in the C++ bindings
51  * as a binary method in a class T, taking extra arguments
52  * of type A1 and A2 and returning an object of type R.
53  */
54 template <typename A1, typename A2, typename R, typename T>
55 using ternary_fn = R (T::*)(A1, A2) const;
56 
57 /* A function for selecting an overload of a pointer to a binary C++ method
58  * based on the (first) argument type(s).
59  * The object type and the return type are meant to be deduced.
60  */
61 template <typename A1, typename A2, typename R, typename T>
arg(const ternary_fn<A1,A2,R,T> & fn)62 static ternary_fn<A1, A2, R, T> const arg(const ternary_fn<A1, A2, R, T> &fn)
63 {
64 	return fn;
65 }
66 
67 /* A description of the input and the output of a unary operation.
68  */
69 struct unary {
70 	const char *arg;
71 	const char *res;
72 };
73 
74 /* A description of the inputs and the output of a binary operation.
75  */
76 struct binary {
77 	const char *arg1;
78 	const char *arg2;
79 	const char *res;
80 };
81 
82 /* A description of the inputs and the output of a ternary operation.
83  */
84 struct ternary {
85 	const char *arg1;
86 	const char *arg2;
87 	const char *arg3;
88 	const char *res;
89 };
90 
91 /* A template function for checking whether two objects
92  * of the same (isl) type are (obviously) equal.
93  * The spelling depends on the isl type and
94  * in particular on whether an equality method is available or
95  * whether only obvious equality can be tested.
96  */
97 template <typename T, typename std::decay<decltype(
98 	std::declval<T>().is_equal(std::declval<T>()))>::type = true>
is_equal(const T & a,const T & b)99 static bool is_equal(const T &a, const T &b)
100 {
101 	return a.is_equal(b);
102 }
103 template <typename T, typename std::decay<decltype(
104 	std::declval<T>().plain_is_equal(std::declval<T>()))>::type = true>
is_equal(const T & a,const T & b)105 static bool is_equal(const T &a, const T &b)
106 {
107 	return a.plain_is_equal(b);
108 }
109 
110 /* A helper macro for throwing an isl::exception_invalid with message "msg".
111  */
112 #define THROW_INVALID(msg) \
113 	isl::exception::throw_error(isl_error_invalid, msg, __FILE__, __LINE__)
114 
115 /* Run a sequence of tests of method "fn" with stringification "name" and
116  * with input and output described by "test",
117  * throwing an exception when an unexpected result is produced.
118  */
119 template <typename R, typename T>
test(isl::ctx ctx,R (T::* fn)()const,const std::string & name,const std::vector<unary> & tests)120 static void test(isl::ctx ctx, R (T::*fn)() const, const std::string &name,
121 	const std::vector<unary> &tests)
122 {
123 	for (const auto &test : tests) {
124 		T obj(ctx, test.arg);
125 		R expected(ctx, test.res);
126 		const auto &res = (obj.*fn)();
127 		std::ostringstream ss;
128 
129 		if (is_equal(expected, res))
130 			continue;
131 
132 		ss << name << "(" << test.arg << ") =\n"
133 		   << res << "\n"
134 		   << "expecting:\n"
135 		   << expected;
136 		THROW_INVALID(ss.str().c_str());
137 	}
138 }
139 
140 /* Run a sequence of tests of method "fn" with stringification "name" and
141  * with inputs and output described by "test",
142  * throwing an exception when an unexpected result is produced.
143  */
144 template <typename R, typename T, typename A1>
test(isl::ctx ctx,R (T::* fn)(A1)const,const std::string & name,const std::vector<binary> & tests)145 static void test(isl::ctx ctx, R (T::*fn)(A1) const, const std::string &name,
146 	const std::vector<binary> &tests)
147 {
148 	for (const auto &test : tests) {
149 		T obj(ctx, test.arg1);
150 		A1 arg1(ctx, test.arg2);
151 		R expected(ctx, test.res);
152 		const auto &res = (obj.*fn)(arg1);
153 		std::ostringstream ss;
154 
155 		if (is_equal(expected, res))
156 			continue;
157 
158 		ss << name << "(" << test.arg1 << ", " << test.arg2 << ") =\n"
159 		   << res << "\n"
160 		   << "expecting:\n"
161 		   << expected;
162 		THROW_INVALID(ss.str().c_str());
163 	}
164 }
165 
166 /* Run a sequence of tests of method "fn" with stringification "name" and
167  * with inputs and output described by "test",
168  * throwing an exception when an unexpected result is produced.
169  */
170 template <typename R, typename T, typename A1, typename A2>
test(isl::ctx ctx,R (T::* fn)(A1,A2)const,const std::string & name,const std::vector<ternary> & tests)171 static void test(isl::ctx ctx, R (T::*fn)(A1, A2) const,
172 	const std::string &name, const std::vector<ternary> &tests)
173 {
174 	for (const auto &test : tests) {
175 		T obj(ctx, test.arg1);
176 		A1 arg1(ctx, test.arg2);
177 		A2 arg2(ctx, test.arg3);
178 		R expected(ctx, test.res);
179 		const auto &res = (obj.*fn)(arg1, arg2);
180 		std::ostringstream ss;
181 
182 		if (is_equal(expected, res))
183 			continue;
184 
185 		ss << name << "(" << test.arg1 << ", " << test.arg2 << ", "
186 		   << test.arg3 << ") =\n"
187 		   << res << "\n"
188 		   << "expecting:\n"
189 		   << expected;
190 		THROW_INVALID(ss.str().c_str());
191 	}
192 }
193 
194 /* A helper macro that calls test with as implicit initial argument "ctx" and
195  * as extra argument a stringification of "FN".
196  */
197 #define C(FN, ...) test(ctx, FN, #FN, __VA_ARGS__)
198 
199 /* Perform some basic isl::space tests.
200  */
test_space(isl::ctx ctx)201 static void test_space(isl::ctx ctx)
202 {
203 	C(&isl::space::domain, {
204 	{ "{ A[] -> B[] }", "{ A[] }" },
205 	{ "{ A[C[] -> D[]] -> B[E[] -> F[]] }", "{ A[C[] -> D[]] }" },
206 	});
207 
208 	C(&isl::space::range, {
209 	{ "{ A[] -> B[] }", "{ B[] }" },
210 	{ "{ A[C[] -> D[]] -> B[E[] -> F[]] }", "{ B[E[] -> F[]] }" },
211 	});
212 
213 	C(&isl::space::params, {
214 	{ "{ A[] -> B[] }", "{ : }" },
215 	{ "{ A[C[] -> D[]] -> B[E[] -> F[]] }", "{ : }" },
216 	});
217 }
218 
219 /* Perform some basic conversion tests.
220  *
221  * In particular, check that a map with an output dimension
222  * that is equal to some integer division over a domain involving
223  * a local variable without a known integer division expression or
224  * to some linear combination of integer divisions
225  * can be converted to a function expressed in the same way.
226  */
test_conversion(isl::ctx ctx)227 static void test_conversion(isl::ctx ctx)
228 {
229 	C(&isl::set::as_pw_multi_aff, {
230 	{ "[N=0:] -> { [] }",
231 	  "[N=0:] -> { [] }" },
232 	});
233 
234 	C(&isl::multi_pw_aff::as_set, {
235 	{ "[n] -> { [] : n >= 0 } ",
236 	  "[n] -> { [] : n >= 0 } " },
237 	});
238 
239 	C(&isl::map::as_pw_multi_aff, {
240 	{ "{ [a] -> [a//2] : "
241 	    "exists (e0: 8*floor((-a + e0)/8) <= -8 - a + 8e0) }",
242 	  "{ [a] -> [a//2] : "
243 	    "exists (e0: 8*floor((-a + e0)/8) <= -8 - a + 8e0) }" },
244 	{ "{ [a, b] -> [(2*floor((a)/8) + floor((b)/6))] }",
245 	  "{ [a, b] -> [(2*floor((a)/8) + floor((b)/6))] }" },
246 	});
247 }
248 
249 /* Perform some basic preimage tests.
250  */
test_preimage(isl::ctx ctx)251 static void test_preimage(isl::ctx ctx)
252 {
253 	C(arg<isl::multi_aff>(&isl::set::preimage), {
254 	{ "{ B[i,j] : 0 <= i < 10 and 0 <= j < 100 }",
255 	  "{ A[j,i] -> B[i,j] }",
256 	  "{ A[j,i] : 0 <= i < 10 and 0 <= j < 100 }" },
257 	{ "{ rat: B[i,j] : 0 <= i, j and 3 i + 5 j <= 100 }",
258 	  "{ A[a,b] -> B[a/2,b/6] }",
259 	  "{ rat: A[a,b] : 0 <= a, b and 9 a + 5 b <= 600 }" },
260 	{ "{ B[i,j] : 0 <= i, j and 3 i + 5 j <= 100 }",
261 	  "{ A[a,b] -> B[a/2,b/6] }",
262 	  "{ A[a,b] : 0 <= a, b and 9 a + 5 b <= 600 and "
263 		    "exists i,j : a = 2 i and b = 6 j }" },
264 	{ "[n] -> { S[i] : 0 <= i <= 100 }", "[n] -> { S[n] }",
265 	  "[n] -> { : 0 <= n <= 100 }" },
266 	{ "{ B[i] : 0 <= i < 100 and exists a : i = 4 a }",
267 	  "{ A[a] -> B[2a] }",
268 	  "{ A[a] : 0 <= a < 50 and exists b : a = 2 b }" },
269 	{ "{ B[i] : 0 <= i < 100 and exists a : i = 4 a }",
270 	  "{ A[a] -> B[([a/2])] }",
271 	  "{ A[a] : 0 <= a < 200 and exists b : [a/2] = 4 b }" },
272 	{ "{ B[i,j,k] : 0 <= i,j,k <= 100 }",
273 	  "{ A[a] -> B[a,a,a/3] }",
274 	  "{ A[a] : 0 <= a <= 100 and exists b : a = 3 b }" },
275 	{ "{ B[i,j] : j = [(i)/2] } ", "{ A[i,j] -> B[i/3,j] }",
276 	  "{ A[i,j] : j = [(i)/6] and exists a : i = 3 a }" },
277 	});
278 
279 	C(arg<isl::pw_multi_aff>(&isl::set::preimage), {
280 	{ "{ B[i,j] : 0 <= i < 10 and 0 <= j < 100 }",
281 	  "{ A[j,i] -> B[i,j] : false }",
282 	  "{ A[j,i] : false }" },
283 	});
284 
285 	C(arg<isl::multi_aff>(&isl::union_map::preimage_domain), {
286 	{ "{ B[i,j] -> C[2i + 3j] : 0 <= i < 10 and 0 <= j < 100 }",
287 	  "{ A[j,i] -> B[i,j] }",
288 	  "{ A[j,i] -> C[2i + 3j] : 0 <= i < 10 and 0 <= j < 100 }" },
289 	{ "{ B[i] -> C[i]; D[i] -> E[i] }",
290 	  "{ A[i] -> B[i + 1] }",
291 	  "{ A[i] -> C[i + 1] }" },
292 	{ "{ B[i] -> C[i]; B[i] -> E[i] }",
293 	  "{ A[i] -> B[i + 1] }",
294 	  "{ A[i] -> C[i + 1]; A[i] -> E[i + 1] }" },
295 	{ "{ B[i] -> C[([i/2])] }",
296 	  "{ A[i] -> B[2i] }",
297 	  "{ A[i] -> C[i] }" },
298 	{ "{ B[i,j] -> C[([i/2]), ([(i+j)/3])] }",
299 	  "{ A[i] -> B[([i/5]), ([i/7])] }",
300 	  "{ A[i] -> C[([([i/5])/2]), ([(([i/5])+([i/7]))/3])] }" },
301 	{ "[N] -> { B[i] -> C[([N/2]), i, ([N/3])] }",
302 	  "[N] -> { A[] -> B[([N/5])] }",
303 	  "[N] -> { A[] -> C[([N/2]), ([N/5]), ([N/3])] }" },
304 	{ "{ B[i] -> C[i] : exists a : i = 5 a }",
305 	  "{ A[i] -> B[2i] }",
306 	  "{ A[i] -> C[2i] : exists a : 2i = 5 a }" },
307 	{ "{ B[i] -> C[i] : exists a : i = 2 a; "
308 	    "B[i] -> D[i] : exists a : i = 2 a + 1 }",
309 	  "{ A[i] -> B[2i] }",
310 	  "{ A[i] -> C[2i] }" },
311 	{ "{ A[i] -> B[i] }", "{ C[i] -> A[(i + floor(i/3))/2] }",
312 	  "{ C[i] -> B[j] : 2j = i + floor(i/3) }" },
313 	});
314 
315 	C(arg<isl::multi_aff>(&isl::union_map::preimage_range), {
316 	{ "[M] -> { A[a] -> B[a] }", "[M] -> { C[] -> B[floor(M/2)] }",
317 	  "[M] -> { A[floor(M/2)] -> C[] }" },
318 	});
319 }
320 
321 /* Perform some basic fixed power tests.
322  */
test_fixed_power(isl::ctx ctx)323 static void test_fixed_power(isl::ctx ctx)
324 {
325 	C(arg<isl::val>(&isl::map::fixed_power), {
326 	{ "{ [i] -> [i + 1] }", "23",
327 	  "{ [i] -> [i + 23] }" },
328 	{ "{ [a = 0:1, b = 0:15, c = 0:1, d = 0:1, 0] -> [a, b, c, d, 1]; "
329 	    "[a = 0:1, b = 0:15, c = 0:1, 0, 1] -> [a, b, c, 1, 0];  "
330 	    "[a = 0:1, b = 0:15, 0, 1, 1] -> [a, b, 1, 0, 0];  "
331 	    "[a = 0:1, b = 0:14, 1, 1, 1] -> [a, 1 + b, 0, 0, 0];  "
332 	    "[0, 15, 1, 1, 1] -> [1, 0, 0, 0, 0] }",
333 	  "128",
334 	  "{ [0, b = 0:15, c = 0:1, d = 0:1, e = 0:1] -> [1, b, c, d, e] }" },
335 	});
336 }
337 
338 /* Perform some basic intersection tests.
339  */
test_intersect(isl::ctx ctx)340 static void test_intersect(isl::ctx ctx)
341 {
342 	C(&isl::union_map::intersect_domain_wrapped_domain, {
343 	{ "{ [A[x] -> B[y]] -> C[z]; [D[x] -> A[y]] -> E[z] }",
344 	  "{ A[0] }",
345 	  "{ [A[0] -> B[y]] -> C[z] }" },
346 	{ "{ C[z] -> [A[x] -> B[y]]; E[z] -> [D[x] -> A[y]] }",
347 	  "{ A[0] }",
348 	  "{ }" },
349 	{ "{ T[A[x] -> B[y]] -> C[z]; [D[x] -> A[y]] -> E[z] }",
350 	  "{ A[0] }",
351 	  "{ T[A[0] -> B[y]] -> C[z] }" },
352 	});
353 
354 	C(&isl::union_map::intersect_range_wrapped_domain, {
355 	{ "{ [A[x] -> B[y]] -> C[z]; [D[x] -> A[y]] -> E[z] }",
356 	  "{ A[0] }",
357 	  "{ }" },
358 	{ "{ C[z] -> [A[x] -> B[y]]; E[z] -> [D[x] -> A[y]] }",
359 	  "{ A[0] }",
360 	  "{ C[z] -> [A[0] -> B[y]] }" },
361 	{ "{ C[z] -> T[A[x] -> B[y]]; E[z] -> [D[x] -> A[y]] }",
362 	  "{ A[0] }",
363 	  "{ C[z] -> T[A[0] -> B[y]] }" },
364 	});
365 }
366 
367 /* Perform some basic gist tests.
368  */
test_gist(isl::ctx ctx)369 static void test_gist(isl::ctx ctx)
370 {
371 	C(arg<isl::set>(&isl::pw_aff::gist), {
372 	{ "{ [x] -> [x] : x != 0 }", "{ [x] : x < -1 or x > 1 }",
373 	  "{ [x] -> [x] }" },
374 	});
375 
376 	C(&isl::pw_aff::gist_params, {
377 	{ "[N] -> { D[x] -> [x] : N >= 0; D[x] -> [0] : N < 0 }",
378 	  "[N] -> { : N >= 0 }",
379 	  "[N] -> { D[x] -> [x] }" },
380 	});
381 
382 	C(arg<isl::set>(&isl::multi_aff::gist), {
383 	{ "{ A[i] -> B[i, i] }", "{ A[0] }",
384 	  "{ A[i] -> B[0, 0] }" },
385 	{ "[N] -> { A[i] -> B[i, N] }", "[N] -> { A[0] : N = 5 }",
386 	  "[N] -> { A[i] -> B[0, 5] }" },
387 	{ "[N] -> { B[N + 1, N] }", "[N] -> { : N = 5 }",
388 	  "[N] -> { B[6, 5] }" },
389 	{ "[N] -> { A[i] -> B[] }", "[N] -> { A[0] : N = 5 }",
390 	  "[N] -> { A[i] -> B[] }" },
391 	{ "[N] -> { B[] }", "[N] -> { : N = 5 }",
392 	  "[N] -> { B[] }" },
393 	});
394 
395 	C(&isl::multi_aff::gist_params, {
396 	{ "[N] -> { A[i] -> B[i, N] }", "[N] -> { : N = 5 }",
397 	  "[N] -> { A[i] -> B[i, 5] }" },
398 	{ "[N] -> { B[N + 1, N] }", "[N] -> { : N = 5 }",
399 	  "[N] -> { B[6, 5] }" },
400 	{ "[N] -> { A[i] -> B[] }", "[N] -> { : N = 5 }",
401 	  "[N] -> { A[i] -> B[] }" },
402 	{ "[N] -> { B[] }", "[N] -> { : N = 5 }",
403 	  "[N] -> { B[] }" },
404 	});
405 
406 	C(arg<isl::set>(&isl::multi_pw_aff::gist), {
407 	{ "{ A[i] -> B[i, i] : i >= 0 }", "{ A[0] }",
408 	  "{ A[i] -> B[0, 0] }" },
409 	{ "[N] -> { A[i] -> B[i, N] : N >= 0 }", "[N] -> { A[0] : N = 5 }",
410 	  "[N] -> { A[i] -> B[0, 5] }" },
411 	{ "[N] -> { B[N + 1, N] }", "[N] -> { : N = 5 }",
412 	  "[N] -> { B[6, 5] }" },
413 	{ "[N] -> { A[i] -> B[] }", "[N] -> { A[0] : N = 5 }",
414 	  "[N] -> { A[i] -> B[] }" },
415 	{ "[N] -> { B[] }", "[N] -> { : N = 5 }",
416 	  "[N] -> { B[] }" },
417 	{ "{ A[i=0:10] -> B[i] }", "{ A[5] }",
418 	  "{ A[i] -> B[5] }" },
419 	{ "{ A[0:10] -> B[] }", "{ A[0:10] }",
420 	  "{ A[i] -> B[] }" },
421 	{ "[N] -> { A[i] -> B[] : N >= 0 }", "[N] -> { A[0] : N = 5 }",
422 	  "[N] -> { A[i] -> B[] }" },
423 	{ "[N] -> { B[] : N >= 0 }", "[N] -> { : N = 5 }",
424 	  "[N] -> { B[] }" },
425 	{ "[N] -> { B[] : N = 5 }", "[N] -> { : N >= 0 }",
426 	  "[N] -> { B[] : N = 5 }" },
427 	});
428 
429 	C(&isl::multi_pw_aff::gist_params, {
430 	{ "[N] -> { A[i] -> B[i, N] : N >= 0 }", "[N] -> { : N = 5 }",
431 	  "[N] -> { A[i] -> B[i, 5] }" },
432 	{ "[N] -> { B[N + 1, N] }", "[N] -> { : N = 5 }",
433 	  "[N] -> { B[6, 5] }" },
434 	{ "[N] -> { A[i] -> B[] : N >= 0 }", "[N] -> { : N = 5 }",
435 	  "[N] -> { A[i] -> B[] }" },
436 	{ "[N] -> { B[] : N >= 0 }", "[N] -> { : N = 5 }",
437 	  "[N] -> { B[] }" },
438 	{ "[N] -> { B[] : N >= 5 }", "[N] -> { : N >= 0 }",
439 	  "[N] -> { B[] : N >= 5 }" },
440 	});
441 
442 	C(&isl::multi_union_pw_aff::gist, {
443 	{ "C[{ B[i,i] -> [3i] }]", "{ B[i,i] }",
444 	  "C[{ B[i,j] -> [3i] }]" },
445 	{ "(C[] : { B[i,i] })", "{ B[i,i] }",
446 	  "(C[] : { B[i,j] })" },
447 	{ "[N] -> (C[] : { B[N,N] })", "[N] -> { B[N,N] }",
448 	  "[N] -> (C[] : { B[i,j] })" },
449 	{ "C[]", "{ B[i,i] }",
450 	  "C[]" },
451 	{ "[N] -> (C[] : { B[i,i] : N >= 0 })", "{ B[i,i] }",
452 	  "[N] -> (C[] : { B[i,j] : N >= 0 })" },
453 	{ "[N] -> (C[] : { : N >= 0 })", "{ B[i,i] }",
454 	  "[N] -> (C[] : { : N >= 0 })" },
455 	{ "[N] -> (C[] : { : N >= 0 })", "[N] -> { B[i,i] : N >= 0 }",
456 	  "[N] -> C[]" },
457 	});
458 
459 	C(&isl::multi_union_pw_aff::gist_params, {
460 	{ "[N] -> C[{ B[i,i] -> [3i + N] }]", "[N] -> { : N = 1 }",
461 	  "[N] -> C[{ B[i,i] -> [3i + 1] }]" },
462 	{ "C[{ B[i,i] -> [3i] }]", "[N] -> { : N >= 0 }",
463 	  "[N] -> C[{ B[i,i] -> [3i] }]" },
464 	{ "[N] -> C[{ B[i,i] -> [3i] : N >= 0 }]", "[N] -> { : N >= 0 }",
465 	  "[N] -> C[{ B[i,i] -> [3i] }]" },
466 	{ "[N] -> C[{ B[i,i] -> [3i] : N >= 1 }]", "[N] -> { : N >= 0 }",
467 	  "[N] -> C[{ B[i,i] -> [3i] : N >= 1 }]" },
468 	{ "[N] -> (C[] : { B[i,i] : N >= 0 })", "[N] -> { : N >= 0 }",
469 	  "[N] -> (C[] : { B[i,i] })" },
470 	{ "[N] -> (C[] : { : N >= 0 })", "[N] -> { : N >= 0 }",
471 	  "[N] -> C[]" },
472 	{ "C[{ B[i,i] -> [3i] }]", "[N] -> { : N >= 0 }",
473 	  "[N] -> C[{ B[i,i] -> [3i] }]" },
474 	});
475 }
476 
477 /* Perform tests that project out parameters.
478  */
test_project(isl::ctx ctx)479 static void test_project(isl::ctx ctx)
480 {
481 	C(arg<isl::id>(&isl::union_map::project_out_param), {
482 	{ "[N] -> { D[i] -> A[0:N-1]; D[i] -> B[i] }", "N",
483 	  "{ D[i] -> A[0:]; D[i] -> B[i] }" },
484 	{ "[N] -> { D[i] -> A[0:N-1]; D[i] -> B[i] }", "M",
485 	  "[N] -> { D[i] -> A[0:N-1]; D[i] -> B[i] }" },
486 	});
487 
488 	C(arg<isl::id_list>(&isl::union_map::project_out_param), {
489 	{ "[M, N, O] -> { D[i] -> A[j] : i <= j < M, N, O }", "(M, N)",
490 	  "[O] -> { D[i] -> A[j] : i <= j < O }" },
491 	});
492 }
493 
494 /* Perform some basic reverse tests.
495  */
test_reverse(isl::ctx ctx)496 static void test_reverse(isl::ctx ctx)
497 {
498 	C(&isl::aff::domain_reverse, {
499 	{ "{ T[A[] -> B[*]] -> [0] }",
500 	  "{ [B[*] -> A[]] -> [0] }" },
501 	{ "{ T[A[] -> A[]] -> [0] }",
502 	  "{ T[A[] -> A[]] -> [0] }" },
503 	{ "{ [A[x] -> B[y]] -> [5*(x // 2) + 7*(y // 3)] }",
504 	  "{ [B[y] -> A[x]] -> [5*(x // 2) + 7*(y // 3)] }" },
505 	});
506 
507 	C(&isl::multi_aff::domain_reverse, {
508 	{ "{ [A[x] -> B[y]] -> [5*(x // 2) + 7*(y // 3)] }",
509 	  "{ [B[y] -> A[x]] -> [5*(x // 2) + 7*(y // 3)] }" },
510 	{ "{ [A[x] -> B[y]] -> T[5*(x // 2) + 7*(y // 3), 0] }",
511 	  "{ [B[y] -> A[x]] -> T[5*(x // 2) + 7*(y // 3), 0] }" },
512 	});
513 
514 	C(&isl::set::wrapped_reverse, {
515 	{ "{ T[A[] -> B[*]] }",
516 	  "{ [B[*] -> A[]] }" },
517 	{ "{ T[A[] -> A[]] }",
518 	  "{ T[A[] -> A[]] }" },
519 	{ "{ [A[x] -> B[2x]] }",
520 	  "{ [B[y] -> A[x]] : y = 2x }" },
521 	});
522 
523 	C(&isl::pw_aff::domain_reverse, {
524 	{ "{ [A[x] -> B[y]] -> [5*(x // 2) + 7*(y // 3)] }",
525 	  "{ [B[y] -> A[x]] -> [5*(x // 2) + 7*(y // 3)] }" },
526 	{ "{ [A[x] -> B[y]] -> [5*(x // 2) + 7*(y // 3)] : x > y }",
527 	  "{ [B[y] -> A[x]] -> [5*(x // 2) + 7*(y // 3)] : x > y }" },
528 	{ "{ [A[i] -> B[i + 1]] -> [i + 2] }",
529 	  "{ [B[i] -> A[i - 1]] -> [i + 1] }" },
530 	});
531 
532 	C(&isl::pw_multi_aff::domain_reverse, {
533 	{ "{ [A[x] -> B[y]] -> T[5*(x // 2) + 7*(y // 3), 0] : x > y }",
534 	  "{ [B[y] -> A[x]] -> T[5*(x // 2) + 7*(y // 3), 0] : x > y }" },
535 	{ "{ [A[i] -> B[i + 1]] -> T[0, i + 2] }",
536 	  "{ [B[i] -> A[i - 1]] -> T[0, i + 1] }" },
537 	});
538 
539 	C(&isl::multi_pw_aff::domain_reverse, {
540 	{ "{ [A[x] -> B[y]] -> T[5*(x // 2) + 7*(y // 3) : x > y, 0] }",
541 	  "{ [B[y] -> A[x]] -> T[5*(x // 2) + 7*(y // 3) : x > y, 0] }" },
542 	});
543 
544 	C(&isl::map::domain_reverse, {
545 	{ "{ [A[] -> B[]] -> [C[] -> D[]] }",
546 	  "{ [B[] -> A[]] -> [C[] -> D[]] }" },
547 	{ "{ N[B[] -> C[]] -> A[] }",
548 	  "{ [C[] -> B[]] -> A[] }" },
549 	{ "{ N[B[x] -> B[y]] -> A[] }",
550 	  "{ N[B[*] -> B[*]] -> A[] }" },
551 	});
552 
553 	C(&isl::union_map::domain_reverse, {
554 	{ "{ [A[] -> B[]] -> [C[] -> D[]] }",
555 	  "{ [B[] -> A[]] -> [C[] -> D[]] }" },
556 	{ "{ A[] -> [B[] -> C[]]; A[] -> B[]; A[0] -> N[B[1] -> B[2]] }",
557 	  "{ }" },
558 	{ "{ N[B[] -> C[]] -> A[] }",
559 	  "{ [C[] -> B[]] -> A[] }" },
560 	{ "{ N[B[x] -> B[y]] -> A[] }",
561 	  "{ N[B[*] -> B[*]] -> A[] }" },
562 	});
563 
564 	C(&isl::union_map::range_reverse, {
565 	{ "{ A[] -> [B[] -> C[]]; A[] -> B[]; A[0] -> N[B[1] -> B[2]] }",
566 	  "{ A[] -> [C[] -> B[]]; A[0] -> N[B[2] -> B[1]] }" },
567 	{ "{ A[] -> N[B[] -> C[]] }",
568 	  "{ A[] -> [C[] -> B[]] }" },
569 	{ "{ A[] -> N[B[x] -> B[y]] }",
570 	  "{ A[] -> N[B[*] -> B[*]] }" },
571 	});
572 }
573 
574 /* Perform some basic scaling tests.
575  */
test_scale(isl::ctx ctx)576 static void test_scale(isl::ctx ctx)
577 {
578 	C(arg<isl::multi_val>(&isl::pw_multi_aff::scale), {
579 	{ "{ A[a] -> B[a, a + 1, a - 1] : a >= 0 }", "{ B[2, 7, 0] }",
580 	  "{ A[a] -> B[2a, 7a + 7, 0] : a >= 0 }" },
581 	});
582 	C(arg<isl::multi_val>(&isl::pw_multi_aff::scale), {
583 	{ "{ A[a] -> B[1, a - 1] : a >= 0 }", "{ B[1/2, 7] }",
584 	  "{ A[a] -> B[1/2, 7a - 7] : a >= 0 }" },
585 	});
586 
587 	C(arg<isl::multi_val>(&isl::pw_multi_aff::scale_down), {
588 	{ "{ A[a] -> B[a, a + 1] : a >= 0 }", "{ B[2, 7] }",
589 	  "{ A[a] -> B[a/2, (a + 1)/7] : a >= 0 }" },
590 	});
591 	C(arg<isl::multi_val>(&isl::pw_multi_aff::scale_down), {
592 	{ "{ A[a] -> B[a, a - 1] : a >= 0 }", "{ B[2, 1/7] }",
593 	  "{ A[a] -> B[a/2, 7a - 7] : a >= 0 }" },
594 	});
595 }
596 
597 /* Perform some basic isl::id_to_id tests.
598  */
test_id_to_id(isl::ctx ctx)599 static void test_id_to_id(isl::ctx ctx)
600 {
601 	C((arg<isl::id, isl::id>(&isl::id_to_id::set)), {
602 	{ "{ }", "a", "b",
603 	  "{ a: b }" },
604 	{ "{ a: b }", "a", "b",
605 	  "{ a: b }" },
606 	{ "{ a: c }", "a", "b",
607 	  "{ a: b }" },
608 	{ "{ a: b }", "b", "a",
609 	  "{ a: b, b: a }" },
610 	{ "{ a: b }", "b", "a",
611 	  "{ b: a, a: b }" },
612 	});
613 }
614 
615 /* The list of tests to perform.
616  */
617 static std::vector<std::pair<const char *, void (*)(isl::ctx)>> tests =
618 {
619 	{ "space", &test_space },
620 	{ "conversion", &test_conversion },
621 	{ "preimage", &test_preimage },
622 	{ "fixed power", &test_fixed_power },
623 	{ "intersect", &test_intersect },
624 	{ "gist", &test_gist },
625 	{ "project out parameters", &test_project },
626 	{ "reverse", &test_reverse },
627 	{ "scale", &test_scale },
628 	{ "id-to-id", &test_id_to_id },
629 };
630 
631 /* Perform some basic checks by means of the C++ bindings.
632  */
main(int argc,char ** argv)633 int main(int argc, char **argv)
634 {
635 	int ret = EXIT_SUCCESS;
636 	struct isl_ctx *ctx;
637 	struct isl_options *options;
638 
639 	options = isl_options_new_with_defaults();
640 	assert(options);
641 	argc = isl_options_parse(options, argc, argv, ISL_ARG_ALL);
642 	ctx = isl_ctx_alloc_with_options(&isl_options_args, options);
643 
644 	try {
645 		for (const auto &f : tests) {
646 			std::cout << f.first << "\n";
647 			f.second(ctx);
648 		}
649 	} catch (const isl::exception &e) {
650 		std::cerr << e.what() << "\n";
651 		ret = EXIT_FAILURE;
652 	}
653 
654 	isl_ctx_free(ctx);
655 	return ret;
656 }
657