OPAL (Object Oriented Parallel Accelerator Library) 2022.1
OPAL
Index.cpp
Go to the documentation of this file.
1// -*- C++ -*-
2/***************************************************************************
3 *
4 * The IPPL Framework
5 *
6 * This program was prepared by PSI.
7 * All rights in the program are reserved by PSI.
8 * Neither PSI nor the author(s)
9 * makes any warranty, express or implied, or assumes any liability or
10 * responsibility for the use of this software
11 *
12 * Visit www.amas.web.psi for more details
13 *
14 ***************************************************************************/
15
16// -*- C++ -*-
17/***************************************************************************
18 *
19 * The IPPL Framework
20 *
21 *
22 * Visit http://people.web.psi.ch/adelmann/ for more details
23 *
24 ***************************************************************************/
25
27// Major functions and test code for Index.
28// See main below for examples of use.
30
31// include files
32#include "Index/Index.h"
33#include "Utility/PAssert.h"
34
35
37
38std::ostream& operator<<(std::ostream& out, const Index& I) {
39
40 out << '[' << I.first() << ':' << I.last() << ':' << I.stride() << ']';
41 return out;
42}
43
44
46// Calculate the least common multipple of s1 and s2.
47// put the result in s.
48// also calculate m1 = s/s1 and m2 = s/s2.
49// This version is optimized for small s1 and s2 and
50// just uses an exhaustive search.
52inline
53void lcm(int s1, int s2, int &s, int &m1, int &m2)
54{
55
56 PAssert_GT(s1, 0); // For simplicity, make some assumptions.
57 PAssert_GT(s2, 0);
58 int i1=s1;
59 int i2=s2;
60 int _m1 = 1;
61 int _m2 = 1;
62 if (i2<i1)
63 while(true)
64 {
65 while (i2<i1)
66 {
67 i2 += s2;
68 ++_m2;
69 }
70 if (i1==i2)
71 {
72 m1 = _m1;
73 m2 = _m2;
74 s = i1;
75 return;
76 }
77 i1 += s1;
78 ++_m1;
79 }
80 else
81 while(true)
82 {
83 while (i1<i2)
84 {
85 i1 += s1;
86 ++_m1;
87 }
88 if (i1==i2)
89 {
90 m1 = _m1;
91 m2 = _m2;
92 s = i1;
93 return;
94 }
95 i2 += s2;
96 ++_m2;
97 }
98}
99
101
102//
103// Intersect, with the code for the common case of
104// both strides equal to one.
105//
106
107Index
108Index::intersect(const Index& rhs) const
109{
110 Index ret = DontInitialize() ;
111 if ( (stride()==1) && (rhs.stride()==1) ) {
112 int lf = first();
113 int rf = rhs.first();
114 int ll = last();
115 int rl = rhs.last();
116 int f = lf > rf ? lf : rf;
117 int l = ll < rl ? ll : rl;
118 ret.First = f;
119 ret.Length = ( (l>=f) ? l-f+1 : 0 );
120 ret.Stride = 1;
121 ret.BaseFirst = BaseFirst + f - lf;
122 ret.Base = Base;
123 }
124 else
125 ret = general_intersect(rhs);
126 return ret;
127}
128
130
131static Index do_intersect(const Index &a, const Index &b)
132{
133
134 PAssert_GT(a.stride(), 0); // This should be assured by the
135 PAssert_GT(b.stride(), 0); // caller of this function.
136
137 int newStride; // The stride for the new index is
138 int a_mul,b_mul; // a_mul=newStride/a.stride() ...
139 lcm(a.stride(),b.stride(), // The input strides...
140 newStride,a_mul,b_mul); // the lcm of the strides of a and b.
141
142 // Find the offset from a.first() in units of newStride
143 // that puts the ranges close together.
144 int a_i = (b.first()-a.first())/a.stride();
145 int a_off = a.first() + a_i*a.stride();
146 if (a_off < b.first())
147 {
148 a_i++;
149 a_off += a.stride();
150 }
151 PAssert_GE(a_off, b.first()); // make sure I'm understanding this right...
152
153 // Now do an exhaustive search for the first point in common.
154 // Count over all possible offsets for a.
155 for (int a_m=0;(a_m<a_mul)&&(a_i<(int)a.length());a_m++,a_i++,a_off+=a.stride())
156 {
157 int b_off = b.first();
158 // Count over all possible offsets for b.
159 for (int b_m=0; (b_m<b_mul)&&(b_m<(int)b.length()); b_m++,b_off+=b.stride())
160 if ( a_off == b_off )
161 { // If the offsets are the same, we found it!
162 int am = a.max(); // Find the minimum maximum of a and b...
163 int bm = b.max();
164 int m = am < bm ? am : bm;
165 return Index(a_off, m, newStride);
166 }
167 }
168 return Index(0); // If we get to here there is no intersection.
169}
170
172
174{
175
176 // If they just don't overlap, return null indexes.
177 if ( (min() > that.max()) || (that.min() > max()) )
178 return Index(0);
179 if ( (Stride==0) || (that.Stride==0) )
180 return Index(0);
181
182 // If one or the other counts -ve, reverse it and intersect result.
183 if ( that.Stride < 0 )
184 return intersect(that.reverse());
185 if ( Stride < 0 )
186 {
187 Index r;
188 r = reverse().intersect(that).reverse();
189 int diff = (r.First-First)/Stride;
190 PAssert_GE(diff, 0);
191 r.BaseFirst = BaseFirst + diff;
192 return r;
193 }
194
195 // Getting closer to the real thing: intersect them.
196 // Pass the one that starts lower as the first argument.
197 Index r;
198 if ( First < that.First )
199 r = do_intersect(*this,that);
200 else
201 r = do_intersect(that,*this);
202
203 // Set the base so you can find what parts correspond
204 // to the original interval.
205 r.Base = Base;
206 int diff = (r.First - First)/Stride;
207 PAssert_GE(diff, 0);
208 r.BaseFirst = BaseFirst + diff;
209 return r;
210}
211
213
214#ifdef DEBUG_INDEX
215int main()
216{
217
218 const int N = 16; // Number of grid points.
219 const int NP = 4; // Number of processors.
220 const int NL = N/NP; // Grid points per processor.
221 int p; // processor counter.
222
223 Index Ranges[NP]; // an index for each processor.
224 for (p=0;p<NP;p++) // On each processor
225 Ranges[p] = Index(p*NL,(p+1)*NL-1); // Set the local range
226
227 for (p=0;p<NP;p++) // On each processor
228 cout << Ranges[p] << endl;
229
230 // work out A[Dest] = B[2*Dest];
231 // Dest = [0...N/2-1]
232 // Index Dest(N/2);
233 // Index Src = 2*Dest;
234
235 // Also try this:
236 // Index Dest(N);
237 // Index Src = N-1-Dest;
238
239 // and this
240 Index Dest(N);
241 Index Src = Dest - 1;
242
243 // another
244 // Index Dest(0,N/2,2);
245 // Index Src = Dest/2;
246
247 // yet another
248 // Index Dest = N-1-2*Index(N/2);
249 // Index Src = N-1-Dest;
250
251 cout << "Dest=" << Dest << endl;
252 cout << "Src =" << Src << endl;
253
254 // Find out the gets from each processor for that operation.
255 for (p=0; p<NP; p++)
256 {
257 cout << "On vp=" << p << ", range=" << Ranges[p] << endl;
258
259 // Calculate what gets will be done.
260 Index LDRange = Dest.intersect(Ranges[p]); // Local Destination Range for p
261 Index SDRange = Src.plugBase(LDRange); // Where that comes from.
262 cout << "LDRange = " << LDRange << endl;
263 cout << "SDRange = " << SDRange << endl;
264 for (int pp=0; pp<NP; pp++)
265 { // Get from pp
266 Index LSDRange = SDRange.intersect(Ranges[pp]); // what comes from pp
267 if (!LSDRange.empty())
268 {
269 cout << " from proc=" << pp << ", receive " << LSDRange << endl;
270 }
271 }
272
273 // Calculate the puts.
274 Index LSRange = Src.intersect(Ranges[p]);
275 Index DSRange = Dest.plugBase(LSRange); // The destination for that.
276 cout << "LSRange = " << LSRange << endl;
277 cout << "DSRange = " << DSRange << endl;
278 for (pp=0; pp<NP; pp++)
279 { // Put to pp
280 Index LDSRange = LSRange.plugBase(DSRange.intersect(Ranges[pp]));
281 if (!LDSRange.empty())
282 {
283 cout << " send to pp=" << pp << ", the range=" << LDSRange << endl;
284 }
285 }
286 }
287}
288
289#endif // DEBUG_INDEX
290
291/***************************************************************************
292 * $RCSfile: Index.cpp,v $ $Author: adelmann $
293 * $Revision: 1.1.1.1 $ $Date: 2003/01/23 07:40:27 $
294 * IPPL_VERSION_ID: $Id: Index.cpp,v 1.1.1.1 2003/01/23 07:40:27 adelmann Exp $
295 ***************************************************************************/
int main(int argc, char *argv[])
Definition: Main.cpp:128
void lcm(int s1, int s2, int &s, int &m1, int &m2)
Definition: Index.cpp:53
std::ostream & operator<<(std::ostream &out, const Index &I)
Definition: Index.cpp:38
std::complex< double > a
Inform & endl(Inform &inf)
Definition: Inform.cpp:42
#define PAssert_GE(a, b)
Definition: PAssert.h:109
#define PAssert_GT(a, b)
Definition: PAssert.h:108
Definition: Index.h:237
int stride() const
Definition: IndexInlines.h:121
int Base
Definition: Index.h:486
unsigned BaseFirst
Definition: Index.h:482
bool empty() const
Definition: IndexInlines.h:126
int last() const
Definition: IndexInlines.h:136
Index intersect(const Index &) const
Definition: Index.cpp:108
int max() const
Definition: IndexInlines.h:146
int Stride
Definition: Index.h:476
unsigned Length
Definition: Index.h:477
Index plugBase(const Index &) const
Definition: IndexInlines.h:215
int First
Definition: Index.h:475
Index reverse() const
Definition: IndexInlines.h:228
int min() const
Definition: IndexInlines.h:141
unsigned int length() const
Definition: IndexInlines.h:131
Index general_intersect(const Index &) const
Definition: Index.cpp:173
int first() const
Definition: IndexInlines.h:116