// -*- C++ -*- /*************************************************************************** * * The IPPL Framework * * This program was prepared by PSI. * All rights in the program are reserved by PSI. * Neither PSI nor the author(s) * makes any warranty, express or implied, or assumes any liability or * responsibility for the use of this software * * Visit www.amas.web.psi for more details * ***************************************************************************/ // -*- C++ -*- /*************************************************************************** * * The IPPL Framework * * * Visit http://people.web.psi.ch/adelmann/ for more details * ***************************************************************************/ // include files #include "Field/CompressedBrickIterator.h" #include "Utility/PAssert.h" ////////////////////////////////////////////////////////////////////// // // The constructor that produces a compressed CompressedBrickIterator. // All it really does is initialize the BrickIterator like normal // except with a pointer to the CompressedData, with strides equal // to zero. // ////////////////////////////////////////////////////////////////////// template CompressedBrickIterator:: CompressedBrickIterator(const NDIndex& o, T& compressed) { // Point to the single data element. BrickIterator::Current = CompressedData = &compressed; for (unsigned d=0; d::Counters[d] = 0; // The counts are just the lengths. BrickCounter::Counts[d] = o[d].length(); // Set all the strides to zero. BrickIterator::Strides[d] = 0; } } ////////////////////////////////////////////////////////////////////// // // The routine that checks to see if all the values are the same. // This is a regular function so that we can do compile time recursion. // ////////////////////////////////////////////////////////////////////// // // CompressedLoopTag // // A tag that we can use to get the compile recursion to work. // // If B==true then we have an explicit function available. // If B==false we need to use the general loop. // // If Dim>3 we use the general loop, but it calls the // one for Dim-1 so the inner loops are always efficient. // template class CompressedLoopTag { #ifdef IPPL_PURIFY // Add explicit default/copy constructors and op= to avoid UMR's. public: CompressedLoopTag() {} CompressedLoopTag(const CompressedLoopTag &) {} CompressedLoopTag& operator=(const CompressedLoopTag &) { return *this; } #endif }; // // Here is the one dimensional version that checks if all the values // in a block are the same. // template inline bool all_values_equal( const CompressedBrickIterator& iter, T val, CompressedLoopTag<1,true> ) //mwerks CompressedLoopTag<1> ) { // Loop over all the elements. int n = iter.size(0); for (int i=0; i inline bool all_values_equal( const CompressedBrickIterator& iter, T val , CompressedLoopTag<2,true> ) //mwerks CompressedLoopTag<2> ) { // Loop over all of the elements. int n0 = iter.size(0); int n1 = iter.size(1); if ( (n0>0)&&(n1>0) ) for (int i1=0; i1 inline bool all_values_equal( const CompressedBrickIterator& iter, T val , CompressedLoopTag<3,true> ) //mwerks CompressedLoopTag<3> ) { // Loop over all of the elements. int n0 = iter.size(0); int n1 = iter.size(1); int n2 = iter.size(2); if ( (n0>0)&&(n1>0)&&(n2>0) ) for (int i2=0; i2 inline bool all_values_equal(CompressedBrickIterator iter, T val, CompressedLoopTag) { // Loop over the outermost dimension. int n = iter.size(Dim2-1); for (int i=0; i()) ) if ( ! all_values_equal(iter,val, CompressedLoopTag<(Dim2-1),((Dim2-1)<=3)>()) ) // If not, we're done. return false; // Otherwise step one in the outermost dimension. iter.step(Dim2-1); } // If we get to here they were all equal. return true; } ////////////////////////////////////////////////////////////////////// // // The function that compresses the iterator if all the // data it points to are equal to the given value. // ////////////////////////////////////////////////////////////////////// template bool CompressedBrickIterator::CanCompress(const T& val) const { if ( IsCompressed() ) return *CompressedData == val; else return all_values_equal(*this,val,CompressedLoopTag()); //mwerks return all_values_equal(*this,val,CompressedLoopTag()); } // put data into a message to send to another node // ... for putMessage, the second argument // is used for an optimization for when the entire brick is being // sent. If that is so, do not copy data into a new buffer, just // put the pointer into the message. USE WITH CARE. The default is // tohave putMessage make a copy of the data in the brick before adding // it to the message. In many situations, this is required since the // data referred to by the iterator is not contiguous. getMessage // has no such option, it always does the most efficient thing it can. template Message& CompressedBrickIterator::putMessage(Message& m, bool makecopy) { // Add in flag indicating if we're compressed. Put it in as an integer. int compressed = (IsCompressed() ? 1 : 0); m.put(compressed); if (compressed == 1) { // If we are compressed, just add in the sizes and the value. int s[Dim]; for (unsigned int i=0; i < Dim; ++i) s[i] = BrickCounter::size(i); m.put(s, s + Dim); ::putMessage(m, BrickIterator::Current, BrickIterator::Current + 1); } else { // If uncompressed, just do as a normal BrickIterator. BrickIterator::putMessage(m, makecopy); } return m; } // get data out from a message template Message& CompressedBrickIterator::getMessage(Message& m) { // Inform msg("CBI::getMessage", INFORM_ALL_NODES); int compressed = 0; m.get(compressed); // msg << " Compressed = " << compressed << endl; if (compressed == 1) { int s[Dim]; m.get((int*) s); for (unsigned int i=0; i < Dim; ++i) { BrickCounter::Counts[i] = s[i]; BrickIterator::Strides[i] = 0; BrickCounter::Counters[i] = 0; } PAssert(CompressedData != 0); BrickIterator::Current = CompressedData; ::getMessage_iter(m, BrickIterator::Current); // msg << " Current value = " << *Current << endl; // msg << " Compres value = " << *CompressedData << endl; } else { // ((BrickIterator*)this)->getMessage(m); BrickIterator::getMessage(m); } return m; } ////////////////////////////////////////////////////////////////////// template CompressedBrickIterator permute(const CompressedBrickIterator& iter, const NDIndex& current, const NDIndex& perm) { unsigned int d1, d2; #ifdef IPPL_DEBUG // Do a sanity check. // Make sure that any indexes in current that don't appear // in perm have length of 1. // It is ok to have indexes in perm that don't appear in current. // They just get zero stride. // Check each Index in current. for (d1=0; d1 permute(iter.GetCompressedData()); if ( iter.IsCompressed() ) { permute = CompressedBrickIterator( perm, *iter ); } else { // Set the pointer to the same place as the one passed in. permute.SetCurrent( &*iter ); // Loop over each dimension of the iterator. for (d2=0; d2 const CompressedBrickIterator& CompressedBrickIterator:: operator=(const CompressedBrickIterator& rhs) { if ( this != &rhs ) { *(dynamic_cast*>(this)) = rhs; CompressedData = rhs.CompressedData; } return *this; } ////////////////////////////////////////////////////////////////////// template CompressedBrickIterator:: CompressedBrickIterator(const CompressedBrickIterator& X) : BrickIterator(X), CompressedData(X.CompressedData) { } ////////////////////////////////////////////////////////////////////// // Make it compress to a given value. // NOTE!!!! This function can only be useful in the following two contexts: // 1. the iterator was constructed with specific internal storage for // CompressedData; and this external storage will be modified (the new // value 'val' will be written into the storage. // 2. the iterator was constructed with no internal storage, and you call // Compress with an external variable for which you can take the address // and have 'CompressedData' point to. template void CompressedBrickIterator::Compress(T& val) { // Inform msg("CBI::Compress", INFORM_ALL_NODES); // msg << "Before storing value " << val << ": "; // msg << "CompressedData = " << (void *)CompressedData; if (CompressedData != 0) { // msg << ", old deref value = " << *CompressedData; *CompressedData = val; // msg << ", new deref value = " << *CompressedData; } else { CompressedData = &val; } // msg << endl; BrickIterator::Current = CompressedData; for (unsigned d=0; d::Strides[d] = 0; } ////////////////////////////////////////////////////////////////////// // Here is a version that lets the user specify a value // to try sparsifying on. template bool CompressedBrickIterator::TryCompress(T val) { // Inform msg("CBI::TryCompress", INFORM_ALL_NODES); // msg << "Trying to compress to value " << val; // msg << " : IsCompressed = " << IsCompressed() << endl; if ( IsCompressed() ) return true; if ( CanCompress(val) ) { // msg << " Compressing now." << endl; // NOTE!!!! This next call will ONLY work if this iterator was // constructed with some external storage for the CompressedData. // If at the time of this call CompressedData == 0, then this will // just not work, since CompressedData will be set to the address of // val which is a temporary variable only active within the scope of // this function. (bfh) Compress(val); return true; } // msg << " Cannot compress." << endl; return false; } /*************************************************************************** * $RCSfile: CompressedBrickIterator.cpp,v $ $Author: adelmann $ * $Revision: 1.1.1.1 $ $Date: 2003/01/23 07:40:26 $ * IPPL_VERSION_ID: $Id: CompressedBrickIterator.cpp,v 1.1.1.1 2003/01/23 07:40:26 adelmann Exp $ ***************************************************************************/