OPAL (Object Oriented Parallel Accelerator Library)  2021.1.99
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  else
125  ret = general_intersect(rhs);
126  return ret;
127 }
128 
130 
131 static 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
215 int 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:127
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