IPPL (Independent Parallel Particle Layer)
IPPL
Loading...
Searching...
No Matches
Index.hpp
Go to the documentation of this file.
1//
2// Class Index
3// Define a slice in an array.
4//
5// This essentially defines a list of evenly spaced numbers.
6// Most commonly this list will be increasing (positive stride)
7// but it can also have negative stride and be decreasing.
8//
9// Index() --> A null interval with no elements.
10// Index(n) --> make an Index on [0..n-1]
11// Index(a,b) --> make an Index on [a..b]
12// Index(a,b,s) --> make an Index on [a..b] with stride s
13//
14// Example1:
15// --------
16// Index I(10); --> Index on [0..9]
17// Index Low(5); --> Index on [0..4]
18// Index High(5,9); --> Index on [5..9]
19// Index IOdd(1,9,2); --> Index on [1..9] stride 2
20// Index IEven(0,9,2); --> Index on [0..9] stride 2
21//
22// Given an Index I(a,n,s), and an integer j you can do the following:
23//
24// I+j : a+j+i*s for i in [0..n-1]
25// j-I : j-a-i*s
26// j*I : j*a + i*j*s
27// I/j : a/j + i*s/j
28//
29// j/I we don't do because it is not a uniform stride, and we don't
30// allow strides that are fractions.
31//
32#include "Utility/PAssert.h"
33
34namespace ippl {
35
36 KOKKOS_INLINE_FUNCTION Index::Index()
37 : first_m(0)
38 , stride_m(0)
39 , length_m(0) {}
40
41 KOKKOS_INLINE_FUNCTION Index::Index(size_t n)
42 : first_m(0)
43 , stride_m(1)
44 , length_m(n) {}
45
46 KOKKOS_INLINE_FUNCTION Index::Index(int f, int l)
47 : first_m(f)
48 , stride_m(1)
49 , length_m(l - f + 1) {
50 PAssert_GE(l - f + 1, 0);
51 }
52
53 KOKKOS_INLINE_FUNCTION Index::Index(int f, int l, int s)
54 : first_m(f)
55 , stride_m(s) {
56 PAssert_NE(s, 0);
57 if (f == l) {
58 length_m = 1;
59 } else if ((l > f) ^ (s < 0)) {
60 length_m = (l - f) / s + 1;
61 } else {
62 length_m = 0;
63 }
64 }
65
66 KOKKOS_INLINE_FUNCTION Index::Index(int m, int a, const Index& b)
67 : first_m(b.first_m * m + a)
68 , stride_m(b.stride_m * m)
69 , length_m(b.length_m) {}
70
71 KOKKOS_INLINE_FUNCTION Index::Index(int f, int s, const Index* b)
72 : first_m(f)
73 , stride_m(s)
74 , length_m(b->length_m) {}
75
76 KOKKOS_INLINE_FUNCTION int Index::first() const noexcept {
77 return first_m;
78 }
79
80 KOKKOS_INLINE_FUNCTION int Index::stride() const noexcept {
81 return stride_m;
82 }
83
84 KOKKOS_INLINE_FUNCTION bool Index::empty() const noexcept {
85 return length_m == 0;
86 }
87
88 KOKKOS_INLINE_FUNCTION size_t Index::length() const noexcept {
89 return length_m;
90 }
91
92 KOKKOS_INLINE_FUNCTION int Index::last() const noexcept {
93 return (length_m == 0) ? first_m : first_m + stride_m * (length_m - 1);
94 }
95
96 KOKKOS_INLINE_FUNCTION int Index::min() const noexcept {
97 return (stride_m >= 0) ? first_m : first_m + stride_m * (length_m - 1);
98 }
99
100 KOKKOS_INLINE_FUNCTION int Index::max() const noexcept {
101 return (stride_m >= 0) ? first_m + stride_m * (length_m - 1) : first_m;
102 }
103
104 KOKKOS_INLINE_FUNCTION Index& Index::operator+=(int off) {
105 first_m += off;
106 return *this;
107 }
108
109 KOKKOS_INLINE_FUNCTION Index& Index::operator-=(int off) {
110 first_m -= off;
111 return *this;
112 }
113
114 KOKKOS_INLINE_FUNCTION Index operator+(const Index& i, int off) {
115 return Index(1, off, i);
116 }
117
118 KOKKOS_INLINE_FUNCTION Index operator+(int off, const Index& i) {
119 return Index(1, off, i);
120 }
121
122 KOKKOS_INLINE_FUNCTION Index operator-(const Index& i, int off) {
123 return Index(1, -off, i);
124 }
125
126 KOKKOS_INLINE_FUNCTION Index operator-(int off, const Index& i) {
127 return Index(-1, off, i);
128 }
129
130 KOKKOS_INLINE_FUNCTION Index operator-(const Index& i) {
131 return Index(-1, 0, i);
132 }
133
134 KOKKOS_INLINE_FUNCTION Index operator*(const Index& i, int m) {
135 return Index(m, 0, i);
136 }
137
138 KOKKOS_INLINE_FUNCTION Index operator*(int m, const Index& i) {
139 return Index(m, 0, i);
140 }
141
142 KOKKOS_INLINE_FUNCTION Index operator/(const Index& i, int d) {
143 return Index(i.first_m / d, i.stride_m / d, &i);
144 }
145
146 KOKKOS_INLINE_FUNCTION Index Index::reverse() const {
147 Index j;
148 j.first_m = last();
149 j.length_m = length_m;
150 j.stride_m = -stride_m;
151 return j;
152 }
153
154 KOKKOS_INLINE_FUNCTION bool Index::touches(const Index& a) const {
155 return (min() <= a.max()) && (max() >= a.min());
156 }
157
158 KOKKOS_INLINE_FUNCTION bool Index::contains(const Index& a) const {
159 return (min() <= a.min()) && (max() >= a.max());
160 }
161
162 KOKKOS_INLINE_FUNCTION bool Index::split(Index& l, Index& r) const {
165 auto mid = first_m + length_m / 2 - 1;
166 l = Index(first_m, mid);
167 r = Index(mid + 1, first_m + length_m - 1);
168 return true;
169 }
170
171 KOKKOS_INLINE_FUNCTION bool Index::split(Index& l, Index& r, int i) const {
174 if (i >= first_m + static_cast<int>(length_m)) {
175 return false;
176 }
177 l = Index(first_m, i);
178 r = Index(i + 1, first_m + length_m - 1);
179 return true;
180 }
181
182 KOKKOS_INLINE_FUNCTION bool Index::split(Index& l, Index& r, double a) const {
185 PAssert_LT(a, 1.0);
186 PAssert_GT(a, 0.0);
187 int mid = first_m + static_cast<int>(length_m * a + 0.5) - 1;
188 l = Index(first_m, mid);
189 r = Index(mid + 1, first_m + length_m - 1);
190 return true;
191 }
192
194 // Calculate the lowest common multiple of s1 and s2.
195 // put the result in s.
196 // Also calculate m1 = s/s1 and m2 = s/s2.
197 // This version is optimized for small s1 and s2 and
198 // just uses an exhaustive search.
200 KOKKOS_INLINE_FUNCTION void lcm(int s1, int s2, int& s, int& m1, int& m2) {
201 PAssert_GT(s1, 0); // For simplicity, make some assumptions.
202 PAssert_GT(s2, 0);
203 int i1 = s1;
204 int i2 = s2;
205 int _m1 = 1;
206 int _m2 = 1;
207 if (i2 < i1) {
208 while (true) {
209 while (i2 < i1) {
210 i2 += s2;
211 ++_m2;
212 }
213 if (i1 == i2) {
214 m1 = _m1;
215 m2 = _m2;
216 s = i1;
217 return;
218 }
219 i1 += s1;
220 ++_m1;
221 }
222 } else {
223 while (true) {
224 while (i1 < i2) {
225 i1 += s1;
226 ++_m1;
227 }
228 if (i1 == i2) {
229 m1 = _m1;
230 m2 = _m2;
231 s = i1;
232 return;
233 }
234 i2 += s2;
235 ++_m2;
236 }
237 }
238 }
239
240 //
241 // Intersect, with the code for the common case of
242 // both strides equal to one.
243 //
244 KOKKOS_INLINE_FUNCTION Index Index::intersect(const Index& rhs) const {
245 Index ret;
246 if ((stride() == 1) && (rhs.stride() == 1)) {
247 int lf = first();
248 int rf = rhs.first();
249 int ll = last();
250 int rl = rhs.last();
251 int f = lf > rf ? lf : rf;
252 int l = ll < rl ? ll : rl;
253 ret.first_m = f;
254 ret.length_m = ((l >= f) ? l - f + 1 : 0);
255 ret.stride_m = 1;
256 } else
257 ret = general_intersect(rhs);
258 return ret;
259 }
260
261 KOKKOS_INLINE_FUNCTION Index Index::grow(int ncells) const {
262 Index index;
263
264 index.first_m = this->first_m - ncells;
265 index.length_m = this->length_m + 2 * ncells;
266 index.stride_m = this->stride_m;
267
268 return index;
269 }
270
271 KOKKOS_INLINE_FUNCTION static Index do_intersect(const Index& a, const Index& b) {
272 PAssert_GT(a.stride(), 0); // This should be assured by the
273 PAssert_GT(b.stride(), 0); // caller of this function.
274
275 int newStride; // The stride for the new index is
276 int a_mul, b_mul; // a_mul=newStride/a.stride() ...
277 lcm(a.stride(), b.stride(), // The input strides...
278 newStride, a_mul, b_mul); // the lcm of the strides of a and b.
279
280 // Find the offset from a.first() in units of newStride
281 // that puts the ranges close together.
282 int a_i = (b.first() - a.first()) / a.stride();
283 int a_off = a.first() + a_i * a.stride();
284 if (a_off < b.first()) {
285 a_i++;
286 a_off += a.stride();
287 }
288
289 PAssert_GE(a_off, b.first()); // make sure I'm understanding this right...
290
291 // Now do an exhaustive search for the first point in common.
292 // Count over all possible offsets for a.
293 for (int a_m = 0; (a_m < a_mul) && (a_i < (int)a.length());
294 a_m++, a_i++, a_off += a.stride()) {
295 int b_off = b.first();
296 // Count over all possible offsets for b.
297 for (int b_m = 0; (b_m < b_mul) && (b_m < (int)b.length()); b_m++, b_off += b.stride())
298 if (a_off == b_off) { // If the offsets are the same, we found it!
299 int am = a.max(); // Find the minimum maximum of a and b...
300 int bm = b.max();
301 int m = am < bm ? am : bm;
302 return Index(a_off, m, newStride);
303 }
304 }
305 return Index(0); // If we get to here there is no intersection.
306 }
307
308 KOKKOS_INLINE_FUNCTION Index Index::general_intersect(const Index& that) const {
309 // If they just don't overlap, return null indexes.
310 if ((min() > that.max()) || (that.min() > max()))
311 return Index(0);
312 if ((stride_m == 0) || (that.stride_m == 0))
313 return Index(0);
314
315 // If one or the other counts -ve, reverse it and intersect result.
316 if (that.stride_m < 0)
317 return intersect(that.reverse());
318 if (stride_m < 0) {
319 Index r;
320 r = reverse().intersect(that).reverse();
321 return r;
322 }
323
324 // Getting closer to the real thing: intersect them.
325 // Pass the one that starts lower as the first argument.
326 Index r;
327 if (first_m < that.first_m)
328 r = do_intersect(*this, that);
329 else
330 r = do_intersect(that, *this);
331
332 return r;
333 }
334} // namespace ippl
#define PAssert_LT(a, b)
Definition PAssert.h:125
#define PAssert_EQ(a, b)
Definition PAssert.h:123
#define PAssert_GE(a, b)
Definition PAssert.h:128
#define PAssert_GT(a, b)
Definition PAssert.h:127
#define PAssert_NE(a, b)
Definition PAssert.h:124
Definition Archive.h:20
KOKKOS_INLINE_FUNCTION Index operator/(const Index &i, int d)
Definition Index.hpp:142
KOKKOS_INLINE_FUNCTION Index operator-(const Index &i, int off)
Definition Index.hpp:122
static KOKKOS_INLINE_FUNCTION Index do_intersect(const Index &a, const Index &b)
Definition Index.hpp:271
KOKKOS_INLINE_FUNCTION Index operator+(const Index &i, int off)
Definition Index.hpp:114
KOKKOS_INLINE_FUNCTION void lcm(int s1, int s2, int &s, int &m1, int &m2)
Definition Index.hpp:200
KOKKOS_INLINE_FUNCTION Index operator*(const Index &i, int m)
Definition Index.hpp:134
KOKKOS_INLINE_FUNCTION Index general_intersect(const Index &) const
Definition Index.hpp:308
KOKKOS_INLINE_FUNCTION Index intersect(const Index &) const
Definition Index.hpp:244
int stride_m
First index element.
Definition Index.h:238
KOKKOS_INLINE_FUNCTION bool touches(const Index &a) const
Definition Index.hpp:154
KOKKOS_INLINE_FUNCTION int min() const noexcept
Definition Index.hpp:96
KOKKOS_INLINE_FUNCTION int first() const noexcept
Definition Index.hpp:76
KOKKOS_INLINE_FUNCTION bool contains(const Index &a) const
Definition Index.hpp:158
KOKKOS_INLINE_FUNCTION Index reverse() const
The number of elements.
Definition Index.hpp:146
int first_m
Definition Index.h:237
KOKKOS_INLINE_FUNCTION bool split(Index &l, Index &r) const
Definition Index.hpp:162
KOKKOS_INLINE_FUNCTION int stride() const noexcept
Definition Index.hpp:80
KOKKOS_INLINE_FUNCTION Index()
Definition Index.hpp:36
KOKKOS_INLINE_FUNCTION Index & operator-=(int)
Definition Index.hpp:109
KOKKOS_INLINE_FUNCTION bool empty() const noexcept
Definition Index.hpp:84
KOKKOS_INLINE_FUNCTION size_t length() const noexcept
Definition Index.hpp:88
KOKKOS_INLINE_FUNCTION Index grow(int ncells) const
Definition Index.hpp:261
KOKKOS_INLINE_FUNCTION int max() const noexcept
Definition Index.hpp:100
size_t length_m
Definition Index.h:239
KOKKOS_INLINE_FUNCTION Index & operator+=(int)
Definition Index.hpp:104
KOKKOS_INLINE_FUNCTION int last() const noexcept
Definition Index.hpp:92