array2D.h

Go to the documentation of this file.
00001 
00015 #ifndef _DLR_ARRAY2D_H_
00016 #define _DLR_ARRAY2D_H_
00017 
00018 // Early inclusion of <algorithm> to allow inlining of member templates.
00019 #include <algorithm>
00020 
00021 #include <iostream>
00022 #include <dlrCommon/exception.h>
00023 #include <dlrNumeric/array1D.h>
00024 
00025 namespace dlr {
00026 
00027   namespace numeric {
00028     
00051     template <class Type>
00052     class Array2D {
00053     public:
00054 
00055       /* ******** Public typedefs ******** */
00056 
00060       typedef Type value_type;
00061 
00065       typedef Type* iterator;
00066     
00071       typedef const Type* const_iterator;
00072 
00073       /* ******** Public member functions ******** */
00074 
00078       Array2D();
00079 
00089       Array2D(size_t rows, size_t columns);
00090 
00104       explicit
00105       Array2D(const std::string& inputString);
00106 
00113       Array2D(const Array2D<Type> &source);
00114 
00130       Array2D(size_t rows, size_t columns, Type* const dataPtr);
00131 
00132 
00154       Array2D(size_t rows, size_t columns, Type* const dataPtr,
00155               size_t* refCountPtr);
00156     
00161       virtual
00162       ~Array2D();
00163 
00169       iterator
00170       begin() {return m_dataPtr;}
00171 
00178       const_iterator
00179       begin() const {return m_dataPtr;}
00180 
00185       void
00186       clear() {this->reinit(0, 0);}
00187 
00195       size_t
00196       columns() const {return m_columns;}
00197 
00198 
00207       inline void 
00208       checkDimension(size_t rows, size_t columns) const;
00209 
00210     
00216       Array2D<Type>
00217       copy() const;
00218 
00229       template <class Type2> void
00230       copy(const Array2D<Type2>& source);
00231 
00238       template <class Type2> void
00239       copy(const Type2* dataPtr);
00240 
00250       Type*
00251       data() {return m_dataPtr;}
00252 
00259       const Type*
00260       data() const {return m_dataPtr;}
00261 
00272       Type*
00273       data(size_t index) {
00274         this->checkBounds(index);
00275         return m_dataPtr + index;
00276       }
00277 
00287       const Type*
00288       data(size_t index) const {
00289         this->checkBounds(index);
00290         return m_dataPtr+index;
00291       }
00292 
00305       Type*
00306       data(size_t row, size_t column) {
00307         this->checkBounds(row, column);
00308         return m_dataPtr + column + (row * m_columns);
00309       }
00310 
00322       const Type*
00323       data(size_t row, size_t column) const {
00324         this->checkBounds(row, column);
00325         return m_dataPtr + column + (row * m_columns);
00326       }
00327 
00328     
00336       bool
00337       empty() const {return this->size() == 0;}
00338 
00339     
00346       iterator
00347       end() {return m_dataPtr + m_size;}
00348 
00349       
00356       const_iterator
00357       end() const {return m_dataPtr + m_size;}
00358 
00359     
00368       bool
00369       isAllocated() const {return m_isAllocated;}
00370     
00371     
00379       Array1D<Type>
00380       ravel();
00381 
00389       const Array1D<Type>
00390       ravel() const;
00391 
00404       std::istream&
00405       readFromStream(std::istream& inputStream);
00406     
00407 
00415       size_t*
00416       refCountPtr() const {return m_refCountPtr;}
00417 
00418     
00428       void
00429       reinit(size_t rows, size_t columns);
00430 
00445       void
00446       reshape(int rows, int columns);
00447 
00458       Array1D<Type>
00459       row(size_t index);
00460 
00471       const Array1D<Type>
00472       row(size_t index) const;
00473 
00474       
00485       iterator
00486       rowBegin(size_t rowIndex) {return m_dataPtr + rowIndex * m_columns;}
00487 
00488       
00499       const_iterator
00500       rowBegin(size_t rowIndex) const {
00501         return m_dataPtr + rowIndex * m_columns;
00502       }
00503 
00504       
00515       iterator
00516       rowEnd(size_t rowIndex) {
00517         return m_dataPtr + (rowIndex + 1) * m_columns;
00518       }
00519 
00520 
00531       const_iterator
00532       rowEnd(size_t rowIndex) const {
00533         return m_dataPtr + (rowIndex + 1) * m_columns;
00534       }
00535 
00536       
00544       size_t
00545       rows() const {return m_rows;}
00546 
00555       Array1D<size_t>
00556       shape() const;
00557 
00569       size_t
00570       shape(size_t axis) const;
00571 
00578       size_t
00579       size() const {return m_size;}
00580 
00587       Array2D<Type>
00588       transpose() const;
00589     
00598       Array2D<Type>&
00599       operator=(const Array2D<Type>& source);
00600 
00608       Array2D<Type>&
00609       operator=(Type value);
00610 
00619       Type&
00620       operator()(size_t index) {
00621         this->checkBounds(index);
00622         return m_dataPtr[index];
00623       }
00624 
00631       Type operator()(size_t index) const {
00632         this->checkBounds(index);
00633         return m_dataPtr[index];
00634       }
00635   
00645       Type&
00646       operator()(size_t row, size_t column) {
00647         this->checkBounds(row, column);
00648         return m_dataPtr[column + row * m_columns];
00649       }
00650     
00660       Type
00661       operator()(size_t row, size_t column) const {
00662         this->checkBounds(row, column);
00663         return m_dataPtr[column + row * m_columns];
00664       }
00665 
00674       Type&
00675       operator[](size_t index) {return this->operator()(index);}
00676   
00685       Type
00686       operator[](size_t index) const {return this->operator()(index);}
00687 
00699       template <class Type2> Array2D<Type>&
00700       operator+=(const Array2D<Type2>& arg);
00701       
00713       template <class Type2> Array2D<Type>&
00714       operator-=(const Array2D<Type2>& arg);
00715 
00727       template <class Type2> Array2D<Type>&
00728       operator*=(const Array2D<Type2>& arg);
00729 
00741       template <class Type2> Array2D<Type>&
00742       operator/=(const Array2D<Type2>& arg);
00743     
00751       Array2D<Type>&
00752       operator+=(Type arg);
00753 
00761       Array2D<Type>&
00762       operator-=(Type arg);
00763 
00771       Array2D<Type>&
00772       operator*=(Type arg);
00773 
00781       Array2D<Type>&
00782       operator/=(Type arg);
00783 
00784     private:
00785       /* ******** Private member functions ******** */
00786       void
00787       allocate();
00788     
00789       // Optionally throw an exception if index is beyond the range of
00790       // this array.
00791       inline void
00792       checkBounds(size_t index) const;
00793 
00794       // Optionally throw an exception if either index is beyond the
00795       // range of this array.
00796       inline void
00797       checkBounds(size_t row, size_t column) const;
00798 
00799       void
00800       deAllocate();
00801 
00802       // Constants to help with formatting.  We use the initialization
00803       // on first use paradigm for the string constants to avoid
00804       // headaches.
00805 
00810       static const std::string& ioIntro(); 
00811 
00816       static const std::string& ioOutro();
00817 
00822       static const char ioOpening = '[';
00823 
00828       static const char ioClosing = ']';
00829 
00834       static const char ioSeparator = ',';
00835 
00836     
00837       /* ********Private data members******** */
00838       size_t m_rows;
00839       size_t m_columns;
00840       size_t m_size;
00841       Type* m_dataPtr;
00842       size_t* m_refCountPtr;
00843       bool m_isAllocated;
00844     
00845     };
00846   
00847     /* Non-member functions which will ultimately wind up in a different file */
00848 
00859     template <class Type>
00860     Array2D<Type>
00861     squareRoot(const Array2D<Type>& array0);
00862   
00874     template <class Type>
00875     inline Array2D<Type>
00876     sqrt(const Array2D<Type>& array0);
00877 
00891     template <class Type>
00892     Array2D<Type>
00893     operator+(const Array2D<Type>& array0,
00894               const Array2D<Type>& array1);
00895   
00909     template <class Type>
00910     Array2D<Type>
00911     operator-(const Array2D<Type>& array0,
00912               const Array2D<Type>& array1);
00913   
00927     template <class Type>
00928     Array2D<Type>
00929     operator*(const Array2D<Type>& array0,
00930               const Array2D<Type>& array1);
00931   
00945     template <class Type>
00946     Array2D<Type>
00947     operator/(const Array2D<Type>& array0,
00948               const Array2D<Type>& array1);
00949   
00961     template <class Type>
00962     Array2D<Type>
00963     operator+(const Array2D<Type>& array0, Type scalar);
00964   
00976     template <class Type>
00977     Array2D<Type>
00978     operator-(const Array2D<Type>& array0, Type scalar);
00979   
00991     template <class Type>
00992     Array2D<Type>
00993     operator*(const Array2D<Type>& array0, Type scalar);
00994   
01006     template <class Type>
01007     Array2D<Type>
01008     operator/(const Array2D<Type>& array0, Type scalar);
01009 
01021     template <class Type>
01022     inline Array2D<Type>
01023     operator+(Type scalar, const Array2D<Type>& array0);
01024   
01025 
01037     template <class Type>
01038     inline Array2D<Type>
01039     operator*(Type scalar, const Array2D<Type>& array0);
01040 
01041 
01053     template <class Type>
01054     Array2D<bool>
01055     operator==(const Array2D<Type>& array0, const Type arg);
01056 
01057     
01070     template <class Type>
01071     Array2D<bool>
01072     operator==(const Array2D<Type>& array0, const Array2D<Type>& array1);
01073     
01074 
01086     template <class Type>
01087     Array2D<bool>
01088     operator>(const Array2D<Type>& array0, Type arg);
01089 
01090   
01102     template <class Type>
01103     Array2D<bool>
01104     operator<(const Array2D<Type>& array0, Type arg);
01105 
01106   
01119     template <class Type>
01120     Array2D<bool>
01121     operator>=(const Array2D<Type>& array0, Type arg);
01122 
01123   
01136     template <class Type>
01137     Array2D<bool>
01138     operator<=(const Array2D<Type>& array0, Type arg);
01139 
01140   
01159     template <class Type>
01160     std::ostream&
01161     operator<<(std::ostream& stream, const Array2D<Type>& array0);
01162 
01174     template <class Type>
01175     std::istream&
01176     operator>>(std::istream& stream, Array2D<Type>& array0);
01177   
01178   } // namespace numeric
01179 
01180 } // namespace dlr
01181 
01182 
01183 /* ======= Declarations to maintain compatibility with legacy code. ======= */
01184 
01185 namespace dlr {
01186 
01187   using numeric::Array2D;
01188 
01189 } // namespace dlr
01190 
01191 
01192 /*******************************************************************
01193  * Member function definitions follow.  This would be a .C file
01194  * if it weren't templated.
01195  *******************************************************************/
01196 
01197 #include <algorithm>
01198 #include <functional>
01199 #include <sstream>
01200 #include <vector>
01201 #include <dlrCommon/functional.h>
01202 #include <dlrCommon/inputStream.h>
01203 #include <dlrNumeric/numericTraits.h>
01204 #include <dlrNumeric/functional.h>
01205 
01206 namespace dlr {
01207 
01208   namespace numeric {
01209     
01210     // Static constant describing how the string representation of an
01211     // Array2D should start.
01212     template <class Type>
01213     const std::string&
01214     Array2D<Type>::
01215     ioIntro()
01216     {
01217       static const std::string intro = "Array2D(";
01218       return intro;
01219     }
01220 
01221     // Static constant describing how the string representation of an
01222     // Array2D should end.
01223     template <class Type>
01224     const std::string&
01225     Array2D<Type>::
01226     ioOutro()
01227     {
01228       static const std::string outro = ")";
01229       return outro;
01230     }
01231 
01232     // Non-static member functions below.
01233 
01234     template <class Type>
01235     Array2D<Type>::
01236     Array2D()
01237       : m_rows(0),
01238         m_columns(0),
01239         m_size(0),
01240         m_dataPtr(0),
01241         m_refCountPtr(0),
01242         m_isAllocated(false)
01243     {
01244       // Empty
01245     }
01246 
01247     template <class Type>
01248     Array2D<Type>::
01249     Array2D(size_t rows, size_t columns)
01250       : m_rows(rows),
01251         m_columns(columns),
01252         m_size(0),          // This will be set in the call to allocate().
01253         m_dataPtr(0),       // This will be set in the call to allocate().
01254         m_refCountPtr(0),   // This will be set in the call to allocate().
01255         m_isAllocated(false)
01256     {
01257       this->allocate();
01258     }
01259 
01260   
01261     // Construct from an initialization string.
01262     template <class Type>
01263     Array2D<Type>::
01264     Array2D(const std::string& inputString)
01265       : m_rows(0),
01266         m_columns(0),
01267         m_size(0),
01268         m_dataPtr(0),
01269         m_refCountPtr(0),
01270         m_isAllocated(false)
01271     {
01272       // We'll use the stream input operator to parse the string.
01273       std::istringstream inputStream(inputString);
01274 
01275       // Now read the string into an array.
01276       Array2D<Type> inputArray;
01277       inputStream >> inputArray;
01278       if(!inputStream) {
01279         std::ostringstream message;
01280         message << "Couldn't parse input string: \"" << inputString << "\".";
01281         DLR_THROW3(ValueException, "Array2D::Array2D(const std::string&)",
01282                    message.str().c_str());                 
01283       }
01284 
01285       // If all went well, copy into *this.
01286       *this = inputArray;
01287     }
01288 
01289 
01290     /* When copying from a Array2D do a shallow copy */
01291     /* Update reference count if the array we're copying has */
01292     /* valid data. */
01293     template <class Type>
01294     Array2D<Type>::
01295     Array2D(const Array2D<Type>& source)
01296       : m_rows(source.m_rows),
01297         m_columns(source.m_columns),
01298         m_size(source.m_size),
01299         m_dataPtr(source.m_dataPtr),
01300         m_refCountPtr(source.m_refCountPtr),
01301         m_isAllocated(source.m_isAllocated)
01302     {
01303       if(m_isAllocated) {
01304         ++(*m_refCountPtr);
01305       }
01306     }
01307 
01308   
01309     /* Here's a constructor for getting image data into the array */
01310     /* cheaply. */
01311     template <class Type>
01312     Array2D<Type>::
01313     Array2D(size_t rows, size_t columns, Type* const dataPtr)
01314       : m_rows(rows),
01315         m_columns(columns),
01316         m_size(rows*columns),
01317         m_dataPtr(dataPtr),
01318         m_refCountPtr(0),
01319         m_isAllocated(false)
01320     {
01321       // Empty
01322     }
01323 
01324   
01325     // Construct an array around external data which was allocated by
01326     // an Array?D instance.
01327     template <class Type>
01328     Array2D<Type>::
01329     Array2D(size_t rows, size_t columns, Type* const dataPtr,
01330             size_t* refCountPtr)
01331       : m_rows(rows),
01332         m_columns(columns),
01333         m_size(rows*columns),
01334         m_dataPtr(dataPtr),
01335         m_refCountPtr(refCountPtr),
01336         m_isAllocated(true)
01337     {
01338       ++(*m_refCountPtr);
01339     }
01340 
01341   
01342     template <class Type>
01343     Array2D<Type>::
01344     ~Array2D()
01345     {
01346       deAllocate();
01347     }
01348 
01349   
01350     template <class Type>
01351     inline void Array2D<Type>::
01352     checkDimension(size_t rows, size_t columns) const
01353     {
01354 #ifdef _DLRNUMERIC_CHECKBOUNDS_
01355       if(rows != this->rows()
01356          || columns != this->columns()) {
01357         std::ostringstream message;
01358         message << "Size mismatch: required dimension is ("
01359                 << rows << ", " << columns << ") "
01360                 << " while *this has dimension "
01361                 << this->rows() << ", " << this->columns() << ").";
01362         DLR_THROW(IndexException, "Array2D::checkDimension()",
01363                   message.str().c_str());
01364       }
01365 #endif
01366     }
01367 
01368 
01369     template <class Type>
01370     Array2D<Type> Array2D<Type>::
01371     copy() const
01372     {
01373       Array2D<Type> newArray(m_rows, m_columns);
01374       newArray.copy(*this);
01375       return newArray;
01376     }
01377 
01378     template <class Type> template <class Type2>
01379     void Array2D<Type>::
01380     copy(const Array2D<Type2>& source)
01381     {
01382       if(source.size() != m_size) {
01383         std::ostringstream message;
01384         message << "Mismatched array sizes. Source array has "
01385                 << source.size() << " elements, while destination array has "
01386                 << m_size << " elements.";
01387         DLR_THROW3(ValueException, "Array2D::copy(const Array2D&)",
01388                    message.str().c_str());
01389       }
01390       if(m_size != 0) {
01391         this->copy(source.data());
01392       }
01393     }
01394 
01395     template <class Type> template <class Type2>
01396     void Array2D<Type>::
01397     copy(const Type2* dataPtr)
01398     {
01399       if(dataPtr == 0) {
01400         DLR_THROW(ValueException, "Array2D::copy(const Type2*)",
01401                   "Argument is a NULL pointer.");
01402       }
01403       std::transform(dataPtr, dataPtr + m_size, m_dataPtr,
01404                      StaticCastFunctor<Type2, Type>());
01405     }
01406 
01407 
01408     template <class Type>
01409     const Array1D<Type> Array2D<Type>::
01410     ravel() const
01411     {
01412       if(m_isAllocated) {
01413         return Array1D<Type>(m_size, m_dataPtr, m_refCountPtr);
01414       }
01415       return Array1D<Type>(m_size, m_dataPtr);
01416     }
01417 
01418     template <class Type>
01419     Array1D<Type> Array2D<Type>::
01420     ravel()
01421     {
01422       if(m_isAllocated) {
01423         return Array1D<Type>(m_size, m_dataPtr, m_refCountPtr);
01424       }
01425       return Array1D<Type>(m_size, m_dataPtr);
01426     }
01427 
01428 
01429     template <class Type>
01430     std::istream&
01431     Array2D<Type>::
01432     readFromStream(std::istream& inputStream)
01433     {
01434       // Most of the time, InputType will be the same as Type.
01435       typedef typename NumericTraits<Type>::TextOutputType InputType;
01436 
01437       // If stream is in a bad state, we can't read from it.
01438       if (!inputStream){
01439         return inputStream;
01440       }
01441     
01442       // It's a lot easier to use a try block than to be constantly
01443       // testing whether the IO has succeeded, so we tell inputStream to
01444       // complain if anything goes wrong.
01445       std::ios_base::iostate oldExceptionState = inputStream.exceptions();
01446       inputStream.exceptions(
01447         std::ios_base::badbit | std::ios_base::failbit | std::ios_base::eofbit);
01448 
01449       // Now on with the show.
01450       try{
01451         // Construct an InputStream instance so we can use our
01452         // convenience functions.
01453         InputStream stream(inputStream);
01454 
01455         // Skip any preceding whitespace.
01456         stream.skipWhiteSpace();
01457       
01458         // We won't require the input format to start with "Array2D(", but
01459         // if it does we read it here.
01460         bool foundIntro = false;
01461         if(stream.peek() == ioIntro()[0]) {
01462           foundIntro = true;
01463           stream.expect(ioIntro());
01464         }
01465 
01466         // OK.  We've dispensed with the intro.  What's left should be of
01467         // the format "[row, row, row, ...]".  We require the square
01468         // brackets to be there.
01469         stream.expect(ioOpening);
01470 
01471         // Read the data.  We'll use the Array1D<Type> stream operator to
01472         // read each row.
01473         Array1D<Type> inputValue;
01474         std::vector< Array1D<Type> > inputBuffer;
01475         while(1) {
01476           // Read the next row.
01477           stream >> inputValue;
01478           inputBuffer.push_back(inputValue);
01479 
01480           // Read the separator, or else the closing character.
01481           char inChar = 0;
01482           stream >> inChar;
01483           if(inChar == ioClosing) {
01484             // Found a closing.  Stop here.
01485             break;
01486           }
01487           if(inChar != ioSeparator) {
01488             // Missing separator?  Fail here.
01489             stream.clear(std::ios_base::failbit);
01490           }
01491         }
01492     
01493         // If we found an intro, we expect the corresponding outro.
01494         if(foundIntro) {
01495           stream.expect(ioOutro());
01496         }
01497 
01498         // Now we're done with all of the parsing, verify that all rows
01499         // have the same length.
01500         size_t rows = inputBuffer.size();
01501         size_t columns = ((inputBuffer.size() != 0) ? inputBuffer[0].size() : 0);
01502         for(size_t index = 1; index < rows; ++index) {
01503           if(inputBuffer[index].size() != columns) {
01504             // Inconsistent row lengths!  Fail here.
01505             stream.clear(std::ios_base::failbit);
01506           }
01507         }
01508 
01509         // And finally, copy the data.
01510         this->reinit(rows, columns);
01511         for(size_t index = 0; index < rows; ++index) {
01512           std::copy(inputBuffer[index].begin(), inputBuffer[index].end(),
01513                     this->begin() + (index * columns));
01514         }
01515       } catch(std::ios_base::failure) {
01516         // Empty
01517       }
01518       inputStream.exceptions(oldExceptionState);
01519       return inputStream;
01520     }
01521   
01522 
01523     template <class Type>
01524     void Array2D<Type>::
01525     reinit(size_t rows, size_t columns)
01526     {
01527       this->deAllocate();
01528       this->m_rows = rows;
01529       this->m_columns = columns;
01530       this->allocate();
01531     }
01532 
01533 
01534     /* After reshaping, matrix is still row major order */
01535     template <class Type>
01536     void Array2D<Type>::
01537     reshape(int rows, int columns)
01538     {
01539       // If one axis is specified as -1, it will be automatically 
01540       // chosen to match the number of elements in the array.
01541       if((rows == -1) && (columns != 0)) {
01542         rows = static_cast<int>(this->size()) / columns;
01543       } else
01544         if((columns == -1) && (rows != 0)) {
01545           columns = static_cast<int>(this->size()) / rows;
01546         }
01547       if((rows * columns) != static_cast<int>(this->size())) {
01548         std::ostringstream message;
01549         message << "Can't reshape a(n) " << this->size()
01550                 << " element array to have " << rows << " rows and "
01551                 << columns << " columns.";
01552         DLR_THROW(ValueException, "Array2D::reshape()", message.str().c_str());
01553       }
01554       m_rows = rows;
01555       m_columns = columns;
01556     }
01557 
01558   
01559     template <class Type>
01560     Array1D<Type> Array2D<Type>::
01561     row(size_t index)
01562     {
01563       this->checkBounds(index, 0);
01564       return Array1D<Type>(this->columns(),
01565                            m_dataPtr + (index * this->m_columns));
01566     }
01567 
01568   
01569     template <class Type>
01570     const Array1D<Type> Array2D<Type>::
01571     row(size_t index) const
01572     {
01573       this->checkBounds(index, 0);
01574       return Array1D<Type>(this->columns(),
01575                            m_dataPtr + (index * this->m_columns));
01576     }
01577 
01578 
01579     template <class Type>
01580     Array1D<size_t> Array2D<Type>::
01581     shape() const
01582     {
01583       Array1D<size_t> rc(2);
01584       rc(0) = this->rows();
01585       rc(1) = this->columns();
01586       return rc;
01587     }
01588 
01589 
01590     template <class Type>
01591     size_t Array2D<Type>::
01592     shape(size_t axis) const
01593     {
01594       size_t shape;
01595       switch(axis) {
01596       case 0:
01597         shape = this->rows();
01598         break;
01599       case 1:
01600         shape = this->columns();
01601         break;
01602       default:
01603         std::ostringstream message;
01604         message << "Invalid Axis: "<< axis << ".";
01605         DLR_THROW(ValueException, "Array2D::shape(size_t)",
01606                   message.str().c_str());
01607         shape = 0;
01608         break;
01609       }
01610       return shape;
01611     }
01612 
01613 
01614     template <class Type>
01615     Array2D<Type>& Array2D<Type>::
01616     operator=(Type value)
01617     {
01618       std::fill(m_dataPtr, m_dataPtr + m_size, value);
01619       return *this;
01620     }
01621 
01622   
01623     template <class Type>
01624     Array2D<Type>& Array2D<Type>::
01625     operator=(const Array2D<Type>& source)
01626     {
01627       // Check for self-assignment
01628       if(&source != this) {
01629         this->deAllocate();
01630         m_rows = source.m_rows;
01631         m_columns = source.m_columns;
01632         m_size = source.m_size;
01633         m_dataPtr = source.m_dataPtr;
01634         m_refCountPtr = source.m_refCountPtr;
01635         m_isAllocated = source.m_isAllocated;
01636         if(m_isAllocated) {
01637           ++(*m_refCountPtr);
01638         }
01639       }
01640       return *this;
01641     }
01642 
01643 
01644     template <class Type> template <class Type2>
01645     Array2D<Type>&
01646     Array2D<Type>::
01647     operator+=(const Array2D<Type2>& arg)
01648     {
01649       if(m_size != arg.size()) {
01650         std::ostringstream message;
01651         message << "Mismatched array sizes. Argument array is "
01652                 << arg.rows() << " x " << arg.columns()
01653                 << ", while destination array is "
01654                 << m_rows << " x " << m_columns << ".";
01655         DLR_THROW(ValueException, "Array2D::operator+=()",
01656                   message.str().c_str());
01657       }
01658       std::transform(m_dataPtr, m_dataPtr + m_size, arg.data(), m_dataPtr,
01659                      std::plus<Type>());
01660       return *this;
01661     }
01662 
01663 
01664     template <class Type> template <class Type2>
01665     Array2D<Type>&
01666     Array2D<Type>::
01667     operator-=(const Array2D<Type2>& arg)
01668     {
01669       if(m_size != arg.size()) {
01670         std::ostringstream message;
01671         message << "Mismatched array sizes. Argument array is "
01672                 << arg.rows() << " x " << arg.columns()
01673                 << ", while destination array is "
01674                 << m_rows << " x " << m_columns << ".";
01675         DLR_THROW(ValueException, "Array2D::operator-=()",
01676                   message.str().c_str());
01677       }
01678       std::transform(m_dataPtr, m_dataPtr + m_size, arg.data(), m_dataPtr,
01679                      std::minus<Type>());
01680       return *this;
01681     }
01682 
01683 
01684     template <class Type> template <class Type2>
01685     Array2D<Type>&
01686     Array2D<Type>::
01687     operator*=(const Array2D<Type2>& arg)
01688     {
01689       if(m_size != arg.size()) {
01690         std::ostringstream message;
01691         message << "Mismatched array sizes. Argument array is "
01692                 << arg.rows() << " x " << arg.columns()
01693                 << ", while destination array is "
01694                 << m_rows << " x " << m_columns << ".";
01695         DLR_THROW(ValueException, "Array2D::operator*=()",
01696                   message.str().c_str());
01697       }
01698       std::transform(m_dataPtr, m_dataPtr + m_size, arg.data(), m_dataPtr,
01699                      std::multiplies<Type>());
01700       return *this;
01701     }
01702 
01703 
01704     template <class Type> template <class Type2>
01705     Array2D<Type>&
01706     Array2D<Type>::
01707     operator/=(const Array2D<Type2>& arg)
01708     {
01709       if(m_size != arg.size()) {
01710         std::ostringstream message;
01711         message << "Mismatched array sizes. Argument array is "
01712                 << arg.rows() << " x " << arg.columns()
01713                 << ", while destination array is "
01714                 << m_rows << " x " << m_columns << ".";
01715         DLR_THROW(ValueException, "Array2D::operator/=()",
01716                   message.str().c_str());
01717       }
01718       std::transform(m_dataPtr, m_dataPtr + m_size, arg.data(), m_dataPtr,
01719                      std::divides<Type>());
01720       return *this;
01721     }
01722 
01723 
01724     template <class Type>
01725     Array2D<Type>&
01726     Array2D<Type>::
01727     operator*=(Type arg)
01728     {
01729       std::transform(m_dataPtr, m_dataPtr + m_size, m_dataPtr,
01730                      std::bind2nd(std::multiplies<Type>(), arg));
01731       return *this;
01732     }
01733 
01734 
01735     template <class Type>
01736     Array2D<Type>&
01737     Array2D<Type>::
01738     operator/=(Type arg)
01739     {
01740       std::transform(m_dataPtr, m_dataPtr + m_size, m_dataPtr,
01741                      std::bind2nd(std::divides<Type>(), arg));
01742       return *this;
01743     }
01744 
01745 
01746     template <class Type>
01747     Array2D<Type>&
01748     Array2D<Type>::
01749     operator+=(Type arg)
01750     {
01751       std::transform(m_dataPtr, m_dataPtr + m_size, m_dataPtr,
01752                      std::bind2nd(std::plus<Type>(), arg));
01753       return *this;
01754     }
01755 
01756 
01757     template <class Type>
01758     Array2D<Type>&
01759     Array2D<Type>::
01760     operator-=(Type arg)
01761     {
01762       std::transform(m_dataPtr, m_dataPtr + m_size, m_dataPtr,
01763                      std::bind2nd(std::minus<Type>(), arg));
01764       return *this;
01765     }
01766 
01767 
01768     template <class Type>
01769     Array2D<Type> Array2D<Type>::
01770     transpose() const
01771     {
01772       Array2D<Type> newMx(m_columns, m_rows);
01773 
01774       // Waiting for row & column iterators
01775       Type *tPtr0 = newMx.m_dataPtr;
01776       for(size_t j = 0; j < m_columns; ++j) {
01777         // const Type *tPtr1 = this->data(0, j);
01778         const Type *tPtr1 = this->data(j);
01779         for(size_t i = 0; i < m_rows; ++i) {
01780           *tPtr0 = *tPtr1;
01781           ++tPtr0;
01782           tPtr1 += m_columns;
01783         }
01784       }
01785       return newMx;
01786     }
01787 
01788 
01789     template <class Type>
01790     void Array2D<Type>::
01791     allocate()
01792     {
01793       m_size = m_rows * m_columns;
01794       if(m_rows > 0 && m_columns > 0) {
01795         m_dataPtr = new(Type[m_rows * m_columns]); // should throw an exception
01796         m_refCountPtr = new size_t;                 // if we're out of memory.
01797         *m_refCountPtr = 1;
01798         m_isAllocated = true;
01799         return;
01800       }
01801       m_dataPtr = 0;
01802       m_refCountPtr = 0;
01803       m_isAllocated = false;
01804       return;
01805     }
01806 
01807 
01808     template <class Type>
01809     inline void Array2D<Type>::
01810     checkBounds(size_t index) const
01811     {
01812 #ifdef _DLRNUMERIC_CHECKBOUNDS_
01813       if(index < 0 || index >= m_size) {
01814         std::ostringstream message;
01815         message << "Index " << index << " is invalid for a(n) " << m_rows
01816                 << " x " << m_columns << " array.";
01817         DLR_THROW(IndexException, "Array2D::checkBounds(size_t)",
01818                   message.str().c_str());
01819       }
01820 #endif
01821     }
01822 
01823 
01824     template <class Type>
01825     inline void Array2D<Type>::
01826     checkBounds(size_t row, size_t column) const
01827     {
01828 #ifdef _DLRNUMERIC_CHECKBOUNDS_
01829       if(row < 0 || row >= m_rows) {
01830         std::ostringstream message;
01831         message << "Row index " << row << " is invalid for a(n) "
01832                 << m_rows << " x " << m_columns << " array.";
01833         DLR_THROW(IndexException, "Array2D::checkBounds(size_t, size_t)",
01834                   message.str().c_str());
01835       }
01836       if(column < 0 || column >= m_columns) {
01837         std::ostringstream message;
01838         message << "Column index " << column << " is invalid for a(n) "
01839                 << m_rows << " x " << m_columns << " array.";
01840         DLR_THROW(IndexException, "Array2D::checkBounds(size_t, size_t)",
01841                   message.str().c_str());
01842       }
01843 #endif
01844     }
01845 
01846 
01847     template <class Type>
01848     void Array2D<Type>::
01849     deAllocate()
01850     {
01851       if(m_isAllocated == true) {
01852         if(--(*m_refCountPtr) == 0) {
01853           delete[] m_dataPtr;
01854           delete m_refCountPtr;
01855           m_isAllocated = false;
01856           m_dataPtr = 0;
01857           m_refCountPtr = 0;
01858         }
01859       } else {
01860         m_dataPtr = 0;
01861         m_refCountPtr = 0;
01862       }
01863     }
01864 
01865     /* Non-member functions which will ultimately wind up in a different file */
01866 
01867     template <class Type>
01868     inline Array2D<Type>
01869     sqrt(const Array2D<Type>& array0)
01870     {
01871       return squareRoot(array0);
01872     }
01873 
01874     // This function returns an Array2D instance of the same shape and
01875     // element type as its input, in which each element contains the
01876     // square root of the corresponding element of the input array.
01877     template <class Type>
01878     Array2D<Type>
01879     squareRoot(const Array2D<Type>& array0)
01880     {
01881       Array2D<Type> result(array0.rows(), array0.columns());
01882       std::transform(array0.begin(), array0.end(),
01883                      result.begin(), SquareRootFunctor<Type>());
01884       return result;
01885     }
01886 
01887     template <class Type>
01888     Array2D<Type> operator+(const Array2D<Type>& array0,
01889                             const Array2D<Type>& array1)
01890     {
01891       if((array0.rows() != array1.rows())
01892          || (array0.columns() != array1.columns())) {
01893         std::ostringstream message;
01894         message << "Array sizes do not match.  Array0 is " << array0.rows()
01895                 << " x " << array0.columns() << ", while array1 is "
01896                 << array1.rows() << " x " << array1.columns() << ".";
01897         DLR_THROW(ValueException, "Array2D::operator+()", message.str().c_str());
01898       }
01899       Array2D<Type> result(array0.rows(), array0.columns());
01900       std::transform(array0.begin(), array0.end(), array1.begin(),
01901                      result.begin(), std::plus<Type>());
01902       return result;
01903     }
01904 
01905     template <class Type>
01906     Array2D<Type> operator-(const Array2D<Type>& array0,
01907                             const Array2D<Type>& array1)
01908     {
01909       if((array0.rows() != array1.rows())
01910          || (array0.columns() != array1.columns())) {
01911         std::ostringstream message;
01912         message << "Array sizes do not match.  Array0 is " << array0.rows()
01913                 << " x " << array0.columns() << ", while array1 is "
01914                 << array1.rows() << " x " << array1.columns() << ".";
01915         DLR_THROW(ValueException, "Array2D::operator-()", message.str().c_str());
01916       }
01917       Array2D<Type> result(array0.rows(), array0.columns());
01918       std::transform(array0.begin(), array0.end(), array1.begin(),
01919                      result.begin(), std::minus<Type>());
01920       return result;
01921     }
01922 
01923     template <class Type>
01924     Array2D<Type> operator*(const Array2D<Type>& array0,
01925                             const Array2D<Type>& array1)
01926     {
01927       if((array0.rows() != array1.rows())
01928          || (array0.columns() != array1.columns())) {
01929         std::ostringstream message;
01930         message << "Array sizes do not match.  Array0 is " << array0.rows()
01931                 << " x " << array0.columns() << ", while array1 is "
01932                 << array1.rows() << " x " << array1.columns() << ".";
01933         DLR_THROW(ValueException, "Array2D::operator*()", message.str().c_str());
01934       }
01935       Array2D<Type> result(array0.rows(), array0.columns());
01936       std::transform(array0.begin(), array0.end(), array1.begin(),
01937                      result.begin(), std::multiplies<Type>());
01938       return result;
01939     }
01940 
01941     template <class Type>
01942     Array2D<Type> operator/(const Array2D<Type>& array0,
01943                             const Array2D<Type>& array1)
01944     {
01945       if((array0.rows() != array1.rows())
01946          || (array0.columns() != array1.columns())) {
01947         std::ostringstream message;
01948         message << "Array sizes do not match.  Array0 is " << array0.rows()
01949                 << " x " << array0.columns() << ", while array1 is "
01950                 << array1.rows() << " x " << array1.columns() << ".";
01951         DLR_THROW(ValueException, "Array2D::operator/()", message.str().c_str());
01952       }
01953       Array2D<Type> result(array0.rows(), array0.columns());
01954       std::transform(array0.begin(), array0.end(), array1.begin(),
01955                      result.begin(), std::divides<Type>());
01956       return result;
01957     }
01958 
01959     template <class Type>
01960     Array2D<Type> operator+(const Array2D<Type>& array0, Type scalar)
01961     {
01962       Array2D<Type> result(array0.rows(), array0.columns());
01963       std::transform(array0.begin(), array0.end(), result.begin(),
01964                      std::bind2nd(std::plus<Type>(), scalar));
01965       return result;
01966     }
01967 
01968     template <class Type>
01969     Array2D<Type> operator-(const Array2D<Type>& array0, Type scalar)
01970     {
01971       Array2D<Type> result(array0.rows(), array0.columns());
01972       std::transform(array0.begin(), array0.end(), result.begin(),
01973                      std::bind2nd(std::minus<Type>(), scalar));
01974       return result;
01975     }
01976 
01977     template <class Type>
01978     Array2D<Type> operator*(const Array2D<Type>& array0, Type scalar)
01979     {
01980       Array2D<Type> result(array0.rows(), array0.columns());
01981       std::transform(array0.begin(), array0.end(), result.begin(),
01982                      std::bind2nd(std::multiplies<Type>(), scalar));
01983       return result;
01984     }
01985 
01986     template <class Type>
01987     Array2D<Type> operator/(const Array2D<Type>& array0, Type scalar)
01988     {
01989       Array2D<Type> result(array0.rows(), array0.columns());
01990       std::transform(array0.begin(), array0.end(), result.begin(),
01991                      std::bind2nd(std::divides<Type>(), scalar));
01992       return result;
01993     }
01994 
01995     template <class Type>
01996     inline Array2D<Type> operator+(Type scalar, const Array2D<Type>& array0)
01997     {
01998       return array0 + scalar;
01999     }
02000 
02001     template <class Type>
02002     inline Array2D<Type> operator*(Type scalar, const Array2D<Type>& array0)
02003     {
02004       return array0 * scalar;
02005     }
02006 
02007 
02008     // Elementwise comparison of an Array2D with a constant.
02009     template <class Type>
02010     Array2D<bool>
02011     operator==(const Array2D<Type>& array0, const Type arg)
02012     {
02013       Array2D<bool> result(array0.rows(), array0.columns());
02014       std::transform(array0.begin(), array0.end(), result.data(),
02015                      std::bind2nd(std::equal_to<Type>(), arg));
02016       return result;
02017     }
02018 
02019     
02020     // Elementwise comparison of an Array2D with another array.
02021     template <class Type>
02022     Array2D<bool>
02023     operator==(const Array2D<Type>& array0, const Array2D<Type>& array1)
02024     {
02025       array0.checkDimension(array1.rows(), array1.columns());
02026       Array2D<bool> result(array0.rows(), array0.columns());
02027       std::transform(array0.begin(), array0.end(), array1.begin(),
02028                      result.begin(), std::equal_to<Type>());
02029       return result;
02030     }
02031 
02032   
02033     template <class Type>
02034     Array2D<bool> operator>(const Array2D<Type>& array0, Type arg)
02035     {
02036       Array2D<bool> result(array0.rows(), array0.columns());
02037       std::transform(array0.begin(), array0.end(), result.begin(),
02038                      std::bind2nd(std::greater<Type>(), arg));
02039       return result;
02040     }
02041 
02042     template <class Type>
02043     Array2D<bool> operator<(const Array2D<Type>& array0, Type arg)
02044     {
02045       Array2D<bool> result(array0.rows(), array0.columns());
02046       std::transform(array0.begin(), array0.end(), result.begin(),
02047                      std::bind2nd(std::less<Type>(), arg));
02048       return result;
02049     }
02050 
02051     template <class Type>
02052     Array2D<bool> operator>=(const Array2D<Type>& array0, Type arg)
02053     {
02054       Array2D<bool> result(array0.rows(), array0.columns());
02055       std::transform(array0.begin(), array0.end(), result.begin(),
02056                      std::bind2nd(std::greater_equal<Type>(), arg));
02057       return result;
02058     }
02059 
02060     template <class Type>
02061     Array2D<bool> operator<=(const Array2D<Type>& array0, Type arg)
02062     {
02063       Array2D<bool> result(array0.rows(), array0.columns());
02064       std::transform(array0.begin(), array0.end(), result.begin(),
02065                      std::bind2nd(std::less_equal<Type>(), arg));
02066       return result;
02067     }
02068 
02069     template <class Type>
02070     std::ostream& operator<<(std::ostream& stream, const Array2D<Type>& array0)
02071     {
02072       // Most of the time, OutputType will be the same as Type.
02073       typedef typename NumericTraits<Type>::TextOutputType OutputType;
02074 
02075       stream << "Array2D([[";
02076       for(size_t row = 0; row < array0.rows(); ++row) {
02077         if (array0.columns() > 0) {
02078           for(size_t column = 0; column < array0.columns() - 1; ++column) {
02079             stream << static_cast<OutputType>(array0(row, column)) << ", ";
02080           }
02081           stream << static_cast<OutputType>(array0(row, array0.columns() - 1));
02082           if(row != array0.rows() - 1) {
02083             stream << "],\n";
02084             stream << "         [";
02085           }
02086         }
02087       } 
02088       stream << "]])";
02089       stream.flush();
02090       return stream;
02091     }
02092 
02093   
02094     template <class Type>
02095     std::istream& operator>>(std::istream& inputStream, Array2D<Type>& array0)
02096     {
02097       return array0.readFromStream(inputStream);
02098     }
02099   
02100   } // namespace numeric
02101 
02102 } // namespace dlr
02103 
02104 #endif // #ifdef _DLR_ARRAY2D_H_

Generated on Mon Jul 9 20:34:02 2007 for dlrLibs Utility Libraries by  doxygen 1.5.2