1 # Copyright 2016-2017 Tobias Grosser
3 # Use of this software is governed by the MIT license
5 # Written by Tobias Grosser, Weststrasse 47, CH-8003, Zurich
10 # Test that isl objects can be constructed.
13 # - construction from a string
14 # - construction from an integer
15 # - static constructor without a parameter
16 # - conversion construction
17 # - construction of empty union set
19 # The tests to construct from integers and strings cover functionality that
20 # is also tested in the parameter type tests, but here the presence of
21 # multiple overloaded constructors and overload resolution is tested.
23 def test_constructors():
25 assert(zero1
.is_zero())
28 assert(zero2
.is_zero())
30 zero3
= isl
.val
.zero()
31 assert(zero3
.is_zero())
33 bs
= isl
.basic_set("{ [1] }")
34 result
= isl
.set("{ [1] }")
36 assert(s
.is_equal(result
))
38 us
= isl
.union_set("{ A[1]; B[2, 3] }")
39 empty
= isl
.union_set
.empty()
40 assert(us
.is_equal(us
.union(empty
)))
42 # Test integer function parameters for a particular integer value.
46 val_str
= isl
.val(str(i
))
47 assert(val_int
.eq(val_str
))
49 # Test integer function parameters.
51 # Verify that extreme values and zero work.
53 def test_parameters_int():
55 test_int(-sys
.maxsize
- 1)
58 # Test isl objects parameters.
60 # Verify that isl objects can be passed as lvalue and rvalue parameters.
61 # Also verify that isl object parameters are automatically type converted if
62 # there is an inheritance relation. Finally, test function calls without
63 # any additional parameters, apart from the isl object on which
64 # the method is called.
66 def test_parameters_obj():
67 a
= isl
.set("{ [0] }")
68 b
= isl
.set("{ [1] }")
69 c
= isl
.set("{ [2] }")
70 expected
= isl
.set("{ [i] : 0 <= i <= 2 }")
73 res_lvalue_param
= tmp
.union(c
)
74 assert(res_lvalue_param
.is_equal(expected
))
76 res_rvalue_param
= a
.union(b
).union(c
)
77 assert(res_rvalue_param
.is_equal(expected
))
79 a2
= isl
.basic_set("{ [0] }")
80 assert(a
.is_equal(a2
))
84 res_only_this_param
= two
.inv()
85 assert(res_only_this_param
.eq(half
))
87 # Test different kinds of parameters to be passed to functions.
89 # This includes integer and isl object parameters.
91 def test_parameters():
95 # Test that isl objects are returned correctly.
97 # This only tests that after combining two objects, the result is successfully
100 def test_return_obj():
107 assert(res
.eq(three
))
109 # Test that integer values are returned correctly.
111 def test_return_int():
113 neg_one
= isl
.val("-1")
116 assert(one
.sgn() > 0)
117 assert(neg_one
.sgn() < 0)
118 assert(zero
.sgn() == 0)
120 # Test that isl_bool values are returned correctly.
122 # In particular, check the conversion to bool in case of true and false.
124 def test_return_bool():
125 empty
= isl
.set("{ : false }")
126 univ
= isl
.set("{ : }")
128 b_true
= empty
.is_empty()
129 b_false
= univ
.is_empty()
134 # Test that strings are returned correctly.
135 # Do so by calling overloaded isl.ast_build.from_expr methods.
137 def test_return_string():
138 context
= isl
.set("[n] -> { : }")
139 build
= isl
.ast_build
.from_context(context
)
140 pw_aff
= isl
.pw_aff("[n] -> { [n] }")
141 set = isl
.set("[n] -> { : n >= 0 }")
143 expr
= build
.expr_from(pw_aff
)
144 expected_string
= "n"
145 assert(expected_string
== expr
.to_C_str())
147 expr
= build
.expr_from(set)
148 expected_string
= "n >= 0"
149 assert(expected_string
== expr
.to_C_str())
151 # Test that return values are handled correctly.
153 # Test that isl objects, integers, boolean values, and strings are
154 # returned correctly.
162 # Test that foreach functions are modeled correctly.
164 # Verify that closures are correctly called as callback of a 'foreach'
165 # function and that variables captured by the closure work correctly. Also
166 # check that the foreach function handles exceptions thrown from
167 # the closure and that it propagates the exception.
170 s
= isl
.set("{ [0]; [1]; [2] }")
175 s
.foreach_basic_set(add
)
177 assert(len(list) == 3)
178 assert(list[0].is_subset(s
))
179 assert(list[1].is_subset(s
))
180 assert(list[2].is_subset(s
))
181 assert(not list[0].is_equal(list[1]))
182 assert(not list[0].is_equal(list[2]))
183 assert(not list[1].is_equal(list[2]))
186 raise Exception("fail")
190 s
.foreach_basic_set(fail
)
195 # Test the functionality of "foreach_scc" functions.
197 # In particular, test it on a list of elements that can be completely sorted
198 # but where two of the elements ("a" and "b") are incomparable.
200 def test_foreach_scc():
201 list = isl
.id_list(3)
202 sorted = [isl
.id_list(3)]
204 'a' : isl
.map("{ [0] -> [1] }"),
205 'b' : isl
.map("{ [1] -> [0] }"),
206 'c' : isl
.map("{ [i = 0:1] -> [i] }"),
208 for k
, v
in data
.items():
210 id = data
['a'].space().domain().identity_multi_pw_aff_on_domain()
212 map = data
[b
.name()].apply_domain(data
[a
.name()])
213 return not map.lex_ge_at(id).is_empty()
216 assert(scc
.size() == 1)
217 sorted[0] = sorted[0].concat(scc
)
219 list.foreach_scc(follows
, add_single
)
220 assert(sorted[0].size() == 3)
221 assert(sorted[0].at(0).name() == "b")
222 assert(sorted[0].at(1).name() == "c")
223 assert(sorted[0].at(2).name() == "a")
225 # Test the functionality of "every" functions.
227 # In particular, test the generic functionality and
228 # test that exceptions are properly propagated.
231 us
= isl
.union_set("{ A[i]; B[j] }")
235 assert(not us
.every_set(is_empty
))
238 return not s
.is_empty()
239 assert(us
.every_set(is_non_empty
))
242 return s
.is_subset(isl
.set("{ A[x] }"))
243 assert(not us
.every_set(in_A
))
246 return not s
.is_subset(isl
.set("{ A[x] }"))
247 assert(not us
.every_set(not_in_A
))
250 raise Exception("fail")
259 # Check basic construction of spaces.
262 unit
= isl
.space
.unit()
263 set_space
= unit
.add_named_tuple("A", 3)
264 map_space
= set_space
.add_named_tuple("B", 2)
266 set = isl
.set.universe(set_space
)
267 map = isl
.map.universe(map_space
)
268 assert(set.is_equal(isl
.set("{ A[*,*,*] }")))
269 assert(map.is_equal(isl
.map("{ A[*,*,*] -> B[*,*] }")))
271 # Construct a simple schedule tree with an outer sequence node and
272 # a single-dimensional band node in each branch, with one of them
275 def construct_schedule_tree():
276 A
= isl
.union_set("{ A[i] : 0 <= i < 10 }")
277 B
= isl
.union_set("{ B[i] : 0 <= i < 20 }")
279 node
= isl
.schedule_node
.from_domain(A
.union(B
))
282 filters
= isl
.union_set_list(A
).add(B
)
283 node
= node
.insert_sequence(filters
)
285 f_A
= isl
.multi_union_pw_aff("[ { A[i] -> [i] } ]")
288 node
= node
.insert_partial_schedule(f_A
)
289 node
= node
.member_set_coincident(0, True)
290 node
= node
.ancestor(2)
292 f_B
= isl
.multi_union_pw_aff("[ { B[i] -> [i] } ]")
295 node
= node
.insert_partial_schedule(f_B
)
296 node
= node
.ancestor(2)
298 return node
.schedule()
300 # Test basic schedule tree functionality.
302 # In particular, create a simple schedule tree and
303 # - check that the root node is a domain node
304 # - test map_descendant_bottom_up
305 # - test foreach_descendant_top_down
306 # - test every_descendant
308 def test_schedule_tree():
309 schedule
= construct_schedule_tree()
310 root
= schedule
.root()
312 assert(type(root
) == isl
.schedule_node_domain
)
318 root
= root
.map_descendant_bottom_up(inc_count
)
319 assert(count
[0] == 8)
322 raise Exception("fail")
326 root
.map_descendant_bottom_up(fail_map
)
335 root
.foreach_descendant_top_down(inc_count
)
336 assert(count
[0] == 8)
342 root
.foreach_descendant_top_down(inc_count
)
343 assert(count
[0] == 1)
345 def is_not_domain(node
):
346 return type(node
) != isl
.schedule_node_domain
347 assert(root
.child(0).every_descendant(is_not_domain
))
348 assert(not root
.every_descendant(is_not_domain
))
351 raise Exception("fail")
354 root
.every_descendant(fail
)
359 domain
= root
.domain()
360 filters
= [isl
.union_set("{}")]
361 def collect_filters(node
):
362 if type(node
) == isl
.schedule_node_filter
:
363 filters
[0] = filters
[0].union(node
.filter())
365 root
.every_descendant(collect_filters
)
366 assert(domain
.is_equal(filters
[0]))
368 # Test marking band members for unrolling.
369 # "schedule" is the schedule created by construct_schedule_tree.
370 # It schedules two statements, with 10 and 20 instances, respectively.
371 # Unrolling all band members therefore results in 30 at-domain calls
372 # by the AST generator.
374 def test_ast_build_unroll(schedule
):
375 root
= schedule
.root()
376 def mark_unroll(node
):
377 if type(node
) == isl
.schedule_node_band
:
378 node
= node
.member_set_ast_loop_unroll(0)
380 root
= root
.map_descendant_bottom_up(mark_unroll
)
381 schedule
= root
.schedule()
384 def inc_count_ast(node
, build
):
388 build
= isl
.ast_build()
389 build
= build
.set_at_each_domain(inc_count_ast
)
390 ast
= build
.node_from(schedule
)
391 assert(count_ast
[0] == 30)
393 # Test basic AST generation from a schedule tree.
395 # In particular, create a simple schedule tree and
396 # - generate an AST from the schedule tree
397 # - test at_each_domain
400 def test_ast_build():
401 schedule
= construct_schedule_tree()
404 def inc_count_ast(node
, build
):
408 build
= isl
.ast_build()
409 build_copy
= build
.set_at_each_domain(inc_count_ast
)
410 ast
= build
.node_from(schedule
)
411 assert(count_ast
[0] == 0)
413 ast
= build_copy
.node_from(schedule
)
414 assert(count_ast
[0] == 2)
417 ast
= build
.node_from(schedule
)
418 assert(count_ast
[0] == 2)
422 def fail_inc_count_ast(node
, build
):
423 count_ast_fail
[0] += 1
425 raise Exception("fail")
427 build
= isl
.ast_build()
428 build
= build
.set_at_each_domain(fail_inc_count_ast
)
431 ast
= build
.node_from(schedule
)
435 assert(count_ast_fail
[0] > 0)
437 build_copy
= build_copy
.set_at_each_domain(inc_count_ast
)
439 ast
= build_copy
.node_from(schedule
)
440 assert(count_ast
[0] == 2)
441 count_ast_fail
[0] = 0
443 ast
= build
.node_from(schedule
)
444 assert(count_ast_fail
[0] == 2)
446 test_ast_build_unroll(schedule
)
448 # Test basic AST expression generation from an affine expression.
450 def test_ast_build_expr():
451 pa
= isl
.pw_aff("[n] -> { [n + 1] }")
452 build
= isl
.ast_build
.from_context(pa
.domain())
454 op
= build
.expr_from(pa
)
455 assert(type(op
) == isl
.ast_expr_op_add
)
456 assert(op
.n_arg() == 2)
458 # Test the isl Python interface
461 # - Object construction
462 # - Different parameter types
463 # - Different return types
464 # - Foreach functions
465 # - Foreach SCC function
470 # - AST expression generation
481 test_ast_build_expr()