| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
 138
 139
 140
 141
 142
 143
 144
 145
 146
 147
 148
 149
 150
 151
 152
 153
 154
 155
 156
 157
 158
 159
 160
 161
 162
 163
 164
 165
 166
 167
 168
 169
 170
 171
 172
 173
 174
 175
 176
 177
 178
 179
 180
 181
 182
 183
 184
 185
 186
 187
 188
 189
 190
 191
 192
 
 | #include <assert.h>
#include <stdlib.h>
#include <functional>
#include <iostream>
#include <sstream>
#include <string>
#include <type_traits>
#include <utility>
#include <vector>
#include <isl/cpp.h>
/* A binary isl function that appears in the C++ bindings
 * as a unary method in a class T, taking an extra argument
 * of type A1 and returning an object of type R.
 */
template <typename A1, typename R, typename T>
using binary_fn = R (T::*)(A1) const;
/* A function for selecting an overload of a pointer to a unary C++ method
 * based on the single argument type.
 * The object type and the return type are meant to be deduced.
 */
template <typename A1, typename R, typename T>
static binary_fn<A1, R, T> const arg(const binary_fn<A1, R, T> &fn)
{
	return fn;
}
/* A description of the inputs and the output of a binary operation.
 */
struct binary {
	const char *arg1;
	const char *arg2;
	const char *res;
};
/* A template function for checking whether two objects
 * of the same (isl) type are (obviously) equal.
 * The spelling depends on the isl type and
 * in particular on whether an equality method is available or
 * whether only obvious equality can be tested.
 */
template <typename T, typename std::decay<decltype(
	std::declval<T>().is_equal(std::declval<T>()))>::type = true>
static bool is_equal(const T &a, const T &b)
{
	return a.is_equal(b);
}
template <typename T, typename std::decay<decltype(
	std::declval<T>().plain_is_equal(std::declval<T>()))>::type = true>
static bool is_equal(const T &a, const T &b)
{
	return a.plain_is_equal(b);
}
/* A helper macro for throwing an isl::exception_invalid with message "msg".
 */
#define THROW_INVALID(msg) \
	isl::exception::throw_error(isl_error_invalid, msg, __FILE__, __LINE__)
/* Run a sequence of tests of method "fn" with stringification "name" and
 * with inputs and output described by "test",
 * throwing an exception when an unexpected result is produced.
 */
template <typename R, typename T, typename A1>
static void test(isl::ctx ctx, R (T::*fn)(A1) const, const std::string &name,
	const std::vector<binary> &tests)
{
	for (const auto &test : tests) {
		T obj(ctx, test.arg1);
		A1 arg1(ctx, test.arg2);
		R expected(ctx, test.res);
		const auto &res = (obj.*fn)(arg1);
		std::ostringstream ss;
		if (is_equal(expected, res))
			continue;
		ss << name << "(" << test.arg1 << ", " << test.arg2 << ") =\n"
		   << res << "\n"
		   << "expecting:\n"
		   << test.res;
		THROW_INVALID(ss.str().c_str());
	}
}
/* A helper macro that calls test with as implicit initial argument "ctx" and
 * as extra argument a stringification of "FN".
 */
#define C(FN, ...) test(ctx, FN, #FN, __VA_ARGS__)
/* Perform some basic preimage tests.
 */
static void test_preimage(isl::ctx ctx)
{
	C(arg<isl::multi_aff>(&isl::set::preimage), {
	{ "{ B[i,j] : 0 <= i < 10 and 0 <= j < 100 }",
	  "{ A[j,i] -> B[i,j] }",
	  "{ A[j,i] : 0 <= i < 10 and 0 <= j < 100 }" },
	{ "{ rat: B[i,j] : 0 <= i, j and 3 i + 5 j <= 100 }",
	  "{ A[a,b] -> B[a/2,b/6] }",
	  "{ rat: A[a,b] : 0 <= a, b and 9 a + 5 b <= 600 }" },
	{ "{ B[i,j] : 0 <= i, j and 3 i + 5 j <= 100 }",
	  "{ A[a,b] -> B[a/2,b/6] }",
	  "{ A[a,b] : 0 <= a, b and 9 a + 5 b <= 600 and "
		    "exists i,j : a = 2 i and b = 6 j }" },
	{ "[n] -> { S[i] : 0 <= i <= 100 }", "[n] -> { S[n] }",
	  "[n] -> { : 0 <= n <= 100 }" },
	{ "{ B[i] : 0 <= i < 100 and exists a : i = 4 a }",
	  "{ A[a] -> B[2a] }",
	  "{ A[a] : 0 <= a < 50 and exists b : a = 2 b }" },
	{ "{ B[i] : 0 <= i < 100 and exists a : i = 4 a }",
	  "{ A[a] -> B[([a/2])] }",
	  "{ A[a] : 0 <= a < 200 and exists b : [a/2] = 4 b }" },
	{ "{ B[i,j,k] : 0 <= i,j,k <= 100 }",
	  "{ A[a] -> B[a,a,a/3] }",
	  "{ A[a] : 0 <= a <= 100 and exists b : a = 3 b }" },
	{ "{ B[i,j] : j = [(i)/2] } ", "{ A[i,j] -> B[i/3,j] }",
	  "{ A[i,j] : j = [(i)/6] and exists a : i = 3 a }" },
	});
	C(arg<isl::multi_aff>(&isl::union_map::preimage_domain), {
	{ "{ B[i,j] -> C[2i + 3j] : 0 <= i < 10 and 0 <= j < 100 }",
	  "{ A[j,i] -> B[i,j] }",
	  "{ A[j,i] -> C[2i + 3j] : 0 <= i < 10 and 0 <= j < 100 }" },
	{ "{ B[i] -> C[i]; D[i] -> E[i] }",
	  "{ A[i] -> B[i + 1] }",
	  "{ A[i] -> C[i + 1] }" },
	{ "{ B[i] -> C[i]; B[i] -> E[i] }",
	  "{ A[i] -> B[i + 1] }",
	  "{ A[i] -> C[i + 1]; A[i] -> E[i + 1] }" },
	{ "{ B[i] -> C[([i/2])] }",
	  "{ A[i] -> B[2i] }",
	  "{ A[i] -> C[i] }" },
	{ "{ B[i,j] -> C[([i/2]), ([(i+j)/3])] }",
	  "{ A[i] -> B[([i/5]), ([i/7])] }",
	  "{ A[i] -> C[([([i/5])/2]), ([(([i/5])+([i/7]))/3])] }" },
	{ "[N] -> { B[i] -> C[([N/2]), i, ([N/3])] }",
	  "[N] -> { A[] -> B[([N/5])] }",
	  "[N] -> { A[] -> C[([N/2]), ([N/5]), ([N/3])] }" },
	{ "{ B[i] -> C[i] : exists a : i = 5 a }",
	  "{ A[i] -> B[2i] }",
	  "{ A[i] -> C[2i] : exists a : 2i = 5 a }" },
	{ "{ B[i] -> C[i] : exists a : i = 2 a; "
	    "B[i] -> D[i] : exists a : i = 2 a + 1 }",
	  "{ A[i] -> B[2i] }",
	  "{ A[i] -> C[2i] }" },
	{ "{ A[i] -> B[i] }", "{ C[i] -> A[(i + floor(i/3))/2] }",
	  "{ C[i] -> B[j] : 2j = i + floor(i/3) }" },
	});
	C(arg<isl::multi_aff>(&isl::union_map::preimage_range), {
	{ "[M] -> { A[a] -> B[a] }", "[M] -> { C[] -> B[floor(M/2)] }",
	  "[M] -> { A[floor(M/2)] -> C[] }" },
	});
}
/* The list of tests to perform.
 */
static std::vector<std::pair<const char *, void (*)(isl::ctx)>> tests =
{
	{ "preimage", &test_preimage },
};
/* Perform some basic checks by means of the C++ bindings.
 */
int main(int argc, char **argv)
{
	int ret = EXIT_SUCCESS;
	struct isl_ctx *ctx;
	struct isl_options *options;
	options = isl_options_new_with_defaults();
	assert(options);
	argc = isl_options_parse(options, argc, argv, ISL_ARG_ALL);
	ctx = isl_ctx_alloc_with_options(&isl_options_args, options);
	try {
		for (const auto &f : tests) {
			std::cout << f.first << "\n";
			f.second(ctx);
		}
	} catch (const isl::exception &e) {
		std::cerr << e.what() << "\n";
		ret = EXIT_FAILURE;
	}
	isl_ctx_free(ctx);
	return ret;
}
 |