OPAL (Object Oriented Parallel Accelerator Library)  2.2.0
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 
38 std::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.
52 inline
53 void 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 
107 Index
108 Index::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 #ifdef UNDEFINED
125  Index test = general_intersect(rhs);
126  cout << "inter: First Length Stride BaseFirst Base " << endl;
127  cout << "*this= " << First << "," << Length << "," << Stride << "," << BaseFirst << "," << Base << endl;
128  cout << "rhs = " << rhs.First << "," << rhs.Length << "," << rhs.Stride << "," << rhs.BaseFirst << "," << rhs.Base << endl;
129  cout << "ret = " << ret.First << "," << ret.Length << "," << ret.Stride << "," << ret.BaseFirst << "," << ret.Base << endl;
130  cout << "test = " << test.First << "," << test.Length << "," << test.Stride << "," << test.BaseFirst << "," << test.Base << endl;
131  PAssert_EQ( ret.Length, test.Length );
132  if ( ret.Length > 0 ) {
133  PAssert_EQ( ret.First , test.First );
134  PAssert_EQ( ret.Stride , test.Stride );
135  PAssert_EQ( ret.BaseFirst, test.BaseFirst );
136  PAssert_EQ( ret.Base, test.Base );
137  }
138 #endif // UNDEFINED
139 
140  }
141  else
142  ret = general_intersect(rhs);
143  return ret;
144 }
145 
147 
148 static Index do_intersect(const Index &a, const Index &b)
149 {
150 
151  PAssert_GT(a.stride(), 0); // This should be assured by the
152  PAssert_GT(b.stride(), 0); // caller of this function.
153 
154  int newStride; // The stride for the new index is
155  int a_mul,b_mul; // a_mul=newStride/a.stride() ...
156  lcm(a.stride(),b.stride(), // The input strides...
157  newStride,a_mul,b_mul); // the lcm of the strides of a and b.
158 
159  // Find the offset from a.first() in units of newStride
160  // that puts the ranges close together.
161  int a_i = (b.first()-a.first())/a.stride();
162  int a_off = a.first() + a_i*a.stride();
163  if (a_off < b.first())
164  {
165  a_i++;
166  a_off += a.stride();
167  }
168  PAssert_GE(a_off, b.first()); // make sure I'm understanding this right...
169 
170  // Now do an exhaustive search for the first point in common.
171  // Count over all possible offsets for a.
172  for (int a_m=0;(a_m<a_mul)&&(a_i<(int)a.length());a_m++,a_i++,a_off+=a.stride())
173  {
174  int b_off = b.first();
175  // Count over all possible offsets for b.
176  for (int b_m=0; (b_m<b_mul)&&(b_m<(int)b.length()); b_m++,b_off+=b.stride())
177  if ( a_off == b_off )
178  { // If the offsets are the same, we found it!
179  int am = a.max(); // Find the minimum maximum of a and b...
180  int bm = b.max();
181  int m = am < bm ? am : bm;
182  return Index(a_off, m, newStride);
183  }
184  }
185  return Index(0); // If we get to here there is no intersection.
186 }
187 
189 
191 {
192 
193  // If they just don't overlap, return null indexes.
194  if ( (min() > that.max()) || (that.min() > max()) )
195  return Index(0);
196  if ( (Stride==0) || (that.Stride==0) )
197  return Index(0);
198 
199  // If one or the other counts -ve, reverse it and intersect result.
200  if ( that.Stride < 0 )
201  return intersect(that.reverse());
202  if ( Stride < 0 )
203  {
204  Index r;
205  r = reverse().intersect(that).reverse();
206  int diff = (r.First-First)/Stride;
207  PAssert_GE(diff, 0);
208  r.BaseFirst = BaseFirst + diff;
209  return r;
210  }
211 
212  // Getting closer to the real thing: intersect them.
213  // Pass the one that starts lower as the first argument.
214  Index r;
215  if ( First < that.First )
216  r = do_intersect(*this,that);
217  else
218  r = do_intersect(that,*this);
219 
220  // Set the base so you can find what parts correspond
221  // to the original interval.
222  r.Base = Base;
223  int diff = (r.First - First)/Stride;
224  PAssert_GE(diff, 0);
225  r.BaseFirst = BaseFirst + diff;
226  return r;
227 }
228 
230 
231 #ifdef DEBUG_INDEX
232 int main()
233 {
234 
235  const int N = 16; // Number of grid points.
236  const int NP = 4; // Number of processors.
237  const int NL = N/NP; // Grid points per processor.
238  int p; // processor counter.
239 
240  Index Ranges[NP]; // an index for each processor.
241  for (p=0;p<NP;p++) // On each processor
242  Ranges[p] = Index(p*NL,(p+1)*NL-1); // Set the local range
243 
244  for (p=0;p<NP;p++) // On each processor
245  cout << Ranges[p] << endl;
246 
247  // work out A[Dest] = B[2*Dest];
248  // Dest = [0...N/2-1]
249  // Index Dest(N/2);
250  // Index Src = 2*Dest;
251 
252  // Also try this:
253  // Index Dest(N);
254  // Index Src = N-1-Dest;
255 
256  // and this
257  Index Dest(N);
258  Index Src = Dest - 1;
259 
260  // another
261  // Index Dest(0,N/2,2);
262  // Index Src = Dest/2;
263 
264  // yet another
265  // Index Dest = N-1-2*Index(N/2);
266  // Index Src = N-1-Dest;
267 
268  cout << "Dest=" << Dest << endl;
269  cout << "Src =" << Src << endl;
270 
271  // Find out the gets from each processor for that operation.
272  for (p=0; p<NP; p++)
273  {
274  cout << "On vp=" << p << ", range=" << Ranges[p] << endl;
275 
276  // Calculate what gets will be done.
277  Index LDRange = Dest.intersect(Ranges[p]); // Local Destination Range for p
278  Index SDRange = Src.plugBase(LDRange); // Where that comes from.
279  cout << "LDRange = " << LDRange << endl;
280  cout << "SDRange = " << SDRange << endl;
281  for (int pp=0; pp<NP; pp++)
282  { // Get from pp
283  Index LSDRange = SDRange.intersect(Ranges[pp]); // what comes from pp
284  if (!LSDRange.empty())
285  {
286  cout << " from proc=" << pp << ", receive " << LSDRange << endl;
287  }
288  }
289 
290  // Calculate the puts.
291  Index LSRange = Src.intersect(Ranges[p]);
292  Index DSRange = Dest.plugBase(LSRange); // The destination for that.
293  cout << "LSRange = " << LSRange << endl;
294  cout << "DSRange = " << DSRange << endl;
295  for (pp=0; pp<NP; pp++)
296  { // Put to pp
297  Index LDSRange = LSRange.plugBase(DSRange.intersect(Ranges[pp]));
298  if (!LDSRange.empty())
299  {
300  cout << " send to pp=" << pp << ", the range=" << LDSRange << endl;
301  }
302  }
303  }
304 }
305 
306 #endif // DEBUG_INDEX
307 
308 /***************************************************************************
309  * $RCSfile: Index.cpp,v $ $Author: adelmann $
310  * $Revision: 1.1.1.1 $ $Date: 2003/01/23 07:40:27 $
311  * IPPL_VERSION_ID: $Id: Index.cpp,v 1.1.1.1 2003/01/23 07:40:27 adelmann Exp $
312  ***************************************************************************/
std::ostream & operator<<(std::ostream &os, const Attribute &attr)
Definition: Attribute.cpp:167
Index intersect(const Index &) const
Definition: Index.cpp:108
int Base
Definition: Index.h:501
Index reverse() const
Definition: IndexInlines.h:228
void lcm(int s1, int s2, int &s, int &m1, int &m2)
Definition: Index.cpp:53
unsigned int length() const
Definition: IndexInlines.h:131
unsigned Length
Definition: Index.h:492
int First
Definition: Index.h:490
#define PAssert_GE(a, b)
Definition: PAssert.h:124
#define PAssert_EQ(a, b)
Definition: PAssert.h:119
Definition: Index.h:236
int last() const
Definition: IndexInlines.h:136
int Stride
Definition: Index.h:491
Index general_intersect(const Index &) const
Definition: Index.cpp:190
#define PAssert_GT(a, b)
Definition: PAssert.h:123
int main(int argc, char *argv[])
Definition: Main.cpp:107
int max() const
Definition: IndexInlines.h:146
Index plugBase(const Index &) const
Definition: IndexInlines.h:215
bool empty() const
Definition: IndexInlines.h:126
int stride() const
Definition: IndexInlines.h:121
int first() const
Definition: IndexInlines.h:116
int min() const
Definition: IndexInlines.h:141
Inform & endl(Inform &inf)
Definition: Inform.cpp:42
unsigned BaseFirst
Definition: Index.h:497