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 
00080 
00090       Array2D(size_t arrayRows, size_t arrayColumns);
00091 
00092 
00106       explicit
00107       Array2D(const std::string& inputString);
00108 
00115       Array2D(const Array2D<Type> &source);
00116 
00132       Array2D(size_t arrayRows, size_t arrayColumns, Type* const dataPtr);
00133 
00134 
00156       Array2D(size_t arrayRows, size_t arrayColumns, Type* const dataPtr,
00157               size_t* referenceCountPtr);
00158     
00163       virtual
00164       ~Array2D();
00165 
00171       iterator
00172       begin() {return m_dataPtr;}
00173 
00180       const_iterator
00181       begin() const {return m_dataPtr;}
00182 
00187       void
00188       clear() {this->reinit(0, 0);}
00189 
00197       size_t
00198       columns() const {return m_columns;}
00199 
00200 
00209       inline void 
00210       checkDimension(size_t arrayRows, size_t arrayColumns) const;
00211 
00212     
00218       Array2D<Type>
00219       copy() const;
00220 
00231       template <class Type2> void
00232       copy(const Array2D<Type2>& source);
00233 
00240       template <class Type2> void
00241       copy(const Type2* dataPtr);
00242 
00252       Type*
00253       data() {return m_dataPtr;}
00254 
00261       const Type*
00262       data() const {return m_dataPtr;}
00263 
00274       Type*
00275       data(size_t index) {
00276         this->checkBounds(index);
00277         return m_dataPtr + index;
00278       }
00279 
00289       const Type*
00290       data(size_t index) const {
00291         this->checkBounds(index);
00292         return m_dataPtr+index;
00293       }
00294 
00307       Type*
00308       data(size_t rowIndex, size_t columnIndex) {
00309         this->checkBounds(rowIndex, columnIndex);
00310         return m_dataPtr + columnIndex + (rowIndex * m_columns);
00311       }
00312 
00324       const Type*
00325       data(size_t rowIndex, size_t columnIndex) const {
00326         this->checkBounds(rowIndex, columnIndex);
00327         return m_dataPtr + columnIndex + (rowIndex * m_columns);
00328       }
00329 
00330     
00338       bool
00339       empty() const {return this->size() == 0;}
00340 
00341     
00348       iterator
00349       end() {return m_dataPtr + m_size;}
00350 
00351       
00358       const_iterator
00359       end() const {return m_dataPtr + m_size;}
00360 
00361     
00371       inline Type
00372       getElement(size_t index0) const {return this->operator()(index0);}
00373 
00374 
00387       Type
00388       getElement(size_t rowIndex, size_t columnIndex) const {
00389         return this->operator()(rowIndex, columnIndex);
00390       }        
00391 
00392 
00403       Array1D<Type>
00404       getRow(size_t index);
00405 
00416       const Array1D<Type>
00417       getRow(size_t index) const;
00418 
00419       
00428       bool
00429       isAllocated() const {return m_isAllocated;}
00430     
00431     
00439       Array1D<Type>
00440       ravel();
00441 
00449       const Array1D<Type>
00450       ravel() const;
00451 
00464       std::istream&
00465       readFromStream(std::istream& inputStream);
00466     
00467 
00475       size_t*
00476       refCountPtr() const {return m_refCountPtr;}
00477 
00478     
00488       void
00489       reinit(size_t arrayRows, size_t arrayColumns);
00490 
00491       
00503       inline void
00504       reinitIfNecessary(size_t arrayRows, size_t arrayColumns);
00505 
00506 
00521       void
00522       reshape(int arrayRows, int arrayColumns);
00523 
00524       
00532       inline Array1D<Type>
00533       row(size_t index) {return this->getRow(index);}
00534 
00535       
00543       const Array1D<Type>
00544       row(size_t index) const {return this->getRow(index);}
00545 
00546       
00557       iterator
00558       rowBegin(size_t rowIndex) {return m_dataPtr + rowIndex * m_columns;}
00559 
00560       
00571       const_iterator
00572       rowBegin(size_t rowIndex) const {
00573         return m_dataPtr + rowIndex * m_columns;
00574       }
00575 
00576       
00587       iterator
00588       rowEnd(size_t rowIndex) {
00589         return m_dataPtr + (rowIndex + 1) * m_columns;
00590       }
00591 
00592 
00603       const_iterator
00604       rowEnd(size_t rowIndex) const {
00605         return m_dataPtr + (rowIndex + 1) * m_columns;
00606       }
00607 
00608       
00616       size_t
00617       rows() const {return m_rows;}
00618 
00619 
00633       Type&
00634       setElement(size_t index0, const Type& value) {
00635         return this->operator()(index0) = value;
00636       }
00637 
00638 
00655       Type&
00656       setElement(size_t rowIndex, size_t columnIndex, const Type& value) {
00657         return this->operator()(rowIndex, columnIndex) = value;
00658       }
00659 
00660 
00669       Array1D<size_t>
00670       shape() const;
00671 
00683       size_t
00684       shape(size_t axis) const;
00685 
00692       size_t
00693       size() const {return m_size;}
00694 
00701       Array2D<Type>
00702       transpose() const;
00703     
00712       Array2D<Type>&
00713       operator=(const Array2D<Type>& source);
00714 
00722       Array2D<Type>&
00723       operator=(Type value);
00724 
00733       Type&
00734       operator()(size_t index) {
00735         this->checkBounds(index);
00736         return m_dataPtr[index];
00737       }
00738 
00745       Type operator()(size_t index) const {
00746         this->checkBounds(index);
00747         return m_dataPtr[index];
00748       }
00749   
00759       Type&
00760       operator()(size_t rowIndex, size_t columnIndex) {
00761         this->checkBounds(rowIndex, columnIndex);
00762         return m_dataPtr[columnIndex + rowIndex * m_columns];
00763       }
00764     
00774       Type
00775       operator()(size_t rowIndex, size_t columnIndex) const {
00776         this->checkBounds(rowIndex, columnIndex);
00777         return m_dataPtr[columnIndex + rowIndex * m_columns];
00778       }
00779 
00788       Type&
00789       operator[](size_t index) {return this->operator()(index);}
00790   
00799       Type
00800       operator[](size_t index) const {return this->operator()(index);}
00801 
00813       template <class Type2> Array2D<Type>&
00814       operator+=(const Array2D<Type2>& arg);
00815       
00827       template <class Type2> Array2D<Type>&
00828       operator-=(const Array2D<Type2>& arg);
00829 
00841       template <class Type2> Array2D<Type>&
00842       operator*=(const Array2D<Type2>& arg);
00843 
00855       template <class Type2> Array2D<Type>&
00856       operator/=(const Array2D<Type2>& arg);
00857     
00865       Array2D<Type>&
00866       operator+=(Type arg);
00867 
00875       Array2D<Type>&
00876       operator-=(Type arg);
00877 
00885       Array2D<Type>&
00886       operator*=(Type arg);
00887 
00895       Array2D<Type>&
00896       operator/=(Type arg);
00897 
00898     private:
00899       /* ******** Private member functions ******** */
00900       void
00901       allocate();
00902     
00903       // Optionally throw an exception if index is beyond the range of
00904       // this array.
00905       inline void
00906       checkBounds(size_t index) const;
00907 
00908       // Optionally throw an exception if either index is beyond the
00909       // range of this array.
00910       inline void
00911       checkBounds(size_t row, size_t column) const;
00912 
00913       void
00914       deAllocate();
00915 
00916       // Constants to help with formatting.  We use the initialization
00917       // on first use paradigm for the string constants to avoid
00918       // headaches.
00919 
00924       static const std::string& ioIntro(); 
00925 
00930       static const std::string& ioOutro();
00931 
00936       static const char ioOpening = '[';
00937 
00942       static const char ioClosing = ']';
00943 
00948       static const char ioSeparator = ',';
00949 
00950     
00951       /* ********Private data members******** */
00952       size_t m_rows;
00953       size_t m_columns;
00954       size_t m_size;
00955       Type* m_dataPtr;
00956       size_t* m_refCountPtr;
00957       bool m_isAllocated;
00958     
00959     };
00960   
00961     /* Non-member functions which will ultimately wind up in a different file */
00962 
00973     template <class Type>
00974     Array2D<Type>
00975     squareRoot(const Array2D<Type>& array0);
00976   
00988     template <class Type>
00989     inline Array2D<Type>
00990     sqrt(const Array2D<Type>& array0);
00991 
01005     template <class Type>
01006     Array2D<Type>
01007     operator+(const Array2D<Type>& array0,
01008               const Array2D<Type>& array1);
01009   
01023     template <class Type>
01024     Array2D<Type>
01025     operator-(const Array2D<Type>& array0,
01026               const Array2D<Type>& array1);
01027   
01041     template <class Type>
01042     Array2D<Type>
01043     operator*(const Array2D<Type>& array0,
01044               const Array2D<Type>& array1);
01045   
01059     template <class Type>
01060     Array2D<Type>
01061     operator/(const Array2D<Type>& array0,
01062               const Array2D<Type>& array1);
01063   
01075     template <class Type>
01076     Array2D<Type>
01077     operator+(const Array2D<Type>& array0, Type scalar);
01078   
01090     template <class Type>
01091     Array2D<Type>
01092     operator-(const Array2D<Type>& array0, Type scalar);
01093   
01105     template <class Type>
01106     Array2D<Type>
01107     operator*(const Array2D<Type>& array0, Type scalar);
01108   
01120     template <class Type>
01121     Array2D<Type>
01122     operator/(const Array2D<Type>& array0, Type scalar);
01123 
01135     template <class Type>
01136     inline Array2D<Type>
01137     operator+(Type scalar, const Array2D<Type>& array0);
01138   
01139 
01151     template <class Type>
01152     inline Array2D<Type>
01153     operator*(Type scalar, const Array2D<Type>& array0);
01154 
01155 
01167     template <class Type>
01168     Array2D<bool>
01169     operator==(const Array2D<Type>& array0, const Type arg);
01170 
01171     
01184     template <class Type>
01185     Array2D<bool>
01186     operator==(const Array2D<Type>& array0, const Array2D<Type>& array1);
01187     
01188 
01200     template <class Type>
01201     Array2D<bool>
01202     operator>(const Array2D<Type>& array0, Type arg);
01203 
01204   
01216     template <class Type>
01217     Array2D<bool>
01218     operator<(const Array2D<Type>& array0, Type arg);
01219 
01220   
01233     template <class Type>
01234     Array2D<bool>
01235     operator>=(const Array2D<Type>& array0, Type arg);
01236 
01237   
01250     template <class Type>
01251     Array2D<bool>
01252     operator<=(const Array2D<Type>& array0, Type arg);
01253 
01254   
01273     template <class Type>
01274     std::ostream&
01275     operator<<(std::ostream& stream, const Array2D<Type>& array0);
01276 
01288     template <class Type>
01289     std::istream&
01290     operator>>(std::istream& stream, Array2D<Type>& array0);
01291   
01292   } // namespace numeric
01293 
01294 } // namespace dlr
01295 
01296 
01297 /* ======= Declarations to maintain compatibility with legacy code. ======= */
01298 
01299 namespace dlr {
01300 
01301   using numeric::Array2D;
01302 
01303 } // namespace dlr
01304 
01305 
01306 /*******************************************************************
01307  * Member function definitions follow.  This would be a .C file
01308  * if it weren't templated.
01309  *******************************************************************/
01310 
01311 #include <algorithm>
01312 #include <functional>
01313 #include <sstream>
01314 #include <vector>
01315 #include <dlrCommon/functional.h>
01316 #include <dlrCommon/inputStream.h>
01317 #include <dlrNumeric/numericTraits.h>
01318 #include <dlrNumeric/functional.h>
01319 
01320 namespace dlr {
01321 
01322   namespace numeric {
01323     
01324     // Static constant describing how the string representation of an
01325     // Array2D should start.
01326     template <class Type>
01327     const std::string&
01328     Array2D<Type>::
01329     ioIntro()
01330     {
01331       static const std::string intro = "Array2D(";
01332       return intro;
01333     }
01334 
01335     // Static constant describing how the string representation of an
01336     // Array2D should end.
01337     template <class Type>
01338     const std::string&
01339     Array2D<Type>::
01340     ioOutro()
01341     {
01342       static const std::string outro = ")";
01343       return outro;
01344     }
01345 
01346     // Non-static member functions below.
01347 
01348     template <class Type>
01349     Array2D<Type>::
01350     Array2D()
01351       : m_rows(0),
01352         m_columns(0),
01353         m_size(0),
01354         m_dataPtr(0),
01355         m_refCountPtr(0),
01356         m_isAllocated(false)
01357     {
01358       // Empty
01359     }
01360 
01361 
01362     template <class Type>
01363     Array2D<Type>::
01364     Array2D(size_t arrayRows, size_t arrayColumns)
01365       : m_rows(arrayRows),
01366         m_columns(arrayColumns),
01367         m_size(0),          // This will be set in the call to allocate().
01368         m_dataPtr(0),       // This will be set in the call to allocate().
01369         m_refCountPtr(0),   // This will be set in the call to allocate().
01370         m_isAllocated(false)
01371     {
01372       this->allocate();
01373     }
01374 
01375   
01376     // Construct from an initialization string.
01377     template <class Type>
01378     Array2D<Type>::
01379     Array2D(const std::string& inputString)
01380       : m_rows(0),
01381         m_columns(0),
01382         m_size(0),
01383         m_dataPtr(0),
01384         m_refCountPtr(0),
01385         m_isAllocated(false)
01386     {
01387       // We'll use the stream input operator to parse the string.
01388       std::istringstream inputStream(inputString);
01389 
01390       // Now read the string into an array.
01391       Array2D<Type> inputArray;
01392       inputStream >> inputArray;
01393       if(!inputStream) {
01394         std::ostringstream message;
01395         message << "Couldn't parse input string: \"" << inputString << "\".";
01396         DLR_THROW3(ValueException, "Array2D::Array2D(const std::string&)",
01397                    message.str().c_str());                 
01398       }
01399 
01400       // If all went well, copy into *this.
01401       *this = inputArray;
01402     }
01403 
01404 
01405     /* When copying from a Array2D do a shallow copy */
01406     /* Update reference count if the array we're copying has */
01407     /* valid data. */
01408     template <class Type>
01409     Array2D<Type>::
01410     Array2D(const Array2D<Type>& source)
01411       : m_rows(source.m_rows),
01412         m_columns(source.m_columns),
01413         m_size(source.m_size),
01414         m_dataPtr(source.m_dataPtr),
01415         m_refCountPtr(source.m_refCountPtr),
01416         m_isAllocated(source.m_isAllocated)
01417     {
01418       if(m_isAllocated) {
01419         ++(*m_refCountPtr);
01420       }
01421     }
01422 
01423   
01424     /* Here's a constructor for getting image data into the array */
01425     /* cheaply. */
01426     template <class Type>
01427     Array2D<Type>::
01428     Array2D(size_t arrayRows, size_t arrayColumns, Type* const dataPtr)
01429       : m_rows(arrayRows),
01430         m_columns(arrayColumns),
01431         m_size(arrayRows*arrayColumns),
01432         m_dataPtr(dataPtr),
01433         m_refCountPtr(0),
01434         m_isAllocated(false)
01435     {
01436       // Empty
01437     }
01438 
01439   
01440     // Construct an array around external data which was allocated by
01441     // an Array?D instance.
01442     template <class Type>
01443     Array2D<Type>::
01444     Array2D(size_t arrayRows, size_t arrayColumns, Type* const dataPtr,
01445             size_t* referenceCountPtr)
01446       : m_rows(arrayRows),
01447         m_columns(arrayColumns),
01448         m_size(arrayRows*arrayColumns),
01449         m_dataPtr(dataPtr),
01450         m_refCountPtr(referenceCountPtr),
01451         m_isAllocated(true)
01452     {
01453       ++(*m_refCountPtr);
01454     }
01455 
01456   
01457     template <class Type>
01458     Array2D<Type>::
01459     ~Array2D()
01460     {
01461       deAllocate();
01462     }
01463 
01464   
01465     template <class Type>
01466     inline void Array2D<Type>::
01467     checkDimension(size_t arrayRows, size_t arrayColumns) const
01468     {
01469 #ifdef _DLRNUMERIC_CHECKBOUNDS_
01470       if(arrayRows != this->rows()
01471          || arrayColumns != this->columns()) {
01472         std::ostringstream message;
01473         message << "Size mismatch: required dimension is ("
01474                 << arrayRows << ", " << arrayColumns << ") "
01475                 << " while *this has dimension "
01476                 << this->rows() << ", " << this->columns() << ").";
01477         DLR_THROW(IndexException, "Array2D::checkDimension()",
01478                   message.str().c_str());
01479       }
01480 #endif
01481     }
01482 
01483 
01484     template <class Type>
01485     Array2D<Type> Array2D<Type>::
01486     copy() const
01487     {
01488       Array2D<Type> newArray(m_rows, m_columns);
01489       newArray.copy(*this);
01490       return newArray;
01491     }
01492 
01493     
01494     template <class Type> template <class Type2>
01495     void Array2D<Type>::
01496     copy(const Array2D<Type2>& source)
01497     {
01498       if(source.size() != m_size) {
01499         std::ostringstream message;
01500         message << "Mismatched array sizes. Source array has "
01501                 << source.size() << " elements, while destination array has "
01502                 << m_size << " elements.";
01503         DLR_THROW3(ValueException, "Array2D::copy(const Array2D&)",
01504                    message.str().c_str());
01505       }
01506       if(m_size != 0) {
01507         this->copy(source.data());
01508       }
01509     }
01510 
01511 
01512     template <class Type> template <class Type2>
01513     void Array2D<Type>::
01514     copy(const Type2* dataPtr)
01515     {
01516       if(dataPtr == 0) {
01517         DLR_THROW(ValueException, "Array2D::copy(const Type2*)",
01518                   "Argument is a NULL pointer.");
01519       }
01520       std::transform(dataPtr, dataPtr + m_size, m_dataPtr,
01521                      StaticCastFunctor<Type2, Type>());
01522     }
01523 
01524 
01525     template <class Type>
01526     Array1D<Type> Array2D<Type>::
01527     getRow(size_t index)
01528     {
01529       this->checkBounds(index, 0);
01530       return Array1D<Type>(this->columns(),
01531                            m_dataPtr + (index * this->m_columns));
01532     }
01533 
01534   
01535     template <class Type>
01536     const Array1D<Type> Array2D<Type>::
01537     getRow(size_t index) const
01538     {
01539       this->checkBounds(index, 0);
01540       return Array1D<Type>(this->columns(),
01541                            m_dataPtr + (index * this->m_columns));
01542     }
01543 
01544 
01545     template <class Type>
01546     const Array1D<Type> Array2D<Type>::
01547     ravel() const
01548     {
01549       if(m_isAllocated) {
01550         return Array1D<Type>(m_size, m_dataPtr, m_refCountPtr);
01551       }
01552       return Array1D<Type>(m_size, m_dataPtr);
01553     }
01554 
01555     template <class Type>
01556     Array1D<Type> Array2D<Type>::
01557     ravel()
01558     {
01559       if(m_isAllocated) {
01560         return Array1D<Type>(m_size, m_dataPtr, m_refCountPtr);
01561       }
01562       return Array1D<Type>(m_size, m_dataPtr);
01563     }
01564 
01565 
01566     template <class Type>
01567     std::istream&
01568     Array2D<Type>::
01569     readFromStream(std::istream& inputStream)
01570     {
01571       // Most of the time, InputType will be the same as Type.
01572       typedef typename NumericTraits<Type>::TextOutputType InputType;
01573 
01574       // If stream is in a bad state, we can't read from it.
01575       if (!inputStream){
01576         return inputStream;
01577       }
01578     
01579       // It's a lot easier to use a try block than to be constantly
01580       // testing whether the IO has succeeded, so we tell inputStream to
01581       // complain if anything goes wrong.
01582       std::ios_base::iostate oldExceptionState = inputStream.exceptions();
01583       inputStream.exceptions(
01584         std::ios_base::badbit | std::ios_base::failbit | std::ios_base::eofbit);
01585 
01586       // Now on with the show.
01587       try{
01588         // Construct an InputStream instance so we can use our
01589         // convenience functions.
01590         InputStream stream(inputStream);
01591 
01592         // Skip any preceding whitespace.
01593         stream.skipWhiteSpace();
01594       
01595         // We won't require the input format to start with "Array2D(", but
01596         // if it does we read it here.
01597         bool foundIntro = false;
01598         if(stream.peek() == ioIntro()[0]) {
01599           foundIntro = true;
01600           stream.expect(ioIntro());
01601         }
01602 
01603         // OK.  We've dispensed with the intro.  What's left should be of
01604         // the format "[row, row, row, ...]".  We require the square
01605         // brackets to be there.
01606         stream.expect(ioOpening);
01607 
01608         // Read the data.  We'll use the Array1D<Type> stream operator to
01609         // read each row.
01610         Array1D<Type> inputValue;
01611         std::vector< Array1D<Type> > inputBuffer;
01612         while(1) {
01613           // Read the next row.
01614           stream >> inputValue;
01615           inputBuffer.push_back(inputValue);
01616 
01617           // Read the separator, or else the closing character.
01618           char inChar = 0;
01619           stream >> inChar;
01620           if(inChar == ioClosing) {
01621             // Found a closing.  Stop here.
01622             break;
01623           }
01624           if(inChar != ioSeparator) {
01625             // Missing separator?  Fail here.
01626             stream.clear(std::ios_base::failbit);
01627           }
01628         }
01629     
01630         // If we found an intro, we expect the corresponding outro.
01631         if(foundIntro) {
01632           stream.expect(ioOutro());
01633         }
01634 
01635         // Now we're done with all of the parsing, verify that all rows
01636         // have the same length.
01637         size_t arrayRows = inputBuffer.size();
01638         size_t arrayColumns = ((inputBuffer.size() != 0) ? inputBuffer[0].size() : 0);
01639         for(size_t index = 1; index < arrayRows; ++index) {
01640           if(inputBuffer[index].size() != arrayColumns) {
01641             // Inconsistent row lengths!  Fail here.
01642             stream.clear(std::ios_base::failbit);
01643           }
01644         }
01645 
01646         // And finally, copy the data.
01647         this->reinit(arrayRows, arrayColumns);
01648         for(size_t index = 0; index < arrayRows; ++index) {
01649           std::copy(inputBuffer[index].begin(), inputBuffer[index].end(),
01650                     this->begin() + (index * arrayColumns));
01651         }
01652       } catch(std::ios_base::failure) {
01653         // Empty
01654       }
01655       inputStream.exceptions(oldExceptionState);
01656       return inputStream;
01657     }
01658   
01659 
01660     template <class Type>
01661     void Array2D<Type>::
01662     reinit(size_t arrayRows, size_t arrayColumns)
01663     {
01664       this->deAllocate();
01665       this->m_rows = arrayRows;
01666       this->m_columns = arrayColumns;
01667       this->allocate();
01668     }
01669 
01670 
01671     template <class Type>
01672     void Array2D<Type>::
01673     reinitIfNecessary(size_t arrayRows, size_t arrayColumns)
01674     {
01675       if(this->size() != arrayRows * arrayColumns) {
01676         this->reinit(arrayRows, arrayColumns);
01677       } else {
01678         if(this->rows() != arrayRows) {
01679           this->reshape(arrayRows, arrayColumns);
01680         }
01681       }
01682     }
01683 
01684 
01685     /* After reshaping, matrix is still row major order */
01686     template <class Type>
01687     void Array2D<Type>::
01688     reshape(int arrayRows, int arrayColumns)
01689     {
01690       // If one axis is specified as -1, it will be automatically 
01691       // chosen to match the number of elements in the array.
01692       if((arrayRows == -1) && (arrayColumns != 0)) {
01693         arrayRows = static_cast<int>(this->size()) / arrayColumns;
01694       } else
01695         if((arrayColumns == -1) && (arrayRows != 0)) {
01696           arrayColumns = static_cast<int>(this->size()) / arrayRows;
01697         }
01698       if((arrayRows * arrayColumns) != static_cast<int>(this->size())) {
01699         std::ostringstream message;
01700         message << "Can't reshape a(n) " << this->size()
01701                 << " element array to have " << arrayRows << " rows and "
01702                 << arrayColumns << " columns.";
01703         DLR_THROW(ValueException, "Array2D::reshape()", message.str().c_str());
01704       }
01705       m_rows = arrayRows;
01706       m_columns = arrayColumns;
01707     }
01708 
01709   
01710     template <class Type>
01711     Array1D<size_t> Array2D<Type>::
01712     shape() const
01713     {
01714       Array1D<size_t> rc(2);
01715       rc(0) = this->rows();
01716       rc(1) = this->columns();
01717       return rc;
01718     }
01719 
01720 
01721     template <class Type>
01722     size_t Array2D<Type>::
01723     shape(size_t axis) const
01724     {
01725       size_t result;
01726       switch(axis) {
01727       case 0:
01728         result = this->rows();
01729         break;
01730       case 1:
01731         result = this->columns();
01732         break;
01733       default:
01734         std::ostringstream message;
01735         message << "Invalid Axis: "<< axis << ".";
01736         DLR_THROW(ValueException, "Array2D::shape(size_t)",
01737                   message.str().c_str());
01738         result = 0;
01739         break;
01740       }
01741       return result;
01742     }
01743 
01744 
01745     template <class Type>
01746     Array2D<Type>& Array2D<Type>::
01747     operator=(Type value)
01748     {
01749       std::fill(m_dataPtr, m_dataPtr + m_size, value);
01750       return *this;
01751     }
01752 
01753   
01754     template <class Type>
01755     Array2D<Type>& Array2D<Type>::
01756     operator=(const Array2D<Type>& source)
01757     {
01758       // Check for self-assignment
01759       if(&source != this) {
01760         this->deAllocate();
01761         m_rows = source.m_rows;
01762         m_columns = source.m_columns;
01763         m_size = source.m_size;
01764         m_dataPtr = source.m_dataPtr;
01765         m_refCountPtr = source.m_refCountPtr;
01766         m_isAllocated = source.m_isAllocated;
01767         if(m_isAllocated) {
01768           ++(*m_refCountPtr);
01769         }
01770       }
01771       return *this;
01772     }
01773 
01774 
01775     template <class Type> template <class Type2>
01776     Array2D<Type>&
01777     Array2D<Type>::
01778     operator+=(const Array2D<Type2>& arg)
01779     {
01780       if(m_size != arg.size()) {
01781         std::ostringstream message;
01782         message << "Mismatched array sizes. Argument array is "
01783                 << arg.rows() << " x " << arg.columns()
01784                 << ", while destination array is "
01785                 << m_rows << " x " << m_columns << ".";
01786         DLR_THROW(ValueException, "Array2D::operator+=()",
01787                   message.str().c_str());
01788       }
01789       std::transform(m_dataPtr, m_dataPtr + m_size, arg.data(), m_dataPtr,
01790                      std::plus<Type>());
01791       return *this;
01792     }
01793 
01794 
01795     template <class Type> template <class Type2>
01796     Array2D<Type>&
01797     Array2D<Type>::
01798     operator-=(const Array2D<Type2>& arg)
01799     {
01800       if(m_size != arg.size()) {
01801         std::ostringstream message;
01802         message << "Mismatched array sizes. Argument array is "
01803                 << arg.rows() << " x " << arg.columns()
01804                 << ", while destination array is "
01805                 << m_rows << " x " << m_columns << ".";
01806         DLR_THROW(ValueException, "Array2D::operator-=()",
01807                   message.str().c_str());
01808       }
01809       std::transform(m_dataPtr, m_dataPtr + m_size, arg.data(), m_dataPtr,
01810                      std::minus<Type>());
01811       return *this;
01812     }
01813 
01814 
01815     template <class Type> template <class Type2>
01816     Array2D<Type>&
01817     Array2D<Type>::
01818     operator*=(const Array2D<Type2>& arg)
01819     {
01820       if(m_size != arg.size()) {
01821         std::ostringstream message;
01822         message << "Mismatched array sizes. Argument array is "
01823                 << arg.rows() << " x " << arg.columns()
01824                 << ", while destination array is "
01825                 << m_rows << " x " << m_columns << ".";
01826         DLR_THROW(ValueException, "Array2D::operator*=()",
01827                   message.str().c_str());
01828       }
01829       std::transform(m_dataPtr, m_dataPtr + m_size, arg.data(), m_dataPtr,
01830                      std::multiplies<Type>());
01831       return *this;
01832     }
01833 
01834 
01835     template <class Type> template <class Type2>
01836     Array2D<Type>&
01837     Array2D<Type>::
01838     operator/=(const Array2D<Type2>& arg)
01839     {
01840       if(m_size != arg.size()) {
01841         std::ostringstream message;
01842         message << "Mismatched array sizes. Argument array is "
01843                 << arg.rows() << " x " << arg.columns()
01844                 << ", while destination array is "
01845                 << m_rows << " x " << m_columns << ".";
01846         DLR_THROW(ValueException, "Array2D::operator/=()",
01847                   message.str().c_str());
01848       }
01849       std::transform(m_dataPtr, m_dataPtr + m_size, arg.data(), m_dataPtr,
01850                      std::divides<Type>());
01851       return *this;
01852     }
01853 
01854 
01855     template <class Type>
01856     Array2D<Type>&
01857     Array2D<Type>::
01858     operator*=(Type arg)
01859     {
01860       std::transform(m_dataPtr, m_dataPtr + m_size, m_dataPtr,
01861                      std::bind2nd(std::multiplies<Type>(), arg));
01862       return *this;
01863     }
01864 
01865 
01866     template <class Type>
01867     Array2D<Type>&
01868     Array2D<Type>::
01869     operator/=(Type arg)
01870     {
01871       std::transform(m_dataPtr, m_dataPtr + m_size, m_dataPtr,
01872                      std::bind2nd(std::divides<Type>(), arg));
01873       return *this;
01874     }
01875 
01876 
01877     template <class Type>
01878     Array2D<Type>&
01879     Array2D<Type>::
01880     operator+=(Type arg)
01881     {
01882       std::transform(m_dataPtr, m_dataPtr + m_size, m_dataPtr,
01883                      std::bind2nd(std::plus<Type>(), arg));
01884       return *this;
01885     }
01886 
01887 
01888     template <class Type>
01889     Array2D<Type>&
01890     Array2D<Type>::
01891     operator-=(Type arg)
01892     {
01893       std::transform(m_dataPtr, m_dataPtr + m_size, m_dataPtr,
01894                      std::bind2nd(std::minus<Type>(), arg));
01895       return *this;
01896     }
01897 
01898 
01899     template <class Type>
01900     Array2D<Type> Array2D<Type>::
01901     transpose() const
01902     {
01903       Array2D<Type> newMx(m_columns, m_rows);
01904 
01905       // Waiting for row & column iterators
01906       Type *tPtr0 = newMx.m_dataPtr;
01907       for(size_t j = 0; j < m_columns; ++j) {
01908         // const Type *tPtr1 = this->data(0, j);
01909         const Type *tPtr1 = this->data(j);
01910         for(size_t i = 0; i < m_rows; ++i) {
01911           *tPtr0 = *tPtr1;
01912           ++tPtr0;
01913           tPtr1 += m_columns;
01914         }
01915       }
01916       return newMx;
01917     }
01918 
01919 
01920     template <class Type>
01921     void Array2D<Type>::
01922     allocate()
01923     {
01924       m_size = m_rows * m_columns;
01925       if(m_rows > 0 && m_columns > 0) {
01926         m_dataPtr = new(Type[m_rows * m_columns]); // should throw an exception
01927         m_refCountPtr = new size_t;                 // if we're out of memory.
01928         *m_refCountPtr = 1;
01929         m_isAllocated = true;
01930         return;
01931       }
01932       m_dataPtr = 0;
01933       m_refCountPtr = 0;
01934       m_isAllocated = false;
01935       return;
01936     }
01937 
01938 
01939     template <class Type>
01940     inline void Array2D<Type>::
01941     checkBounds(size_t index) const
01942     {
01943 #ifdef _DLRNUMERIC_CHECKBOUNDS_
01944       if(index >= m_size) {
01945         std::ostringstream message;
01946         message << "Index " << index << " is invalid for a(n) " << m_rows
01947                 << " x " << m_columns << " array.";
01948         DLR_THROW(IndexException, "Array2D::checkBounds(size_t)",
01949                   message.str().c_str());
01950       }
01951 #endif
01952     }
01953 
01954 
01955     template <class Type>
01956     inline void Array2D<Type>::
01957     checkBounds(size_t rowIndex, size_t columnIndex) const
01958     {
01959 #ifdef _DLRNUMERIC_CHECKBOUNDS_
01960       if(rowIndex >= m_rows) {
01961         std::ostringstream message;
01962         message << "Row index " << rowIndex << " is invalid for a(n) "
01963                 << m_rows << " x " << m_columns << " array.";
01964         DLR_THROW(IndexException, "Array2D::checkBounds(size_t, size_t)",
01965                   message.str().c_str());
01966       }
01967       if(columnIndex >= m_columns) {
01968         std::ostringstream message;
01969         message << "Column index " << columnIndex << " is invalid for a(n) "
01970                 << m_rows << " x " << m_columns << " array.";
01971         DLR_THROW(IndexException, "Array2D::checkBounds(size_t, size_t)",
01972                   message.str().c_str());
01973       }
01974 #endif
01975     }
01976 
01977 
01978     template <class Type>
01979     void Array2D<Type>::
01980     deAllocate()
01981     {
01982       if(m_isAllocated == true) {
01983         if(--(*m_refCountPtr) == 0) {
01984           delete[] m_dataPtr;
01985           delete m_refCountPtr;
01986           m_isAllocated = false;
01987           m_dataPtr = 0;
01988           m_refCountPtr = 0;
01989         }
01990       } else {
01991         m_dataPtr = 0;
01992         m_refCountPtr = 0;
01993       }
01994     }
01995 
01996     /* Non-member functions which will ultimately wind up in a different file */
01997 
01998     template <class Type>
01999     inline Array2D<Type>
02000     sqrt(const Array2D<Type>& array0)
02001     {
02002       return squareRoot(array0);
02003     }
02004 
02005     // This function returns an Array2D instance of the same shape and
02006     // element type as its input, in which each element contains the
02007     // square root of the corresponding element of the input array.
02008     template <class Type>
02009     Array2D<Type>
02010     squareRoot(const Array2D<Type>& array0)
02011     {
02012       Array2D<Type> result(array0.rows(), array0.columns());
02013       std::transform(array0.begin(), array0.end(),
02014                      result.begin(), SquareRootFunctor<Type>());
02015       return result;
02016     }
02017 
02018     template <class Type>
02019     Array2D<Type> operator+(const Array2D<Type>& array0,
02020                             const Array2D<Type>& array1)
02021     {
02022       if((array0.rows() != array1.rows())
02023          || (array0.columns() != array1.columns())) {
02024         std::ostringstream message;
02025         message << "Array sizes do not match.  Array0 is " << array0.rows()
02026                 << " x " << array0.columns() << ", while array1 is "
02027                 << array1.rows() << " x " << array1.columns() << ".";
02028         DLR_THROW(ValueException, "Array2D::operator+()", message.str().c_str());
02029       }
02030       Array2D<Type> result(array0.rows(), array0.columns());
02031       std::transform(array0.begin(), array0.end(), array1.begin(),
02032                      result.begin(), std::plus<Type>());
02033       return result;
02034     }
02035 
02036     template <class Type>
02037     Array2D<Type> operator-(const Array2D<Type>& array0,
02038                             const Array2D<Type>& array1)
02039     {
02040       if((array0.rows() != array1.rows())
02041          || (array0.columns() != array1.columns())) {
02042         std::ostringstream message;
02043         message << "Array sizes do not match.  Array0 is " << array0.rows()
02044                 << " x " << array0.columns() << ", while array1 is "
02045                 << array1.rows() << " x " << array1.columns() << ".";
02046         DLR_THROW(ValueException, "Array2D::operator-()", message.str().c_str());
02047       }
02048       Array2D<Type> result(array0.rows(), array0.columns());
02049       std::transform(array0.begin(), array0.end(), array1.begin(),
02050                      result.begin(), std::minus<Type>());
02051       return result;
02052     }
02053 
02054     template <class Type>
02055     Array2D<Type> operator*(const Array2D<Type>& array0,
02056                             const Array2D<Type>& array1)
02057     {
02058       if((array0.rows() != array1.rows())
02059          || (array0.columns() != array1.columns())) {
02060         std::ostringstream message;
02061         message << "Array sizes do not match.  Array0 is " << array0.rows()
02062                 << " x " << array0.columns() << ", while array1 is "
02063                 << array1.rows() << " x " << array1.columns() << ".";
02064         DLR_THROW(ValueException, "Array2D::operator*()", message.str().c_str());
02065       }
02066       Array2D<Type> result(array0.rows(), array0.columns());
02067       std::transform(array0.begin(), array0.end(), array1.begin(),
02068                      result.begin(), std::multiplies<Type>());
02069       return result;
02070     }
02071 
02072     template <class Type>
02073     Array2D<Type> operator/(const Array2D<Type>& array0,
02074                             const Array2D<Type>& array1)
02075     {
02076       if((array0.rows() != array1.rows())
02077          || (array0.columns() != array1.columns())) {
02078         std::ostringstream message;
02079         message << "Array sizes do not match.  Array0 is " << array0.rows()
02080                 << " x " << array0.columns() << ", while array1 is "
02081                 << array1.rows() << " x " << array1.columns() << ".";
02082         DLR_THROW(ValueException, "Array2D::operator/()", message.str().c_str());
02083       }
02084       Array2D<Type> result(array0.rows(), array0.columns());
02085       std::transform(array0.begin(), array0.end(), array1.begin(),
02086                      result.begin(), std::divides<Type>());
02087       return result;
02088     }
02089 
02090     template <class Type>
02091     Array2D<Type> operator+(const Array2D<Type>& array0, Type scalar)
02092     {
02093       Array2D<Type> result(array0.rows(), array0.columns());
02094       std::transform(array0.begin(), array0.end(), result.begin(),
02095                      std::bind2nd(std::plus<Type>(), scalar));
02096       return result;
02097     }
02098 
02099     template <class Type>
02100     Array2D<Type> operator-(const Array2D<Type>& array0, Type scalar)
02101     {
02102       Array2D<Type> result(array0.rows(), array0.columns());
02103       std::transform(array0.begin(), array0.end(), result.begin(),
02104                      std::bind2nd(std::minus<Type>(), scalar));
02105       return result;
02106     }
02107 
02108     template <class Type>
02109     Array2D<Type> operator*(const Array2D<Type>& array0, Type scalar)
02110     {
02111       Array2D<Type> result(array0.rows(), array0.columns());
02112       std::transform(array0.begin(), array0.end(), result.begin(),
02113                      std::bind2nd(std::multiplies<Type>(), scalar));
02114       return result;
02115     }
02116 
02117     template <class Type>
02118     Array2D<Type> operator/(const Array2D<Type>& array0, Type scalar)
02119     {
02120       Array2D<Type> result(array0.rows(), array0.columns());
02121       std::transform(array0.begin(), array0.end(), result.begin(),
02122                      std::bind2nd(std::divides<Type>(), scalar));
02123       return result;
02124     }
02125 
02126     template <class Type>
02127     inline Array2D<Type> operator+(Type scalar, const Array2D<Type>& array0)
02128     {
02129       return array0 + scalar;
02130     }
02131 
02132     template <class Type>
02133     inline Array2D<Type> operator*(Type scalar, const Array2D<Type>& array0)
02134     {
02135       return array0 * scalar;
02136     }
02137 
02138 
02139     // Elementwise comparison of an Array2D with a constant.
02140     template <class Type>
02141     Array2D<bool>
02142     operator==(const Array2D<Type>& array0, const Type arg)
02143     {
02144       Array2D<bool> result(array0.rows(), array0.columns());
02145       std::transform(array0.begin(), array0.end(), result.data(),
02146                      std::bind2nd(std::equal_to<Type>(), arg));
02147       return result;
02148     }
02149 
02150     
02151     // Elementwise comparison of an Array2D with another array.
02152     template <class Type>
02153     Array2D<bool>
02154     operator==(const Array2D<Type>& array0, const Array2D<Type>& array1)
02155     {
02156       array0.checkDimension(array1.rows(), array1.columns());
02157       Array2D<bool> result(array0.rows(), array0.columns());
02158       std::transform(array0.begin(), array0.end(), array1.begin(),
02159                      result.begin(), std::equal_to<Type>());
02160       return result;
02161     }
02162 
02163   
02164     template <class Type>
02165     Array2D<bool> operator>(const Array2D<Type>& array0, Type arg)
02166     {
02167       Array2D<bool> result(array0.rows(), array0.columns());
02168       std::transform(array0.begin(), array0.end(), result.begin(),
02169                      std::bind2nd(std::greater<Type>(), arg));
02170       return result;
02171     }
02172 
02173     template <class Type>
02174     Array2D<bool> operator<(const Array2D<Type>& array0, Type arg)
02175     {
02176       Array2D<bool> result(array0.rows(), array0.columns());
02177       std::transform(array0.begin(), array0.end(), result.begin(),
02178                      std::bind2nd(std::less<Type>(), arg));
02179       return result;
02180     }
02181 
02182     template <class Type>
02183     Array2D<bool> operator>=(const Array2D<Type>& array0, Type arg)
02184     {
02185       Array2D<bool> result(array0.rows(), array0.columns());
02186       std::transform(array0.begin(), array0.end(), result.begin(),
02187                      std::bind2nd(std::greater_equal<Type>(), arg));
02188       return result;
02189     }
02190 
02191     template <class Type>
02192     Array2D<bool> operator<=(const Array2D<Type>& array0, Type arg)
02193     {
02194       Array2D<bool> result(array0.rows(), array0.columns());
02195       std::transform(array0.begin(), array0.end(), result.begin(),
02196                      std::bind2nd(std::less_equal<Type>(), arg));
02197       return result;
02198     }
02199 
02200     template <class Type>
02201     std::ostream& operator<<(std::ostream& stream, const Array2D<Type>& array0)
02202     {
02203       // Most of the time, OutputType will be the same as Type.
02204       typedef typename NumericTraits<Type>::TextOutputType OutputType;
02205 
02206       stream << "Array2D([[";
02207       for(size_t row = 0; row < array0.rows(); ++row) {
02208         if (array0.columns() > 0) {
02209           for(size_t column = 0; column < array0.columns() - 1; ++column) {
02210             stream << static_cast<OutputType>(array0(row, column)) << ", ";
02211           }
02212           stream << static_cast<OutputType>(array0(row, array0.columns() - 1));
02213           if(row != array0.rows() - 1) {
02214             stream << "],\n";
02215             stream << "         [";
02216           }
02217         }
02218       } 
02219       stream << "]])";
02220       stream.flush();
02221       return stream;
02222     }
02223 
02224   
02225     template <class Type>
02226     std::istream& operator>>(std::istream& inputStream, Array2D<Type>& array0)
02227     {
02228       return array0.readFromStream(inputStream);
02229     }
02230   
02231   } // namespace numeric
02232 
02233 } // namespace dlr
02234 
02235 #endif /* #ifdef _DLR_ARRAY2D_H_ */

Generated on Wed Nov 25 00:42:41 2009 for dlrUtilities Utility Library by  doxygen 1.5.8