OPAL (Object Oriented Parallel Accelerator Library)  2021.1.99
OPAL
CompressedBrickIterator.hpp
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 
26 // include files
28 #include "Utility/PAssert.h"
29 
30 
32 //
33 // The constructor that produces a compressed CompressedBrickIterator.
34 // All it really does is initialize the BrickIterator like normal
35 // except with a pointer to the CompressedData, with strides equal
36 // to zero.
37 //
39 
40 template<class T, unsigned Dim>
42 CompressedBrickIterator(const NDIndex<Dim>& o, T& compressed)
43 {
44 
45  // Point to the single data element.
46  BrickIterator<T,Dim>::Current = CompressedData = &compressed;
47  for (unsigned d=0; d<Dim; ++d)
48  {
49  // The counts start off at zero.
51  // The counts are just the lengths.
52  BrickCounter<Dim>::Counts[d] = o[d].length();
53  // Set all the strides to zero.
55  }
56 }
57 
59 //
60 // The routine that checks to see if all the values are the same.
61 // This is a regular function so that we can do compile time recursion.
62 //
64 
65 //
66 // CompressedLoopTag
67 //
68 // A tag that we can use to get the compile recursion to work.
69 //
70 // If B==true then we have an explicit function available.
71 // If B==false we need to use the general loop.
72 //
73 // If Dim>3 we use the general loop, but it calls the
74 // one for Dim-1 so the inner loops are always efficient.
75 //
76 
77 template<unsigned Dim, bool B=(Dim<=3)>
78 class CompressedLoopTag
79 {
80 };
81 
82 //
83 // Here is the one dimensional version that checks if all the values
84 // in a block are the same.
85 //
86 
87 template<class T, unsigned Dim>
88 inline bool
91  //mwerks CompressedLoopTag<1> )
92 {
93 
94  // Loop over all the elements.
95  int n = iter.size(0);
96  for (int i=0; i<n; ++i)
97  // If it is not the same, return failure.
98  if ( val != iter.offset(i) )
99  return false;
100  // If we get to here then all the values were the same.
101  return true;
102 }
103 
104 //
105 // Here is the two dimensional version that checks if all the values
106 // in a block are the same.
107 //
108 
109 template<class T, unsigned Dim>
110 inline bool
113  //mwerks CompressedLoopTag<2> )
114 {
115 
116  // Loop over all of the elements.
117  int n0 = iter.size(0);
118  int n1 = iter.size(1);
119 
120  if ( (n0>0)&&(n1>0) )
121  for (int i1=0; i1<n1; ++i1)
122  for (int i0=0; i0<n0; ++i0)
123  {
124  // If it is not the same, return failure.
125  if ( !(val == iter.offset(i0,i1)) )
126  return false;
127  }
128  // If we get to here then all the values were the same.
129  return true;
130 }
131 
132 //
133 // Here is the three dimensional version that checks if all the values
134 // in a block are the same.
135 //
136 
137 template<class T, unsigned Dim>
138 inline bool
141  //mwerks CompressedLoopTag<3> )
142 {
143 
144  // Loop over all of the elements.
145  int n0 = iter.size(0);
146  int n1 = iter.size(1);
147  int n2 = iter.size(2);
148  if ( (n0>0)&&(n1>0)&&(n2>0) )
149  for (int i2=0; i2<n2; ++i2)
150  for (int i1=0; i1<n1; ++i1)
151  for (int i0=0; i0<n0; ++i0)
152  // If it is not the same, return failure.
153  if ( !(val == iter.offset(i0,i1,i2)) )
154  return false;
155  // If we get to here then all the values were the same.
156  return true;
157 }
158 
159 //
160 // Here is the N dimensional version that checks if all the values
161 // in a block are the same.
162 //
163 // Note that for this one we pass iter by value instead of by
164 // reference because we use the step() member function.
165 //
166 
167 template<class T, unsigned Dim1, unsigned Dim2>
168 inline bool
171 {
172 
173  // Loop over the outermost dimension.
174  int n = iter.size(Dim2-1);
175  for (int i=0; i<n; ++i)
176  {
177  // Check if the next innermost dimension is all equal.
178  //mwerks if ( ! all_values_equal(iter,val,CompressedLoopTag<(Dim2-1)>()) )
179  if ( ! all_values_equal(iter,val,
180  CompressedLoopTag<(Dim2-1),((Dim2-1)<=3)>()) )
181  // If not, we're done.
182  return false;
183  // Otherwise step one in the outermost dimension.
184  iter.step(Dim2-1);
185  }
186  // If we get to here they were all equal.
187  return true;
188 }
189 
191 //
192 // The function that compresses the iterator if all the
193 // data it points to are equal to the given value.
194 //
196 
197 template<class T, unsigned Dim>
199 {
200 
201 
202  if ( IsCompressed() )
203  return *CompressedData == val;
204  else
205  return all_values_equal(*this,val,CompressedLoopTag<Dim,(Dim<=3)>());
206  //mwerks return all_values_equal(*this,val,CompressedLoopTag<Dim>());
207 }
208 
209 
210 // put data into a message to send to another node
211 // ... for putMessage, the second argument
212 // is used for an optimization for when the entire brick is being
213 // sent. If that is so, do not copy data into a new buffer, just
214 // put the pointer into the message. USE WITH CARE. The default is
215 // tohave putMessage make a copy of the data in the brick before adding
216 // it to the message. In many situations, this is required since the
217 // data referred to by the iterator is not contiguous. getMessage
218 // has no such option, it always does the most efficient thing it can.
219 template<class T, unsigned Dim>
221 {
222 
223  // Add in flag indicating if we're compressed. Put it in as an integer.
224  int compressed = (IsCompressed() ? 1 : 0);
225  m.put(compressed);
226  if (compressed == 1)
227  {
228  // If we are compressed, just add in the sizes and the value.
229  int s[Dim];
230  for (unsigned int i=0; i < Dim; ++i)
231  s[i] = BrickCounter<Dim>::size(i);
232  m.put(s, s + Dim);
234  }
235  else
236  {
237  // If uncompressed, just do as a normal BrickIterator.
239  }
240  return m;
241 }
242 
243 // get data out from a message
244 template<class T, unsigned Dim>
246 {
247  // Inform msg("CBI::getMessage", INFORM_ALL_NODES);
248  int compressed = 0;
249  m.get(compressed);
250  // msg << " Compressed = " << compressed << endl;
251  if (compressed == 1)
252  {
253  int s[Dim];
254  m.get((int*) s);
255  for (unsigned int i=0; i < Dim; ++i) {
256  BrickCounter<Dim>::Counts[i] = s[i];
259  }
260  PAssert(CompressedData != 0);
261  BrickIterator<T,Dim>::Current = CompressedData;
263  // msg << " Current value = " << *Current << endl;
264  // msg << " Compres value = " << *CompressedData << endl;
265  }
266  else
267  {
268  // ((BrickIterator<T,Dim>*)this)->getMessage(m);
270  }
271  return m;
272 }
273 
275 
276 template<class T, unsigned D1, unsigned D2>
279  const NDIndex<D1>& current, const NDIndex<D2>& perm)
280 {
281 
282  unsigned int d1, d2;
283 
284  // This is the iterator we'll be building.
286  if ( iter.IsCompressed() )
287  {
288  permute = CompressedBrickIterator<T,D2>( perm, *iter );
289  }
290  else
291  {
292  // Set the pointer to the same place as the one passed in.
293  permute.SetCurrent( &*iter );
294 
295  // Loop over each dimension of the iterator.
296  for (d2=0; d2<D2; ++d2)
297  {
298  // The size of the loop comes from the permuted NDIndex.
299  permute.SetCount(d2,perm[d2].length());
300  // Set the counters to zero.
301  permute.ResetCounter(d2);
302  // Set the stride to zero in case we don't find a match below.
303  permute.SetStride(d2,0);
304  // Check each Index in current to find a match.
305  for (d1=0; d1<D1; ++d1)
306  {
307  if ( current[d1].sameBase( perm[d2] ) )
308  {
309  // Found it. Get the stride for this loop.
310  permute.SetStride(d2,iter.GetStride(d1));
311  // On to the next.
312  break;
313  }
314  }
315  }
316  }
317  // Done constructing permute.
318  return permute;
319 }
320 
322 
323 template<class T, unsigned Dim>
327 {
328 
329  if ( this != &rhs )
330  {
331  *(dynamic_cast<BrickIterator<T,Dim>*>(this)) = rhs;
332  CompressedData = rhs.CompressedData;
333  }
334  return *this;
335 }
336 
338 
339 template<class T, unsigned Dim>
342  : BrickIterator<T,Dim>(X), CompressedData(X.CompressedData)
343 {
344 
345 }
346 
348 
349 // Make it compress to a given value.
350 // NOTE!!!! This function can only be useful in the following two contexts:
351 // 1. the iterator was constructed with specific internal storage for
352 // CompressedData; and this external storage will be modified (the new
353 // value 'val' will be written into the storage.
354 // 2. the iterator was constructed with no internal storage, and you call
355 // Compress with an external variable for which you can take the address
356 // and have 'CompressedData' point to.
357 template<class T, unsigned Dim>
358 void
360 {
361 
362 
363  // Inform msg("CBI::Compress", INFORM_ALL_NODES);
364  // msg << "Before storing value " << val << ": ";
365  // msg << "CompressedData = " << (void *)CompressedData;
366  if (CompressedData != 0) {
367  // msg << ", old deref value = " << *CompressedData;
368  *CompressedData = val;
369  // msg << ", new deref value = " << *CompressedData;
370  } else {
371  CompressedData = &val;
372  }
373  // msg << endl;
374  BrickIterator<T,Dim>::Current = CompressedData;
375  for (unsigned d=0; d<Dim; ++d)
377 }
378 
380 
381 // Here is a version that lets the user specify a value
382 // to try sparsifying on.
383 template<class T, unsigned Dim>
384 bool
386 {
387 
388 
389  // Inform msg("CBI::TryCompress", INFORM_ALL_NODES);
390  // msg << "Trying to compress to value " << val;
391  // msg << " : IsCompressed = " << IsCompressed() << endl;
392  if ( IsCompressed() )
393  return true;
394  if ( CanCompress(val) )
395  {
396  // msg << " Compressing now." << endl;
397  // NOTE!!!! This next call will ONLY work if this iterator was
398  // constructed with some external storage for the CompressedData.
399  // If at the time of this call CompressedData == 0, then this will
400  // just not work, since CompressedData will be set to the address of
401  // val which is a temporary variable only active within the scope of
402  // this function. (bfh)
403  Compress(val);
404  return true;
405  }
406  // msg << " Cannot compress." << endl;
407  return false;
408 }
409 
410 /***************************************************************************
411  * $RCSfile: CompressedBrickIterator.cpp,v $ $Author: adelmann $
412  * $Revision: 1.1.1.1 $ $Date: 2003/01/23 07:40:26 $
413  * IPPL_VERSION_ID: $Id: CompressedBrickIterator.cpp,v 1.1.1.1 2003/01/23 07:40:26 adelmann Exp $
414  ***************************************************************************/
const unsigned Dim
#define X(arg)
Definition: fftpack.cpp:112
CompressedBrickIterator< T, D2 > permute(const CompressedBrickIterator< T, D1 > &iter, const NDIndex< D1 > &current, const NDIndex< D2 > &perm)
bool all_values_equal(const CompressedBrickIterator< T, Dim > &iter, T val, CompressedLoopTag< 1, true >)
void putMessage(Message &m, const T &t)
Definition: Message.h:549
void getMessage_iter(Message &m, OutputIterator o)
Definition: Message.h:595
#define PAssert(c)
Definition: PAssert.h:102
bool CanCompress(const T &) const
Message & getMessage(Message &m)
Message & putMessage(Message &m, bool makecopy=true)
const CompressedBrickIterator< T, Dim > & operator=(const CompressedBrickIterator< T, Dim > &rhs)
int size(unsigned d) const
Definition: BrickIterator.h:43
Message & getMessage(Message &)
Message & putMessage(Message &, bool makecopy=true)
T & offset(int i) const
void step(unsigned d)
Definition: BrickIterator.h:95
Message & put(const T &val)
Definition: Message.h:406
Message & get(const T &cval)
Definition: Message.h:476