Skip to content

Commit 1ac114e

Browse files
committed
Example
1 parent d1824d6 commit 1ac114e

File tree

1 file changed

+231
-1
lines changed

1 file changed

+231
-1
lines changed

README.md

Lines changed: 231 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,231 @@
1-
# How to use isl via the C++ / Python interface
1+
Warning: This is a proposal, which does not document the current isl
2+
3+
# How to use isl via the C++ and Python interface
4+
5+
## Constructing an integer set or map (isl::set / isl::map)
6+
7+
### Explicit Interface (today)
8+
9+
We first describe how the current C++ interface should be used to construct
10+
isl sets and maps, just proposing a small number of extensions beyond what exists
11+
today. The resulting code is still somehow verbose, but very explicit.
12+
13+
Example:
14+
15+
*{ [N, M] -> { [i,j] : 2 * M + 3 * N <= 2 * i + j + 10 }*
16+
17+
We create an integer set as follows. We first create a set of identifiers for
18+
each of the needed dimensions (`isl::id Id_N(ctx, "N"`). We then introduce
19+
initial expressions for all identifiers and required constants (`isl::pw_aff
20+
N(Id_N), Ten(ctx, 10)`). From these initial expressions the actual affine
21+
expressions are constructed (`isl::pw_aff LHS = Two.mul(M)`). Pairs of
22+
expressions are combined with the operators lt_set (<), le_set (<=), ge_set
23+
(>=), gt_set (>), eq_set (=), ne_set (!=) into a parameteric set of constraints
24+
(`isl::set PSet = LHS.le_set(RHS)`). Finally, a non-parameteric set is
25+
constructed from 1) a parameteric set specifying its constraints and 2) a list
26+
of identifiers that specify the parameter dimensions that should be promoted to
27+
set dimensions (`isl::set Set({Id_i, Id_j}, PSet)`). Similary, a map can be
28+
constructed by providing two lists of identifiers defining the input and output
29+
dimensions (`isl::map Map({Id_i}, {Id_j}, PSet)`)
30+
31+
32+
33+
34+
```
35+
// Identifiers
36+
isl::id Id_N(ctx, "N"), Id_M(ctx, "M"), Id_i(ctx, "i"), Id_j(ctx, "j");
37+
38+
// One (piece-wise) affine expression per identifier
39+
// [N] -> { [(N)]}, [N] -> { [(M)]}, [i] -> { [(i)]}, [j] -> { [(j)]}
40+
isl::pw_aff N(Id_N), M(Id_M), i(Id_i), j(Id_j);
41+
42+
// One (piece-wise) affine expression per constant
43+
// {[(10)]}, {[(2)]}, {[(3)]}
44+
isl::pw_aff Ten(ctx, 10), Two(ctx, 2), Three(ctx, 3);
45+
46+
// Build the left and right hand side of the expression
47+
// [M, N] -> { [(2 * M + 3 * M)] }
48+
isl::pw_aff LHS = Two.mul(M).add(Three.mul(N));
49+
50+
// [M, N] -> { [(2 * i + j + 10)] }
51+
isl::pw_aff RHS = Two.mul(i).add(j).add(Ten);
52+
53+
// [N, M, i, j] -> { : 2 * M + 3 * N <= 2 * i + j + 10 }
54+
isl::set PSet = LHS.le_set(RHS);
55+
56+
// [N, M] -> { [i, j] : 2 * M + 3 * N <= 2 * i + j + 10 }
57+
isl::set Set({Id_i, Id_j}, PSet);
58+
59+
// [N, M] -> { [i] -> [j] : 2 * M + 3 * N <= 2 * i + j + 10 }
60+
isl::map Map({Id_i}, {Id_j}, PSet);
61+
```
62+
63+
#### New functions
64+
65+
```
66+
__isl_export
67+
isl_pw_aff *isl_pw_aff_param_on_domain_id(isl_id *);
68+
__isl_constructor
69+
isl_set *isl_set_from_id_list_and_set(isl_id_list *dims, isl_set *pset);
70+
__isl_constructor
71+
isl_map *isl_map_from_id_list_and_set(isl_id_list *input_dims, isl_id_list *output_dims, isl_set *pset);
72+
```
73+
74+
#### Notes
75+
76+
- Currently instead of isl::aff, we always need to use isl::pw_aff, as
77+
isl::aff does not allow for parameter auto-alignment. This should be
78+
changed, but will require more work. We should likely write the
79+
documentation in terms of isl::pw_aff for now.
80+
81+
#### Choices
82+
83+
##### Return type of the comparision operator
84+
85+
There have been concerns that the return type of the `le_set` expression
86+
should not be a set, but rather a constraint.
87+
88+
There are currently three options:
89+
90+
- Sets:
91+
92+
```
93+
// [N, M, i, j] -> { : 2 * M + 3 * N <= 2 * i + j + 10 }
94+
isl::set PSet = LHS.le_set(RHS);
95+
isl::set Set({i}, PSet);
96+
```
97+
98+
- Constraints:
99+
100+
```
101+
// [N, M, i, j] -> { : 2 * M + 3 * N <= 2 * i + j + 10 }
102+
isl::constraint PSet = LHS.le_set(RHS);
103+
isl::set Set({i}, PSet);
104+
```
105+
106+
- Marker
107+
108+
```
109+
110+
// [N, M, i, j] -> { : 2 * M + 3 * N <= 2 * i + j + 10 }
111+
isl::set PSet = isl::set_maker(LHS) <= RHS;
112+
isl::set Set({i}, PSet);
113+
```
114+
115+
##### How to introduce parameters
116+
117+
We can either use a constructor (in the proposal):
118+
119+
```
120+
isl::set PSet("[N, M, i, j] -> { : 2 * M + 3 * N <= 2 * i + j + 10 }")
121+
122+
// { [N, M] -> { [i,j] : 2 * M + 3 * N <= 2 * i + j + 10 }
123+
isl::set Set({i,j}, PSet);
124+
// { [N, M] -> { [i]->[j] : 2 * M + 3 * N <= 2 * i + j + 10 }
125+
isl::map Map({i}, {j}, PSet);
126+
```
127+
128+
or a set of member functions.
129+
130+
```
131+
isl::set PSet("[N, M, i, j] -> { : 2 * M + 3 * N <= 2 * i + j + 10 }")
132+
133+
// { [N, M] -> { [i,j] : 2 * M + 3 * N <= 2 * i + j + 10 }
134+
isl::set PSet.inputs(i,j);
135+
// { [N, M] -> { [i]->[j] : 2 * M + 3 * N <= 2 * i + j + 10 }
136+
isl::map PSet.inputs(i).outputs(j);
137+
```
138+
139+
### Streamlined interface (future)
140+
141+
In certain use cases a more streamlined interface might be useful. Here is
142+
an example which includes:
143+
144+
- operator overloading
145+
- automatic conversion from isl::id to isl::aff
146+
- automatic conversion from int to isl::aff
147+
- a default context
148+
149+
```
150+
isl::id N("N"), M("M"), i("i"), j("j');
151+
152+
isl::aff LHS = 2 * M + 3 * N; // natural precedence works
153+
isl::aff RHS = 2 * i + j + 10;
154+
155+
// { [N, M] -> { [i,j] : 2 * M + 3 * N <= 2 * i + j + 10 }
156+
isl::set Set({i,j}, LHS <= RHS);
157+
158+
// { [N, M] -> { [i]->[j] : 2 * M + 3 * N <= 2 * i + j + 10 }
159+
isl::map Map({i}, {j}, LHS <= RHS);
160+
```
161+
162+
#### Extensions
163+
164+
##### Use of a thread-local context
165+
166+
Instead of always providing a ctx object, the bindings could provide a thread
167+
local ctx.
168+
169+
170+
Explicit context:
171+
```
172+
isl::id N(ctx, "N");
173+
```
174+
175+
Implicit context:
176+
```
177+
isl::id N("N");
178+
```
179+
180+
##### Overloading of operators
181+
182+
Instead of calling the explicit interface, operator overloading can be used.
183+
184+
Without overloading:
185+
```
186+
isl::pw_aff = A.add(B).add(Three.mul(C));
187+
```
188+
189+
With overloading
190+
```
191+
isl::pw_aff = A + B + 3 * C;
192+
```
193+
194+
*Warning*: Overloading of the comparision operators may cause confusion as the
195+
result is not a boolean expression.
196+
197+
#### Choices
198+
199+
#### More efficient construction of parameter isl::aff's
200+
201+
When constructing an affine expression for a parameter, the explicit interface
202+
requires two steps. First the construction of an isl::id and then its conversion
203+
to a isl::aff. It would be nice if just one step would be needed. There
204+
are two options:
205+
206+
1) Construction of isl::aff's from strings.
207+
208+
```
209+
isl::aff A = ...
210+
211+
// [N] -> { [(N)] }
212+
isl::aff N(ctx, "N");
213+
214+
isl::aff X = A.add(N);
215+
```
216+
217+
2) Automatic conversion from isl::id to aff
218+
219+
```
220+
isl::aff A = ...
221+
222+
// [N] -> { [(N)] }
223+
isl::id N(ctx, "N");
224+
225+
isl::aff X = A.add(N);
226+
```
227+
228+
229+
230+
231+

0 commit comments

Comments
 (0)