src/Field/CompressedBrickIterator.cpp

Go to the documentation of this file.
00001 // -*- C++ -*-
00002 /***************************************************************************
00003  *
00004  * The IPPL Framework
00005  * 
00006  * This program was prepared by PSI. 
00007  * All rights in the program are reserved by PSI.
00008  * Neither PSI nor the author(s)
00009  * makes any warranty, express or implied, or assumes any liability or
00010  * responsibility for the use of this software
00011  *
00012  * Visit http://www.acl.lanl.gov/POOMS for more details
00013  *
00014  ***************************************************************************/
00015 
00016 // -*- C++ -*-
00017 /***************************************************************************
00018  *
00019  * The IPPL Framework
00020  * 
00021  *
00022  * Visit http://people.web.psi.ch/adelmann/ for more details
00023  *
00024  ***************************************************************************/
00025 
00026 // include files
00027 #include "Field/CompressedBrickIterator.h"
00028 #include "Utility/PAssert.h"
00029 #include "Profile/Profiler.h"
00030 
00032 //
00033 // The constructor that produces a compressed CompressedBrickIterator.
00034 // All it really does is initialize the BrickIterator like normal
00035 // except with a pointer to the CompressedData, with strides equal
00036 // to zero.
00037 //
00039 
00040 template<class T, unsigned Dim>
00041 CompressedBrickIterator<T,Dim>::
00042 CompressedBrickIterator(const NDIndex<Dim>& o, T& compressed)
00043 {
00044   TAU_TYPE_STRING(taustr, "void (" + CT(o) + ", " + CT(compressed) + " )" );
00045   TAU_PROFILE("CompressedBrickIterator::CompressedBrickIterator()", taustr,
00046               TAU_FIELD);
00047 
00048   // Point to the single data element.
00049   BrickIterator<T,Dim>::Current = CompressedData = &compressed;
00050   for (unsigned d=0; d<Dim; ++d)
00051     {
00052       // The counts start off at zero.
00053       BrickCounter<Dim>::Counters[d] = 0;
00054       // The counts are just the lengths.
00055       BrickCounter<Dim>::Counts[d] = o[d].length();
00056       // Set all the strides to zero.
00057       BrickIterator<T,Dim>::Strides[d] = 0;
00058     }
00059 }
00060 
00062 //
00063 // The routine that checks to see if all the values are the same.
00064 // This is a regular function so that we can do compile time recursion.
00065 // 
00067 
00068 //
00069 // CompressedLoopTag
00070 //
00071 // A tag that we can use to get the compile recursion to work.
00072 //
00073 // If B==true then we have an explicit function available.
00074 // If B==false we need to use the general loop.
00075 //
00076 // If Dim>3 we use the general loop, but it calls the 
00077 // one for Dim-1 so the inner loops are always efficient.
00078 //
00079 
00080 template<unsigned Dim, bool B=(Dim<=3)>
00081 class CompressedLoopTag
00082 {
00083 #ifdef IPPL_PURIFY
00084   // Add explicit default/copy constructors and op= to avoid UMR's.
00085 public:
00086   CompressedLoopTag() {}
00087   CompressedLoopTag(const CompressedLoopTag<Dim,B> &) {}
00088   CompressedLoopTag<Dim,B>&
00089   operator=(const CompressedLoopTag<Dim,B> &) { return *this; }
00090 #endif
00091 };
00092 
00093 //
00094 // Here is the one dimensional version that checks if all the values
00095 // in a block are the same.
00096 //
00097 
00098 template<class T, unsigned Dim>
00099 inline bool
00100 all_values_equal( const CompressedBrickIterator<T,Dim>& iter, T val,
00101                   CompressedLoopTag<1,true> )
00102                   //mwerks                CompressedLoopTag<1> )
00103 {
00104   TAU_TYPE_STRING(taustr, "bool (" + CT(iter) + ", " + CT(val) 
00105     + ", CompressedLoopTag<1> )" );
00106   TAU_PROFILE("all_values_equal()", taustr, TAU_FIELD);
00107   // Loop over all the elements.
00108   int n = iter.size(0);
00109   for (int i=0; i<n; ++i)
00110     // If it is not the same, return failure.
00111     if ( val != iter.offset(i) )
00112       return false;
00113   // If we get to here then all the values were the same.
00114   return true;
00115 }
00116 
00117 //
00118 // Here is the two dimensional version that checks if all the values
00119 // in a block are the same.
00120 //
00121 
00122 template<class T, unsigned Dim>
00123 inline bool
00124 all_values_equal( const CompressedBrickIterator<T,Dim>& iter, T val ,
00125                   CompressedLoopTag<2,true> )
00126   //mwerks                CompressedLoopTag<2> )
00127 {
00128   TAU_TYPE_STRING(taustr, "bool (" + CT(iter) + ", " + CT(val) 
00129     + ", CompressedLoopTag<2> )" );
00130   TAU_PROFILE("all_values_equal()", taustr, TAU_FIELD);
00131   // Loop over all of the elements.
00132   int n0 = iter.size(0);
00133   int n1 = iter.size(1);
00134   
00135   if ( (n0>0)&&(n1>0) )
00136     for (int i1=0; i1<n1; ++i1)
00137       for (int i0=0; i0<n0; ++i0)
00138         {
00139           // If it is not the same, return failure.
00140           if ( !(val == iter.offset(i0,i1)) )
00141             return false;
00142         }
00143   // If we get to here then all the values were the same.
00144   return true;
00145 }
00146 
00147 //
00148 // Here is the three dimensional version that checks if all the values
00149 // in a block are the same.
00150 //
00151 
00152 template<class T, unsigned Dim>
00153 inline bool
00154 all_values_equal( const CompressedBrickIterator<T,Dim>& iter, T val ,
00155                   CompressedLoopTag<3,true> )
00156   //mwerks                CompressedLoopTag<3> )
00157 {
00158   TAU_TYPE_STRING(taustr, "bool (" + CT(iter) + ", " + CT(val) 
00159     + ", CompressedLoopTag<3> )" );
00160   TAU_PROFILE("all_values_equal()", taustr, TAU_FIELD);
00161   // Loop over all of the elements.
00162   int n0 = iter.size(0);
00163   int n1 = iter.size(1);
00164   int n2 = iter.size(2);
00165   if ( (n0>0)&&(n1>0)&&(n2>0) ) 
00166     for (int i2=0; i2<n2; ++i2)
00167       for (int i1=0; i1<n1; ++i1)
00168         for (int i0=0; i0<n0; ++i0)
00169           // If it is not the same, return failure.
00170           if ( !(val == iter.offset(i0,i1,i2)) )
00171             return false;
00172   // If we get to here then all the values were the same.
00173   return true;
00174 }
00175 
00176 //
00177 // Here is the N dimensional version that checks if all the values
00178 // in a block are the same.
00179 //
00180 // Note that for this one we pass iter by value instead of by 
00181 // reference because we use the step() member function.
00182 //
00183 
00184 template<class T, unsigned Dim1, unsigned Dim2>
00185 inline bool
00186 all_values_equal(CompressedBrickIterator<T,Dim1> iter, T val,
00187                  CompressedLoopTag<Dim2,false>)
00188 {
00189   TAU_TYPE_STRING(taustr, "bool (" + CT(iter) + ", " + CT(val) 
00190     + ", CompressedLoopTag<Dim2,false> )" );
00191   TAU_PROFILE("all_values_equal()", taustr, TAU_FIELD);
00192   // Loop over the outermost dimension.
00193   int n = iter.size(Dim2-1);
00194   for (int i=0; i<n; ++i)
00195     {
00196       // Check if the next innermost dimension is all equal.
00197       //mwerks      if ( ! all_values_equal(iter,val,CompressedLoopTag<(Dim2-1)>()) )
00198       if ( ! all_values_equal(iter,val,
00199                               CompressedLoopTag<(Dim2-1),((Dim2-1)<=3)>()) )
00200         // If not, we're done.
00201         return false;
00202       // Otherwise step one in the outermost dimension.
00203       iter.step(Dim2-1);
00204     }
00205   // If we get to here they were all equal.
00206   return true;
00207 }
00208 
00210 //
00211 // The function that compresses the iterator if all the 
00212 // data it points to are equal to the given value.
00213 // 
00215 
00216 template<class T, unsigned Dim>
00217 bool CompressedBrickIterator<T,Dim>::CanCompress(const T& val) const
00218 {
00219   TAU_TYPE_STRING(taustr, CT(*this) + " bool (" + CT(val) + " )" );
00220   TAU_PROFILE("CompressedBrickIterator::CanCompress()", taustr, TAU_FIELD);
00221   if ( IsCompressed() )
00222     return *CompressedData == val;
00223   else
00224     return all_values_equal(*this,val,CompressedLoopTag<Dim,(Dim<=3)>());
00225   //mwerks    return all_values_equal(*this,val,CompressedLoopTag<Dim>());
00226 }
00227 
00228 
00229 // put data into a message to send to another node
00230 // ... for putMessage, the second argument
00231 // is used for an optimization for when the entire brick is being
00232 // sent.  If that is so, do not copy data into a new buffer, just
00233 // put the pointer into the message.  USE WITH CARE.  The default is
00234 // tohave putMessage make a copy of the data in the brick before adding
00235 // it to the message.  In many situations, this is required since the
00236 // data referred to by the iterator is not contiguous.  getMessage
00237 // has no such option, it always does the most efficient thing it can.
00238 template<class T, unsigned Dim>
00239 Message& CompressedBrickIterator<T,Dim>::putMessage(Message& m, bool makecopy)
00240 {
00241   TAU_TYPE_STRING(taustr, CT(*this) + " Message (Message )" );
00242   TAU_PROFILE("CompressedBrickIterator::putMessage()", taustr,
00243               TAU_FIELD|TAU_MESSAGE);
00244 
00245   // Add in flag indicating if we're compressed.  Put it in as an integer.
00246   int compressed = (IsCompressed() ? 1 : 0);
00247   m.put(compressed);
00248   if (compressed == 1)
00249     {
00250       // If we are compressed, just add in the sizes and the value.
00251       int s[Dim];
00252       for (unsigned int i=0; i < Dim; ++i)
00253         s[i] = BrickCounter<Dim>::size(i);
00254       m.put(s, s + Dim);
00255       ::putMessage(m, BrickIterator<T,Dim>::Current, BrickIterator<T,Dim>::Current + 1);
00256     }
00257   else
00258     {
00259       // If uncompressed, just do as a normal BrickIterator.
00260       BrickIterator<T,Dim>::putMessage(m, makecopy);
00261     }
00262   return m;
00263 }
00264 
00265 // get data out from a message
00266 template<class T, unsigned Dim>
00267 Message& CompressedBrickIterator<T,Dim>::getMessage(Message& m)
00268 {
00269   TAU_TYPE_STRING(taustr, CT(*this) + " Message (Message )" );
00270   TAU_PROFILE("CompressedBrickIterator::getMessage()",taustr,
00271               TAU_FIELD|TAU_MESSAGE);
00272   // Inform msg("CBI::getMessage", INFORM_ALL_NODES);
00273   int compressed;
00274   m.get(compressed);
00275   // msg << "  Compressed = " << compressed << endl;
00276   if (compressed == 1)
00277     {
00278       int s[Dim];
00279       m.get((int*) s);
00280       for (unsigned int i=0; i < Dim; ++i) {
00281         BrickCounter<Dim>::Counts[i] = s[i];
00282         BrickIterator<T,Dim>::Strides[i] = 0;
00283         BrickCounter<Dim>::Counters[i] = 0;
00284       }
00285       PAssert(CompressedData != 0);
00286       BrickIterator<T,Dim>::Current = CompressedData;
00287       ::getMessage_iter(m, BrickIterator<T,Dim>::Current);
00288       // msg << "  Current value = " << *Current << endl;
00289       // msg << "  Compres value = " << *CompressedData << endl;
00290     }
00291   else
00292     {
00293       //    ((BrickIterator<T,Dim>*)this)->getMessage(m);
00294       BrickIterator<T,Dim>::getMessage(m);
00295     }
00296   return m;
00297 }
00298 
00300 
00301 template<class T, unsigned D1, unsigned D2>
00302 CompressedBrickIterator<T,D2>
00303 permute(const CompressedBrickIterator<T,D1>& iter,
00304         const NDIndex<D1>& current, const NDIndex<D2>& perm)
00305 {
00306 #if (defined(PROFILING_ON) || defined(TRACING_ON))
00307   static CompressedBrickIterator<T,D2>* tautmp;
00308 #endif
00309   TAU_TYPE_STRING(taustr, CT(*tautmp) + " (" + CT(iter) + ", " + CT(current) +
00310                           ", " + CT(perm) + ")");
00311   TAU_PROFILE("permute()", taustr, TAU_FIELD);
00312   int d1, d2;
00313 
00314 #ifdef IPPL_DEBUG
00315   // Do a sanity check.
00316   // Make sure that any indexes in current that don't appear
00317   // in perm have length of 1.
00318   // It is ok to have indexes in perm that don't appear in current.
00319   // They just get zero stride.
00320 
00321   // Check each Index in current.
00322   for (d1=0; d1<D1; ++d1)
00323     {
00324       // Compare with every Index in perm.
00325       for (d2=0; d2<D2; ++d2)
00326         // If they match, check the next one.
00327         if ( perm[d2].sameBase( current[d1] ) )
00328           {
00329             goto FoundIt;
00330           }
00331       // Didn't find it.
00332       // Make sure the length is 1.
00333       PAssert( current[d1].length() == 1 );
00334     FoundIt:
00335       ;
00336     }
00337   
00338 #endif
00339 
00340   // This is the iterator we'll be building.
00341   CompressedBrickIterator<T,D2> permute(iter.GetCompressedData());
00342   if ( iter.IsCompressed() )
00343     {
00344       permute = CompressedBrickIterator<T,D2>( perm, *iter );
00345     }
00346   else
00347     {
00348       // Set the pointer to the same place as the one passed in.
00349       permute.SetCurrent( &*iter );
00350 
00351       // Loop over each dimension of the iterator.
00352       for (d2=0; d2<D2; ++d2)
00353         {
00354           // The size of the loop comes from the permuted NDIndex.
00355           permute.SetCount(d2,perm[d2].length());
00356           // Set the counters to zero.
00357           permute.ResetCounter(d2);
00358           // Set the stride to zero in case we don't find a match below.
00359           permute.SetStride(d2,0);
00360           // Check each Index in current to find a match.
00361           for (d1=0; d1<D1; ++d1)
00362             {
00363               if ( current[d1].sameBase( perm[d2] ) )
00364                 {
00365                   // Found it.  Get the stride for this loop.
00366                   permute.SetStride(d2,iter.GetStride(d1));
00367                   // On to the next.
00368                   break;
00369                 }
00370             }
00371         }
00372     }
00373   // Done constructing permute.
00374   return permute;
00375 }
00376 
00378 
00379 template<class T, unsigned Dim>
00380 const CompressedBrickIterator<T,Dim>&
00381 CompressedBrickIterator<T,Dim>::
00382 operator=(const CompressedBrickIterator<T,Dim>& rhs)
00383 {
00384   TAU_TYPE_STRING(taustr, CT(rhs) + " (" + CT(rhs) + " )" ); 
00385   TAU_PROFILE("CompressedBrickIterator::operator=()", taustr, 
00386     TAU_FIELD | TAU_ASSIGN);
00387   if ( this != &rhs )
00388     {
00389       *(dynamic_cast<BrickIterator<T,Dim>*>(this)) = rhs;
00390       CompressedData = rhs.CompressedData;
00391     }
00392   return *this;
00393 }
00394 
00396 
00397 template<class T, unsigned Dim>
00398 CompressedBrickIterator<T,Dim>::
00399 CompressedBrickIterator(const CompressedBrickIterator<T,Dim>& X)
00400   : BrickIterator<T,Dim>(X), CompressedData(X.CompressedData)
00401 {
00402   TAU_TYPE_STRING(taustr, "void (" + CT(X) + " )" ); 
00403   TAU_PROFILE("CompressedBrickIterator::CompressedBrickIterator()", taustr, 
00404     TAU_FIELD);
00405 }
00406 
00408 
00409 // Make it compress to a given value.
00410 // NOTE!!!! This function can only be useful in the following two contexts:
00411 //   1. the iterator was constructed with specific internal storage for
00412 //      CompressedData; and this external storage will be modified (the new
00413 //      value 'val' will be written into the storage.
00414 //   2. the iterator was constructed with no internal storage, and you call
00415 //      Compress with an external variable for which you can take the address
00416 //      and have 'CompressedData' point to.
00417 template<class T, unsigned Dim>
00418 void 
00419 CompressedBrickIterator<T,Dim>::Compress(T& val)
00420 {
00421   TAU_TYPE_STRING(taustr, CT(*this) + " void (" + CT(val) + " )" );
00422   TAU_PROFILE("CompressedBrickIterator::Compress()", taustr, TAU_FIELD);
00423   // Inform msg("CBI::Compress", INFORM_ALL_NODES);
00424   // msg << "Before storing value " << val << ": ";
00425   // msg << "CompressedData = " << (void *)CompressedData;
00426   if (CompressedData != 0) {
00427     // msg << ", old deref value = " << *CompressedData;
00428     *CompressedData = val;
00429     // msg << ", new deref value = " << *CompressedData;
00430   } else {
00431     CompressedData = &val;
00432   }
00433   // msg << endl;
00434   BrickIterator<T,Dim>::Current = CompressedData;
00435   for (unsigned d=0; d<Dim; ++d)
00436     BrickIterator<T,Dim>::Strides[d] = 0;
00437 }
00438 
00440 
00441 // Here is a version that lets the user specify a value
00442 // to try sparsifying on.
00443 template<class T, unsigned Dim>
00444 bool 
00445 CompressedBrickIterator<T,Dim>::TryCompress(T val)
00446 {
00447   TAU_TYPE_STRING(taustr, CT(*this) + " bool (" + CT(val) + " )" );
00448   TAU_PROFILE("CompressedBrickIterator::TryCompress()", taustr, TAU_FIELD);
00449   // Inform msg("CBI::TryCompress", INFORM_ALL_NODES);
00450   // msg << "Trying to compress to value " << val;
00451   // msg << " : IsCompressed = " << IsCompressed() << endl;
00452   if ( IsCompressed() )
00453     return true;
00454   if ( CanCompress(val) )
00455     {
00456       // msg << "  Compressing now." << endl;
00457       // NOTE!!!! This next call will ONLY work if this iterator was
00458       // constructed with some external storage for the CompressedData.
00459       // If at the time of this call CompressedData == 0, then this will
00460       // just not work, since CompressedData will be set to the address of
00461       // val which is a temporary variable only active within the scope of
00462       // this function. (bfh)
00463       Compress(val);
00464       return true;
00465     }
00466   // msg << "  Cannot compress." << endl;
00467   return false;
00468 }
00469 
00470 /***************************************************************************
00471  * $RCSfile: CompressedBrickIterator.cpp,v $   $Author: adelmann $
00472  * $Revision: 1.1.1.1 $   $Date: 2003/01/23 07:40:26 $
00473  * IPPL_VERSION_ID: $Id: CompressedBrickIterator.cpp,v 1.1.1.1 2003/01/23 07:40:26 adelmann Exp $ 
00474  ***************************************************************************/

Generated on Mon Jan 16 13:23:44 2006 for IPPL by  doxygen 1.4.6