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 
00505       void
00506       reshape(int arrayRows, int arrayColumns);
00507 
00508       
00516       inline Array1D<Type>
00517       row(size_t index) {return this->getRow(index);}
00518 
00519       
00527       const Array1D<Type>
00528       row(size_t index) const {return this->getRow(index);}
00529 
00530       
00541       iterator
00542       rowBegin(size_t rowIndex) {return m_dataPtr + rowIndex * m_columns;}
00543 
00544       
00555       const_iterator
00556       rowBegin(size_t rowIndex) const {
00557         return m_dataPtr + rowIndex * m_columns;
00558       }
00559 
00560       
00571       iterator
00572       rowEnd(size_t rowIndex) {
00573         return m_dataPtr + (rowIndex + 1) * m_columns;
00574       }
00575 
00576 
00587       const_iterator
00588       rowEnd(size_t rowIndex) const {
00589         return m_dataPtr + (rowIndex + 1) * m_columns;
00590       }
00591 
00592       
00600       size_t
00601       rows() const {return m_rows;}
00602 
00603 
00617       Type&
00618       setElement(size_t index0, const Type& value) {
00619         return this->operator()(index0) = value;
00620       }
00621 
00622 
00639       Type&
00640       setElement(size_t rowIndex, size_t columnIndex, const Type& value) {
00641         return this->operator()(rowIndex, columnIndex) = value;
00642       }
00643 
00644 
00653       Array1D<size_t>
00654       shape() const;
00655 
00667       size_t
00668       shape(size_t axis) const;
00669 
00676       size_t
00677       size() const {return m_size;}
00678 
00685       Array2D<Type>
00686       transpose() const;
00687     
00696       Array2D<Type>&
00697       operator=(const Array2D<Type>& source);
00698 
00706       Array2D<Type>&
00707       operator=(Type value);
00708 
00717       Type&
00718       operator()(size_t index) {
00719         this->checkBounds(index);
00720         return m_dataPtr[index];
00721       }
00722 
00729       Type operator()(size_t index) const {
00730         this->checkBounds(index);
00731         return m_dataPtr[index];
00732       }
00733   
00743       Type&
00744       operator()(size_t rowIndex, size_t columnIndex) {
00745         this->checkBounds(rowIndex, columnIndex);
00746         return m_dataPtr[columnIndex + rowIndex * m_columns];
00747       }
00748     
00758       Type
00759       operator()(size_t rowIndex, size_t columnIndex) const {
00760         this->checkBounds(rowIndex, columnIndex);
00761         return m_dataPtr[columnIndex + rowIndex * m_columns];
00762       }
00763 
00772       Type&
00773       operator[](size_t index) {return this->operator()(index);}
00774   
00783       Type
00784       operator[](size_t index) const {return this->operator()(index);}
00785 
00797       template <class Type2> Array2D<Type>&
00798       operator+=(const Array2D<Type2>& arg);
00799       
00811       template <class Type2> Array2D<Type>&
00812       operator-=(const Array2D<Type2>& arg);
00813 
00825       template <class Type2> Array2D<Type>&
00826       operator*=(const Array2D<Type2>& arg);
00827 
00839       template <class Type2> Array2D<Type>&
00840       operator/=(const Array2D<Type2>& arg);
00841     
00849       Array2D<Type>&
00850       operator+=(Type arg);
00851 
00859       Array2D<Type>&
00860       operator-=(Type arg);
00861 
00869       Array2D<Type>&
00870       operator*=(Type arg);
00871 
00879       Array2D<Type>&
00880       operator/=(Type arg);
00881 
00882     private:
00883       /* ******** Private member functions ******** */
00884       void
00885       allocate();
00886     
00887       // Optionally throw an exception if index is beyond the range of
00888       // this array.
00889       inline void
00890       checkBounds(size_t index) const;
00891 
00892       // Optionally throw an exception if either index is beyond the
00893       // range of this array.
00894       inline void
00895       checkBounds(size_t row, size_t column) const;
00896 
00897       void
00898       deAllocate();
00899 
00900       // Constants to help with formatting.  We use the initialization
00901       // on first use paradigm for the string constants to avoid
00902       // headaches.
00903 
00908       static const std::string& ioIntro(); 
00909 
00914       static const std::string& ioOutro();
00915 
00920       static const char ioOpening = '[';
00921 
00926       static const char ioClosing = ']';
00927 
00932       static const char ioSeparator = ',';
00933 
00934     
00935       /* ********Private data members******** */
00936       size_t m_rows;
00937       size_t m_columns;
00938       size_t m_size;
00939       Type* m_dataPtr;
00940       size_t* m_refCountPtr;
00941       bool m_isAllocated;
00942     
00943     };
00944   
00945     /* Non-member functions which will ultimately wind up in a different file */
00946 
00957     template <class Type>
00958     Array2D<Type>
00959     squareRoot(const Array2D<Type>& array0);
00960   
00972     template <class Type>
00973     inline Array2D<Type>
00974     sqrt(const Array2D<Type>& array0);
00975 
00989     template <class Type>
00990     Array2D<Type>
00991     operator+(const Array2D<Type>& array0,
00992               const Array2D<Type>& array1);
00993   
01007     template <class Type>
01008     Array2D<Type>
01009     operator-(const Array2D<Type>& array0,
01010               const Array2D<Type>& array1);
01011   
01025     template <class Type>
01026     Array2D<Type>
01027     operator*(const Array2D<Type>& array0,
01028               const Array2D<Type>& array1);
01029   
01043     template <class Type>
01044     Array2D<Type>
01045     operator/(const Array2D<Type>& array0,
01046               const Array2D<Type>& array1);
01047   
01059     template <class Type>
01060     Array2D<Type>
01061     operator+(const Array2D<Type>& array0, Type scalar);
01062   
01074     template <class Type>
01075     Array2D<Type>
01076     operator-(const Array2D<Type>& array0, Type scalar);
01077   
01089     template <class Type>
01090     Array2D<Type>
01091     operator*(const Array2D<Type>& array0, Type scalar);
01092   
01104     template <class Type>
01105     Array2D<Type>
01106     operator/(const Array2D<Type>& array0, Type scalar);
01107 
01119     template <class Type>
01120     inline Array2D<Type>
01121     operator+(Type scalar, const Array2D<Type>& array0);
01122   
01123 
01135     template <class Type>
01136     inline Array2D<Type>
01137     operator*(Type scalar, const Array2D<Type>& array0);
01138 
01139 
01151     template <class Type>
01152     Array2D<bool>
01153     operator==(const Array2D<Type>& array0, const Type arg);
01154 
01155     
01168     template <class Type>
01169     Array2D<bool>
01170     operator==(const Array2D<Type>& array0, const Array2D<Type>& array1);
01171     
01172 
01184     template <class Type>
01185     Array2D<bool>
01186     operator>(const Array2D<Type>& array0, Type arg);
01187 
01188   
01200     template <class Type>
01201     Array2D<bool>
01202     operator<(const Array2D<Type>& array0, Type arg);
01203 
01204   
01217     template <class Type>
01218     Array2D<bool>
01219     operator>=(const Array2D<Type>& array0, Type arg);
01220 
01221   
01234     template <class Type>
01235     Array2D<bool>
01236     operator<=(const Array2D<Type>& array0, Type arg);
01237 
01238   
01257     template <class Type>
01258     std::ostream&
01259     operator<<(std::ostream& stream, const Array2D<Type>& array0);
01260 
01272     template <class Type>
01273     std::istream&
01274     operator>>(std::istream& stream, Array2D<Type>& array0);
01275   
01276   } // namespace numeric
01277 
01278 } // namespace dlr
01279 
01280 
01281 /* ======= Declarations to maintain compatibility with legacy code. ======= */
01282 
01283 namespace dlr {
01284 
01285   using numeric::Array2D;
01286 
01287 } // namespace dlr
01288 
01289 
01290 /*******************************************************************
01291  * Member function definitions follow.  This would be a .C file
01292  * if it weren't templated.
01293  *******************************************************************/
01294 
01295 #include <algorithm>
01296 #include <functional>
01297 #include <sstream>
01298 #include <vector>
01299 #include <dlrCommon/functional.h>
01300 #include <dlrCommon/inputStream.h>
01301 #include <dlrNumeric/numericTraits.h>
01302 #include <dlrNumeric/functional.h>
01303 
01304 namespace dlr {
01305 
01306   namespace numeric {
01307     
01308     // Static constant describing how the string representation of an
01309     // Array2D should start.
01310     template <class Type>
01311     const std::string&
01312     Array2D<Type>::
01313     ioIntro()
01314     {
01315       static const std::string intro = "Array2D(";
01316       return intro;
01317     }
01318 
01319     // Static constant describing how the string representation of an
01320     // Array2D should end.
01321     template <class Type>
01322     const std::string&
01323     Array2D<Type>::
01324     ioOutro()
01325     {
01326       static const std::string outro = ")";
01327       return outro;
01328     }
01329 
01330     // Non-static member functions below.
01331 
01332     template <class Type>
01333     Array2D<Type>::
01334     Array2D()
01335       : m_rows(0),
01336         m_columns(0),
01337         m_size(0),
01338         m_dataPtr(0),
01339         m_refCountPtr(0),
01340         m_isAllocated(false)
01341     {
01342       // Empty
01343     }
01344 
01345 
01346     template <class Type>
01347     Array2D<Type>::
01348     Array2D(size_t arrayRows, size_t arrayColumns)
01349       : m_rows(arrayRows),
01350         m_columns(arrayColumns),
01351         m_size(0),          // This will be set in the call to allocate().
01352         m_dataPtr(0),       // This will be set in the call to allocate().
01353         m_refCountPtr(0),   // This will be set in the call to allocate().
01354         m_isAllocated(false)
01355     {
01356       this->allocate();
01357     }
01358 
01359   
01360     // Construct from an initialization string.
01361     template <class Type>
01362     Array2D<Type>::
01363     Array2D(const std::string& inputString)
01364       : m_rows(0),
01365         m_columns(0),
01366         m_size(0),
01367         m_dataPtr(0),
01368         m_refCountPtr(0),
01369         m_isAllocated(false)
01370     {
01371       // We'll use the stream input operator to parse the string.
01372       std::istringstream inputStream(inputString);
01373 
01374       // Now read the string into an array.
01375       Array2D<Type> inputArray;
01376       inputStream >> inputArray;
01377       if(!inputStream) {
01378         std::ostringstream message;
01379         message << "Couldn't parse input string: \"" << inputString << "\".";
01380         DLR_THROW3(ValueException, "Array2D::Array2D(const std::string&)",
01381                    message.str().c_str());                 
01382       }
01383 
01384       // If all went well, copy into *this.
01385       *this = inputArray;
01386     }
01387 
01388 
01389     /* When copying from a Array2D do a shallow copy */
01390     /* Update reference count if the array we're copying has */
01391     /* valid data. */
01392     template <class Type>
01393     Array2D<Type>::
01394     Array2D(const Array2D<Type>& source)
01395       : m_rows(source.m_rows),
01396         m_columns(source.m_columns),
01397         m_size(source.m_size),
01398         m_dataPtr(source.m_dataPtr),
01399         m_refCountPtr(source.m_refCountPtr),
01400         m_isAllocated(source.m_isAllocated)
01401     {
01402       if(m_isAllocated) {
01403         ++(*m_refCountPtr);
01404       }
01405     }
01406 
01407   
01408     /* Here's a constructor for getting image data into the array */
01409     /* cheaply. */
01410     template <class Type>
01411     Array2D<Type>::
01412     Array2D(size_t arrayRows, size_t arrayColumns, Type* const dataPtr)
01413       : m_rows(arrayRows),
01414         m_columns(arrayColumns),
01415         m_size(arrayRows*arrayColumns),
01416         m_dataPtr(dataPtr),
01417         m_refCountPtr(0),
01418         m_isAllocated(false)
01419     {
01420       // Empty
01421     }
01422 
01423   
01424     // Construct an array around external data which was allocated by
01425     // an Array?D instance.
01426     template <class Type>
01427     Array2D<Type>::
01428     Array2D(size_t arrayRows, size_t arrayColumns, Type* const dataPtr,
01429             size_t* referenceCountPtr)
01430       : m_rows(arrayRows),
01431         m_columns(arrayColumns),
01432         m_size(arrayRows*arrayColumns),
01433         m_dataPtr(dataPtr),
01434         m_refCountPtr(referenceCountPtr),
01435         m_isAllocated(true)
01436     {
01437       ++(*m_refCountPtr);
01438     }
01439 
01440   
01441     template <class Type>
01442     Array2D<Type>::
01443     ~Array2D()
01444     {
01445       deAllocate();
01446     }
01447 
01448   
01449     template <class Type>
01450     inline void Array2D<Type>::
01451     checkDimension(size_t arrayRows, size_t arrayColumns) const
01452     {
01453 #ifdef _DLRNUMERIC_CHECKBOUNDS_
01454       if(arrayRows != this->rows()
01455          || arrayColumns != this->columns()) {
01456         std::ostringstream message;
01457         message << "Size mismatch: required dimension is ("
01458                 << arrayRows << ", " << arrayColumns << ") "
01459                 << " while *this has dimension "
01460                 << this->rows() << ", " << this->columns() << ").";
01461         DLR_THROW(IndexException, "Array2D::checkDimension()",
01462                   message.str().c_str());
01463       }
01464 #endif
01465     }
01466 
01467 
01468     template <class Type>
01469     Array2D<Type> Array2D<Type>::
01470     copy() const
01471     {
01472       Array2D<Type> newArray(m_rows, m_columns);
01473       newArray.copy(*this);
01474       return newArray;
01475     }
01476 
01477     
01478     template <class Type> template <class Type2>
01479     void Array2D<Type>::
01480     copy(const Array2D<Type2>& source)
01481     {
01482       if(source.size() != m_size) {
01483         std::ostringstream message;
01484         message << "Mismatched array sizes. Source array has "
01485                 << source.size() << " elements, while destination array has "
01486                 << m_size << " elements.";
01487         DLR_THROW3(ValueException, "Array2D::copy(const Array2D&)",
01488                    message.str().c_str());
01489       }
01490       if(m_size != 0) {
01491         this->copy(source.data());
01492       }
01493     }
01494 
01495 
01496     template <class Type> template <class Type2>
01497     void Array2D<Type>::
01498     copy(const Type2* dataPtr)
01499     {
01500       if(dataPtr == 0) {
01501         DLR_THROW(ValueException, "Array2D::copy(const Type2*)",
01502                   "Argument is a NULL pointer.");
01503       }
01504       std::transform(dataPtr, dataPtr + m_size, m_dataPtr,
01505                      StaticCastFunctor<Type2, Type>());
01506     }
01507 
01508 
01509     template <class Type>
01510     Array1D<Type> Array2D<Type>::
01511     getRow(size_t index)
01512     {
01513       this->checkBounds(index, 0);
01514       return Array1D<Type>(this->columns(),
01515                            m_dataPtr + (index * this->m_columns));
01516     }
01517 
01518   
01519     template <class Type>
01520     const Array1D<Type> Array2D<Type>::
01521     getRow(size_t index) const
01522     {
01523       this->checkBounds(index, 0);
01524       return Array1D<Type>(this->columns(),
01525                            m_dataPtr + (index * this->m_columns));
01526     }
01527 
01528 
01529     template <class Type>
01530     const Array1D<Type> Array2D<Type>::
01531     ravel() const
01532     {
01533       if(m_isAllocated) {
01534         return Array1D<Type>(m_size, m_dataPtr, m_refCountPtr);
01535       }
01536       return Array1D<Type>(m_size, m_dataPtr);
01537     }
01538 
01539     template <class Type>
01540     Array1D<Type> Array2D<Type>::
01541     ravel()
01542     {
01543       if(m_isAllocated) {
01544         return Array1D<Type>(m_size, m_dataPtr, m_refCountPtr);
01545       }
01546       return Array1D<Type>(m_size, m_dataPtr);
01547     }
01548 
01549 
01550     template <class Type>
01551     std::istream&
01552     Array2D<Type>::
01553     readFromStream(std::istream& inputStream)
01554     {
01555       // Most of the time, InputType will be the same as Type.
01556       typedef typename NumericTraits<Type>::TextOutputType InputType;
01557 
01558       // If stream is in a bad state, we can't read from it.
01559       if (!inputStream){
01560         return inputStream;
01561       }
01562     
01563       // It's a lot easier to use a try block than to be constantly
01564       // testing whether the IO has succeeded, so we tell inputStream to
01565       // complain if anything goes wrong.
01566       std::ios_base::iostate oldExceptionState = inputStream.exceptions();
01567       inputStream.exceptions(
01568         std::ios_base::badbit | std::ios_base::failbit | std::ios_base::eofbit);
01569 
01570       // Now on with the show.
01571       try{
01572         // Construct an InputStream instance so we can use our
01573         // convenience functions.
01574         InputStream stream(inputStream);
01575 
01576         // Skip any preceding whitespace.
01577         stream.skipWhiteSpace();
01578       
01579         // We won't require the input format to start with "Array2D(", but
01580         // if it does we read it here.
01581         bool foundIntro = false;
01582         if(stream.peek() == ioIntro()[0]) {
01583           foundIntro = true;
01584           stream.expect(ioIntro());
01585         }
01586 
01587         // OK.  We've dispensed with the intro.  What's left should be of
01588         // the format "[row, row, row, ...]".  We require the square
01589         // brackets to be there.
01590         stream.expect(ioOpening);
01591 
01592         // Read the data.  We'll use the Array1D<Type> stream operator to
01593         // read each row.
01594         Array1D<Type> inputValue;
01595         std::vector< Array1D<Type> > inputBuffer;
01596         while(1) {
01597           // Read the next row.
01598           stream >> inputValue;
01599           inputBuffer.push_back(inputValue);
01600 
01601           // Read the separator, or else the closing character.
01602           char inChar = 0;
01603           stream >> inChar;
01604           if(inChar == ioClosing) {
01605             // Found a closing.  Stop here.
01606             break;
01607           }
01608           if(inChar != ioSeparator) {
01609             // Missing separator?  Fail here.
01610             stream.clear(std::ios_base::failbit);
01611           }
01612         }
01613     
01614         // If we found an intro, we expect the corresponding outro.
01615         if(foundIntro) {
01616           stream.expect(ioOutro());
01617         }
01618 
01619         // Now we're done with all of the parsing, verify that all rows
01620         // have the same length.
01621         size_t arrayRows = inputBuffer.size();
01622         size_t arrayColumns = ((inputBuffer.size() != 0) ? inputBuffer[0].size() : 0);
01623         for(size_t index = 1; index < arrayRows; ++index) {
01624           if(inputBuffer[index].size() != arrayColumns) {
01625             // Inconsistent row lengths!  Fail here.
01626             stream.clear(std::ios_base::failbit);
01627           }
01628         }
01629 
01630         // And finally, copy the data.
01631         this->reinit(arrayRows, arrayColumns);
01632         for(size_t index = 0; index < arrayRows; ++index) {
01633           std::copy(inputBuffer[index].begin(), inputBuffer[index].end(),
01634                     this->begin() + (index * arrayColumns));
01635         }
01636       } catch(std::ios_base::failure) {
01637         // Empty
01638       }
01639       inputStream.exceptions(oldExceptionState);
01640       return inputStream;
01641     }
01642   
01643 
01644     template <class Type>
01645     void Array2D<Type>::
01646     reinit(size_t arrayRows, size_t arrayColumns)
01647     {
01648       this->deAllocate();
01649       this->m_rows = arrayRows;
01650       this->m_columns = arrayColumns;
01651       this->allocate();
01652     }
01653 
01654 
01655     /* After reshaping, matrix is still row major order */
01656     template <class Type>
01657     void Array2D<Type>::
01658     reshape(int arrayRows, int arrayColumns)
01659     {
01660       // If one axis is specified as -1, it will be automatically 
01661       // chosen to match the number of elements in the array.
01662       if((arrayRows == -1) && (arrayColumns != 0)) {
01663         arrayRows = static_cast<int>(this->size()) / arrayColumns;
01664       } else
01665         if((arrayColumns == -1) && (arrayRows != 0)) {
01666           arrayColumns = static_cast<int>(this->size()) / arrayRows;
01667         }
01668       if((arrayRows * arrayColumns) != static_cast<int>(this->size())) {
01669         std::ostringstream message;
01670         message << "Can't reshape a(n) " << this->size()
01671                 << " element array to have " << arrayRows << " rows and "
01672                 << arrayColumns << " columns.";
01673         DLR_THROW(ValueException, "Array2D::reshape()", message.str().c_str());
01674       }
01675       m_rows = arrayRows;
01676       m_columns = arrayColumns;
01677     }
01678 
01679   
01680     template <class Type>
01681     Array1D<size_t> Array2D<Type>::
01682     shape() const
01683     {
01684       Array1D<size_t> rc(2);
01685       rc(0) = this->rows();
01686       rc(1) = this->columns();
01687       return rc;
01688     }
01689 
01690 
01691     template <class Type>
01692     size_t Array2D<Type>::
01693     shape(size_t axis) const
01694     {
01695       size_t result;
01696       switch(axis) {
01697       case 0:
01698         result = this->rows();
01699         break;
01700       case 1:
01701         result = this->columns();
01702         break;
01703       default:
01704         std::ostringstream message;
01705         message << "Invalid Axis: "<< axis << ".";
01706         DLR_THROW(ValueException, "Array2D::shape(size_t)",
01707                   message.str().c_str());
01708         result = 0;
01709         break;
01710       }
01711       return result;
01712     }
01713 
01714 
01715     template <class Type>
01716     Array2D<Type>& Array2D<Type>::
01717     operator=(Type value)
01718     {
01719       std::fill(m_dataPtr, m_dataPtr + m_size, value);
01720       return *this;
01721     }
01722 
01723   
01724     template <class Type>
01725     Array2D<Type>& Array2D<Type>::
01726     operator=(const Array2D<Type>& source)
01727     {
01728       // Check for self-assignment
01729       if(&source != this) {
01730         this->deAllocate();
01731         m_rows = source.m_rows;
01732         m_columns = source.m_columns;
01733         m_size = source.m_size;
01734         m_dataPtr = source.m_dataPtr;
01735         m_refCountPtr = source.m_refCountPtr;
01736         m_isAllocated = source.m_isAllocated;
01737         if(m_isAllocated) {
01738           ++(*m_refCountPtr);
01739         }
01740       }
01741       return *this;
01742     }
01743 
01744 
01745     template <class Type> template <class Type2>
01746     Array2D<Type>&
01747     Array2D<Type>::
01748     operator+=(const Array2D<Type2>& arg)
01749     {
01750       if(m_size != arg.size()) {
01751         std::ostringstream message;
01752         message << "Mismatched array sizes. Argument array is "
01753                 << arg.rows() << " x " << arg.columns()
01754                 << ", while destination array is "
01755                 << m_rows << " x " << m_columns << ".";
01756         DLR_THROW(ValueException, "Array2D::operator+=()",
01757                   message.str().c_str());
01758       }
01759       std::transform(m_dataPtr, m_dataPtr + m_size, arg.data(), m_dataPtr,
01760                      std::plus<Type>());
01761       return *this;
01762     }
01763 
01764 
01765     template <class Type> template <class Type2>
01766     Array2D<Type>&
01767     Array2D<Type>::
01768     operator-=(const Array2D<Type2>& arg)
01769     {
01770       if(m_size != arg.size()) {
01771         std::ostringstream message;
01772         message << "Mismatched array sizes. Argument array is "
01773                 << arg.rows() << " x " << arg.columns()
01774                 << ", while destination array is "
01775                 << m_rows << " x " << m_columns << ".";
01776         DLR_THROW(ValueException, "Array2D::operator-=()",
01777                   message.str().c_str());
01778       }
01779       std::transform(m_dataPtr, m_dataPtr + m_size, arg.data(), m_dataPtr,
01780                      std::minus<Type>());
01781       return *this;
01782     }
01783 
01784 
01785     template <class Type> template <class Type2>
01786     Array2D<Type>&
01787     Array2D<Type>::
01788     operator*=(const Array2D<Type2>& arg)
01789     {
01790       if(m_size != arg.size()) {
01791         std::ostringstream message;
01792         message << "Mismatched array sizes. Argument array is "
01793                 << arg.rows() << " x " << arg.columns()
01794                 << ", while destination array is "
01795                 << m_rows << " x " << m_columns << ".";
01796         DLR_THROW(ValueException, "Array2D::operator*=()",
01797                   message.str().c_str());
01798       }
01799       std::transform(m_dataPtr, m_dataPtr + m_size, arg.data(), m_dataPtr,
01800                      std::multiplies<Type>());
01801       return *this;
01802     }
01803 
01804 
01805     template <class Type> template <class Type2>
01806     Array2D<Type>&
01807     Array2D<Type>::
01808     operator/=(const Array2D<Type2>& arg)
01809     {
01810       if(m_size != arg.size()) {
01811         std::ostringstream message;
01812         message << "Mismatched array sizes. Argument array is "
01813                 << arg.rows() << " x " << arg.columns()
01814                 << ", while destination array is "
01815                 << m_rows << " x " << m_columns << ".";
01816         DLR_THROW(ValueException, "Array2D::operator/=()",
01817                   message.str().c_str());
01818       }
01819       std::transform(m_dataPtr, m_dataPtr + m_size, arg.data(), m_dataPtr,
01820                      std::divides<Type>());
01821       return *this;
01822     }
01823 
01824 
01825     template <class Type>
01826     Array2D<Type>&
01827     Array2D<Type>::
01828     operator*=(Type arg)
01829     {
01830       std::transform(m_dataPtr, m_dataPtr + m_size, m_dataPtr,
01831                      std::bind2nd(std::multiplies<Type>(), arg));
01832       return *this;
01833     }
01834 
01835 
01836     template <class Type>
01837     Array2D<Type>&
01838     Array2D<Type>::
01839     operator/=(Type arg)
01840     {
01841       std::transform(m_dataPtr, m_dataPtr + m_size, m_dataPtr,
01842                      std::bind2nd(std::divides<Type>(), arg));
01843       return *this;
01844     }
01845 
01846 
01847     template <class Type>
01848     Array2D<Type>&
01849     Array2D<Type>::
01850     operator+=(Type arg)
01851     {
01852       std::transform(m_dataPtr, m_dataPtr + m_size, m_dataPtr,
01853                      std::bind2nd(std::plus<Type>(), arg));
01854       return *this;
01855     }
01856 
01857 
01858     template <class Type>
01859     Array2D<Type>&
01860     Array2D<Type>::
01861     operator-=(Type arg)
01862     {
01863       std::transform(m_dataPtr, m_dataPtr + m_size, m_dataPtr,
01864                      std::bind2nd(std::minus<Type>(), arg));
01865       return *this;
01866     }
01867 
01868 
01869     template <class Type>
01870     Array2D<Type> Array2D<Type>::
01871     transpose() const
01872     {
01873       Array2D<Type> newMx(m_columns, m_rows);
01874 
01875       // Waiting for row & column iterators
01876       Type *tPtr0 = newMx.m_dataPtr;
01877       for(size_t j = 0; j < m_columns; ++j) {
01878         // const Type *tPtr1 = this->data(0, j);
01879         const Type *tPtr1 = this->data(j);
01880         for(size_t i = 0; i < m_rows; ++i) {
01881           *tPtr0 = *tPtr1;
01882           ++tPtr0;
01883           tPtr1 += m_columns;
01884         }
01885       }
01886       return newMx;
01887     }
01888 
01889 
01890     template <class Type>
01891     void Array2D<Type>::
01892     allocate()
01893     {
01894       m_size = m_rows * m_columns;
01895       if(m_rows > 0 && m_columns > 0) {
01896         m_dataPtr = new(Type[m_rows * m_columns]); // should throw an exception
01897         m_refCountPtr = new size_t;                 // if we're out of memory.
01898         *m_refCountPtr = 1;
01899         m_isAllocated = true;
01900         return;
01901       }
01902       m_dataPtr = 0;
01903       m_refCountPtr = 0;
01904       m_isAllocated = false;
01905       return;
01906     }
01907 
01908 
01909     template <class Type>
01910     inline void Array2D<Type>::
01911     checkBounds(size_t index) const
01912     {
01913 #ifdef _DLRNUMERIC_CHECKBOUNDS_
01914       if(index >= m_size) {
01915         std::ostringstream message;
01916         message << "Index " << index << " is invalid for a(n) " << m_rows
01917                 << " x " << m_columns << " array.";
01918         DLR_THROW(IndexException, "Array2D::checkBounds(size_t)",
01919                   message.str().c_str());
01920       }
01921 #endif
01922     }
01923 
01924 
01925     template <class Type>
01926     inline void Array2D<Type>::
01927     checkBounds(size_t rowIndex, size_t columnIndex) const
01928     {
01929 #ifdef _DLRNUMERIC_CHECKBOUNDS_
01930       if(rowIndex >= m_rows) {
01931         std::ostringstream message;
01932         message << "Row index " << rowIndex << " is invalid for a(n) "
01933                 << m_rows << " x " << m_columns << " array.";
01934         DLR_THROW(IndexException, "Array2D::checkBounds(size_t, size_t)",
01935                   message.str().c_str());
01936       }
01937       if(columnIndex >= m_columns) {
01938         std::ostringstream message;
01939         message << "Column index " << columnIndex << " is invalid for a(n) "
01940                 << m_rows << " x " << m_columns << " array.";
01941         DLR_THROW(IndexException, "Array2D::checkBounds(size_t, size_t)",
01942                   message.str().c_str());
01943       }
01944 #endif
01945     }
01946 
01947 
01948     template <class Type>
01949     void Array2D<Type>::
01950     deAllocate()
01951     {
01952       if(m_isAllocated == true) {
01953         if(--(*m_refCountPtr) == 0) {
01954           delete[] m_dataPtr;
01955           delete m_refCountPtr;
01956           m_isAllocated = false;
01957           m_dataPtr = 0;
01958           m_refCountPtr = 0;
01959         }
01960       } else {
01961         m_dataPtr = 0;
01962         m_refCountPtr = 0;
01963       }
01964     }
01965 
01966     /* Non-member functions which will ultimately wind up in a different file */
01967 
01968     template <class Type>
01969     inline Array2D<Type>
01970     sqrt(const Array2D<Type>& array0)
01971     {
01972       return squareRoot(array0);
01973     }
01974 
01975     // This function returns an Array2D instance of the same shape and
01976     // element type as its input, in which each element contains the
01977     // square root of the corresponding element of the input array.
01978     template <class Type>
01979     Array2D<Type>
01980     squareRoot(const Array2D<Type>& array0)
01981     {
01982       Array2D<Type> result(array0.rows(), array0.columns());
01983       std::transform(array0.begin(), array0.end(),
01984                      result.begin(), SquareRootFunctor<Type>());
01985       return result;
01986     }
01987 
01988     template <class Type>
01989     Array2D<Type> operator+(const Array2D<Type>& array0,
01990                             const Array2D<Type>& array1)
01991     {
01992       if((array0.rows() != array1.rows())
01993          || (array0.columns() != array1.columns())) {
01994         std::ostringstream message;
01995         message << "Array sizes do not match.  Array0 is " << array0.rows()
01996                 << " x " << array0.columns() << ", while array1 is "
01997                 << array1.rows() << " x " << array1.columns() << ".";
01998         DLR_THROW(ValueException, "Array2D::operator+()", message.str().c_str());
01999       }
02000       Array2D<Type> result(array0.rows(), array0.columns());
02001       std::transform(array0.begin(), array0.end(), array1.begin(),
02002                      result.begin(), std::plus<Type>());
02003       return result;
02004     }
02005 
02006     template <class Type>
02007     Array2D<Type> operator-(const Array2D<Type>& array0,
02008                             const Array2D<Type>& array1)
02009     {
02010       if((array0.rows() != array1.rows())
02011          || (array0.columns() != array1.columns())) {
02012         std::ostringstream message;
02013         message << "Array sizes do not match.  Array0 is " << array0.rows()
02014                 << " x " << array0.columns() << ", while array1 is "
02015                 << array1.rows() << " x " << array1.columns() << ".";
02016         DLR_THROW(ValueException, "Array2D::operator-()", message.str().c_str());
02017       }
02018       Array2D<Type> result(array0.rows(), array0.columns());
02019       std::transform(array0.begin(), array0.end(), array1.begin(),
02020                      result.begin(), std::minus<Type>());
02021       return result;
02022     }
02023 
02024     template <class Type>
02025     Array2D<Type> operator*(const Array2D<Type>& array0,
02026                             const Array2D<Type>& array1)
02027     {
02028       if((array0.rows() != array1.rows())
02029          || (array0.columns() != array1.columns())) {
02030         std::ostringstream message;
02031         message << "Array sizes do not match.  Array0 is " << array0.rows()
02032                 << " x " << array0.columns() << ", while array1 is "
02033                 << array1.rows() << " x " << array1.columns() << ".";
02034         DLR_THROW(ValueException, "Array2D::operator*()", message.str().c_str());
02035       }
02036       Array2D<Type> result(array0.rows(), array0.columns());
02037       std::transform(array0.begin(), array0.end(), array1.begin(),
02038                      result.begin(), std::multiplies<Type>());
02039       return result;
02040     }
02041 
02042     template <class Type>
02043     Array2D<Type> operator/(const Array2D<Type>& array0,
02044                             const Array2D<Type>& array1)
02045     {
02046       if((array0.rows() != array1.rows())
02047          || (array0.columns() != array1.columns())) {
02048         std::ostringstream message;
02049         message << "Array sizes do not match.  Array0 is " << array0.rows()
02050                 << " x " << array0.columns() << ", while array1 is "
02051                 << array1.rows() << " x " << array1.columns() << ".";
02052         DLR_THROW(ValueException, "Array2D::operator/()", message.str().c_str());
02053       }
02054       Array2D<Type> result(array0.rows(), array0.columns());
02055       std::transform(array0.begin(), array0.end(), array1.begin(),
02056                      result.begin(), std::divides<Type>());
02057       return result;
02058     }
02059 
02060     template <class Type>
02061     Array2D<Type> operator+(const Array2D<Type>& array0, Type scalar)
02062     {
02063       Array2D<Type> result(array0.rows(), array0.columns());
02064       std::transform(array0.begin(), array0.end(), result.begin(),
02065                      std::bind2nd(std::plus<Type>(), scalar));
02066       return result;
02067     }
02068 
02069     template <class Type>
02070     Array2D<Type> operator-(const Array2D<Type>& array0, Type scalar)
02071     {
02072       Array2D<Type> result(array0.rows(), array0.columns());
02073       std::transform(array0.begin(), array0.end(), result.begin(),
02074                      std::bind2nd(std::minus<Type>(), scalar));
02075       return result;
02076     }
02077 
02078     template <class Type>
02079     Array2D<Type> operator*(const Array2D<Type>& array0, Type scalar)
02080     {
02081       Array2D<Type> result(array0.rows(), array0.columns());
02082       std::transform(array0.begin(), array0.end(), result.begin(),
02083                      std::bind2nd(std::multiplies<Type>(), scalar));
02084       return result;
02085     }
02086 
02087     template <class Type>
02088     Array2D<Type> operator/(const Array2D<Type>& array0, Type scalar)
02089     {
02090       Array2D<Type> result(array0.rows(), array0.columns());
02091       std::transform(array0.begin(), array0.end(), result.begin(),
02092                      std::bind2nd(std::divides<Type>(), scalar));
02093       return result;
02094     }
02095 
02096     template <class Type>
02097     inline Array2D<Type> operator+(Type scalar, const Array2D<Type>& array0)
02098     {
02099       return array0 + scalar;
02100     }
02101 
02102     template <class Type>
02103     inline Array2D<Type> operator*(Type scalar, const Array2D<Type>& array0)
02104     {
02105       return array0 * scalar;
02106     }
02107 
02108 
02109     // Elementwise comparison of an Array2D with a constant.
02110     template <class Type>
02111     Array2D<bool>
02112     operator==(const Array2D<Type>& array0, const Type arg)
02113     {
02114       Array2D<bool> result(array0.rows(), array0.columns());
02115       std::transform(array0.begin(), array0.end(), result.data(),
02116                      std::bind2nd(std::equal_to<Type>(), arg));
02117       return result;
02118     }
02119 
02120     
02121     // Elementwise comparison of an Array2D with another array.
02122     template <class Type>
02123     Array2D<bool>
02124     operator==(const Array2D<Type>& array0, const Array2D<Type>& array1)
02125     {
02126       array0.checkDimension(array1.rows(), array1.columns());
02127       Array2D<bool> result(array0.rows(), array0.columns());
02128       std::transform(array0.begin(), array0.end(), array1.begin(),
02129                      result.begin(), std::equal_to<Type>());
02130       return result;
02131     }
02132 
02133   
02134     template <class Type>
02135     Array2D<bool> operator>(const Array2D<Type>& array0, Type arg)
02136     {
02137       Array2D<bool> result(array0.rows(), array0.columns());
02138       std::transform(array0.begin(), array0.end(), result.begin(),
02139                      std::bind2nd(std::greater<Type>(), arg));
02140       return result;
02141     }
02142 
02143     template <class Type>
02144     Array2D<bool> operator<(const Array2D<Type>& array0, Type arg)
02145     {
02146       Array2D<bool> result(array0.rows(), array0.columns());
02147       std::transform(array0.begin(), array0.end(), result.begin(),
02148                      std::bind2nd(std::less<Type>(), arg));
02149       return result;
02150     }
02151 
02152     template <class Type>
02153     Array2D<bool> operator>=(const Array2D<Type>& array0, Type arg)
02154     {
02155       Array2D<bool> result(array0.rows(), array0.columns());
02156       std::transform(array0.begin(), array0.end(), result.begin(),
02157                      std::bind2nd(std::greater_equal<Type>(), arg));
02158       return result;
02159     }
02160 
02161     template <class Type>
02162     Array2D<bool> operator<=(const Array2D<Type>& array0, Type arg)
02163     {
02164       Array2D<bool> result(array0.rows(), array0.columns());
02165       std::transform(array0.begin(), array0.end(), result.begin(),
02166                      std::bind2nd(std::less_equal<Type>(), arg));
02167       return result;
02168     }
02169 
02170     template <class Type>
02171     std::ostream& operator<<(std::ostream& stream, const Array2D<Type>& array0)
02172     {
02173       // Most of the time, OutputType will be the same as Type.
02174       typedef typename NumericTraits<Type>::TextOutputType OutputType;
02175 
02176       stream << "Array2D([[";
02177       for(size_t row = 0; row < array0.rows(); ++row) {
02178         if (array0.columns() > 0) {
02179           for(size_t column = 0; column < array0.columns() - 1; ++column) {
02180             stream << static_cast<OutputType>(array0(row, column)) << ", ";
02181           }
02182           stream << static_cast<OutputType>(array0(row, array0.columns() - 1));
02183           if(row != array0.rows() - 1) {
02184             stream << "],\n";
02185             stream << "         [";
02186           }
02187         }
02188       } 
02189       stream << "]])";
02190       stream.flush();
02191       return stream;
02192     }
02193 
02194   
02195     template <class Type>
02196     std::istream& operator>>(std::istream& inputStream, Array2D<Type>& array0)
02197     {
02198       return array0.readFromStream(inputStream);
02199     }
02200   
02201   } // namespace numeric
02202 
02203 } // namespace dlr
02204 
02205 #endif /* #ifdef _DLR_ARRAY2D_H_ */

Generated on Tue Jan 6 17:52:06 2009 for dlrUtilities Utility Library by  doxygen 1.5.6