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     
00369       inline Type
00370       getElement(size_t index0) const {return this->operator()(index0);}
00371 
00372 
00385       Type
00386       getElement(size_t row, size_t column) const {
00387         return this->operator()(row, column);
00388       }        
00389 
00390 
00399       bool
00400       isAllocated() const {return m_isAllocated;}
00401     
00402     
00410       Array1D<Type>
00411       ravel();
00412 
00420       const Array1D<Type>
00421       ravel() const;
00422 
00435       std::istream&
00436       readFromStream(std::istream& inputStream);
00437     
00438 
00446       size_t*
00447       refCountPtr() const {return m_refCountPtr;}
00448 
00449     
00459       void
00460       reinit(size_t rows, size_t columns);
00461 
00476       void
00477       reshape(int rows, int columns);
00478 
00489       Array1D<Type>
00490       row(size_t index);
00491 
00502       const Array1D<Type>
00503       row(size_t index) const;
00504 
00505       
00516       iterator
00517       rowBegin(size_t rowIndex) {return m_dataPtr + rowIndex * m_columns;}
00518 
00519       
00530       const_iterator
00531       rowBegin(size_t rowIndex) const {
00532         return m_dataPtr + rowIndex * m_columns;
00533       }
00534 
00535       
00546       iterator
00547       rowEnd(size_t rowIndex) {
00548         return m_dataPtr + (rowIndex + 1) * m_columns;
00549       }
00550 
00551 
00562       const_iterator
00563       rowEnd(size_t rowIndex) const {
00564         return m_dataPtr + (rowIndex + 1) * m_columns;
00565       }
00566 
00567       
00575       size_t
00576       rows() const {return m_rows;}
00577 
00578 
00592       Type&
00593       setElement(size_t index0, const Type& value) {
00594         return this->operator()(index0) = value;
00595       }
00596 
00597 
00614       Type&
00615       setElement(size_t row, size_t column, const Type& value) {
00616         return this->operator()(row, column) = value;
00617       }
00618 
00619 
00628       Array1D<size_t>
00629       shape() const;
00630 
00642       size_t
00643       shape(size_t axis) const;
00644 
00651       size_t
00652       size() const {return m_size;}
00653 
00660       Array2D<Type>
00661       transpose() const;
00662     
00671       Array2D<Type>&
00672       operator=(const Array2D<Type>& source);
00673 
00681       Array2D<Type>&
00682       operator=(Type value);
00683 
00692       Type&
00693       operator()(size_t index) {
00694         this->checkBounds(index);
00695         return m_dataPtr[index];
00696       }
00697 
00704       Type operator()(size_t index) const {
00705         this->checkBounds(index);
00706         return m_dataPtr[index];
00707       }
00708   
00718       Type&
00719       operator()(size_t row, size_t column) {
00720         this->checkBounds(row, column);
00721         return m_dataPtr[column + row * m_columns];
00722       }
00723     
00733       Type
00734       operator()(size_t row, size_t column) const {
00735         this->checkBounds(row, column);
00736         return m_dataPtr[column + row * m_columns];
00737       }
00738 
00747       Type&
00748       operator[](size_t index) {return this->operator()(index);}
00749   
00758       Type
00759       operator[](size_t index) const {return this->operator()(index);}
00760 
00772       template <class Type2> Array2D<Type>&
00773       operator+=(const Array2D<Type2>& arg);
00774       
00786       template <class Type2> Array2D<Type>&
00787       operator-=(const Array2D<Type2>& arg);
00788 
00800       template <class Type2> Array2D<Type>&
00801       operator*=(const Array2D<Type2>& arg);
00802 
00814       template <class Type2> Array2D<Type>&
00815       operator/=(const Array2D<Type2>& arg);
00816     
00824       Array2D<Type>&
00825       operator+=(Type arg);
00826 
00834       Array2D<Type>&
00835       operator-=(Type arg);
00836 
00844       Array2D<Type>&
00845       operator*=(Type arg);
00846 
00854       Array2D<Type>&
00855       operator/=(Type arg);
00856 
00857     private:
00858       /* ******** Private member functions ******** */
00859       void
00860       allocate();
00861     
00862       // Optionally throw an exception if index is beyond the range of
00863       // this array.
00864       inline void
00865       checkBounds(size_t index) const;
00866 
00867       // Optionally throw an exception if either index is beyond the
00868       // range of this array.
00869       inline void
00870       checkBounds(size_t row, size_t column) const;
00871 
00872       void
00873       deAllocate();
00874 
00875       // Constants to help with formatting.  We use the initialization
00876       // on first use paradigm for the string constants to avoid
00877       // headaches.
00878 
00883       static const std::string& ioIntro(); 
00884 
00889       static const std::string& ioOutro();
00890 
00895       static const char ioOpening = '[';
00896 
00901       static const char ioClosing = ']';
00902 
00907       static const char ioSeparator = ',';
00908 
00909     
00910       /* ********Private data members******** */
00911       size_t m_rows;
00912       size_t m_columns;
00913       size_t m_size;
00914       Type* m_dataPtr;
00915       size_t* m_refCountPtr;
00916       bool m_isAllocated;
00917     
00918     };
00919   
00920     /* Non-member functions which will ultimately wind up in a different file */
00921 
00932     template <class Type>
00933     Array2D<Type>
00934     squareRoot(const Array2D<Type>& array0);
00935   
00947     template <class Type>
00948     inline Array2D<Type>
00949     sqrt(const Array2D<Type>& array0);
00950 
00964     template <class Type>
00965     Array2D<Type>
00966     operator+(const Array2D<Type>& array0,
00967               const Array2D<Type>& array1);
00968   
00982     template <class Type>
00983     Array2D<Type>
00984     operator-(const Array2D<Type>& array0,
00985               const Array2D<Type>& array1);
00986   
01000     template <class Type>
01001     Array2D<Type>
01002     operator*(const Array2D<Type>& array0,
01003               const Array2D<Type>& array1);
01004   
01018     template <class Type>
01019     Array2D<Type>
01020     operator/(const Array2D<Type>& array0,
01021               const Array2D<Type>& array1);
01022   
01034     template <class Type>
01035     Array2D<Type>
01036     operator+(const Array2D<Type>& array0, Type scalar);
01037   
01049     template <class Type>
01050     Array2D<Type>
01051     operator-(const Array2D<Type>& array0, Type scalar);
01052   
01064     template <class Type>
01065     Array2D<Type>
01066     operator*(const Array2D<Type>& array0, Type scalar);
01067   
01079     template <class Type>
01080     Array2D<Type>
01081     operator/(const Array2D<Type>& array0, Type scalar);
01082 
01094     template <class Type>
01095     inline Array2D<Type>
01096     operator+(Type scalar, const Array2D<Type>& array0);
01097   
01098 
01110     template <class Type>
01111     inline Array2D<Type>
01112     operator*(Type scalar, const Array2D<Type>& array0);
01113 
01114 
01126     template <class Type>
01127     Array2D<bool>
01128     operator==(const Array2D<Type>& array0, const Type arg);
01129 
01130     
01143     template <class Type>
01144     Array2D<bool>
01145     operator==(const Array2D<Type>& array0, const Array2D<Type>& array1);
01146     
01147 
01159     template <class Type>
01160     Array2D<bool>
01161     operator>(const Array2D<Type>& array0, Type arg);
01162 
01163   
01175     template <class Type>
01176     Array2D<bool>
01177     operator<(const Array2D<Type>& array0, Type arg);
01178 
01179   
01192     template <class Type>
01193     Array2D<bool>
01194     operator>=(const Array2D<Type>& array0, Type arg);
01195 
01196   
01209     template <class Type>
01210     Array2D<bool>
01211     operator<=(const Array2D<Type>& array0, Type arg);
01212 
01213   
01232     template <class Type>
01233     std::ostream&
01234     operator<<(std::ostream& stream, const Array2D<Type>& array0);
01235 
01247     template <class Type>
01248     std::istream&
01249     operator>>(std::istream& stream, Array2D<Type>& array0);
01250   
01251   } // namespace numeric
01252 
01253 } // namespace dlr
01254 
01255 
01256 /* ======= Declarations to maintain compatibility with legacy code. ======= */
01257 
01258 namespace dlr {
01259 
01260   using numeric::Array2D;
01261 
01262 } // namespace dlr
01263 
01264 
01265 /*******************************************************************
01266  * Member function definitions follow.  This would be a .C file
01267  * if it weren't templated.
01268  *******************************************************************/
01269 
01270 #include <algorithm>
01271 #include <functional>
01272 #include <sstream>
01273 #include <vector>
01274 #include <dlrCommon/functional.h>
01275 #include <dlrCommon/inputStream.h>
01276 #include <dlrNumeric/numericTraits.h>
01277 #include <dlrNumeric/functional.h>
01278 
01279 namespace dlr {
01280 
01281   namespace numeric {
01282     
01283     // Static constant describing how the string representation of an
01284     // Array2D should start.
01285     template <class Type>
01286     const std::string&
01287     Array2D<Type>::
01288     ioIntro()
01289     {
01290       static const std::string intro = "Array2D(";
01291       return intro;
01292     }
01293 
01294     // Static constant describing how the string representation of an
01295     // Array2D should end.
01296     template <class Type>
01297     const std::string&
01298     Array2D<Type>::
01299     ioOutro()
01300     {
01301       static const std::string outro = ")";
01302       return outro;
01303     }
01304 
01305     // Non-static member functions below.
01306 
01307     template <class Type>
01308     Array2D<Type>::
01309     Array2D()
01310       : m_rows(0),
01311         m_columns(0),
01312         m_size(0),
01313         m_dataPtr(0),
01314         m_refCountPtr(0),
01315         m_isAllocated(false)
01316     {
01317       // Empty
01318     }
01319 
01320     template <class Type>
01321     Array2D<Type>::
01322     Array2D(size_t rows, size_t columns)
01323       : m_rows(rows),
01324         m_columns(columns),
01325         m_size(0),          // This will be set in the call to allocate().
01326         m_dataPtr(0),       // This will be set in the call to allocate().
01327         m_refCountPtr(0),   // This will be set in the call to allocate().
01328         m_isAllocated(false)
01329     {
01330       this->allocate();
01331     }
01332 
01333   
01334     // Construct from an initialization string.
01335     template <class Type>
01336     Array2D<Type>::
01337     Array2D(const std::string& inputString)
01338       : m_rows(0),
01339         m_columns(0),
01340         m_size(0),
01341         m_dataPtr(0),
01342         m_refCountPtr(0),
01343         m_isAllocated(false)
01344     {
01345       // We'll use the stream input operator to parse the string.
01346       std::istringstream inputStream(inputString);
01347 
01348       // Now read the string into an array.
01349       Array2D<Type> inputArray;
01350       inputStream >> inputArray;
01351       if(!inputStream) {
01352         std::ostringstream message;
01353         message << "Couldn't parse input string: \"" << inputString << "\".";
01354         DLR_THROW3(ValueException, "Array2D::Array2D(const std::string&)",
01355                    message.str().c_str());                 
01356       }
01357 
01358       // If all went well, copy into *this.
01359       *this = inputArray;
01360     }
01361 
01362 
01363     /* When copying from a Array2D do a shallow copy */
01364     /* Update reference count if the array we're copying has */
01365     /* valid data. */
01366     template <class Type>
01367     Array2D<Type>::
01368     Array2D(const Array2D<Type>& source)
01369       : m_rows(source.m_rows),
01370         m_columns(source.m_columns),
01371         m_size(source.m_size),
01372         m_dataPtr(source.m_dataPtr),
01373         m_refCountPtr(source.m_refCountPtr),
01374         m_isAllocated(source.m_isAllocated)
01375     {
01376       if(m_isAllocated) {
01377         ++(*m_refCountPtr);
01378       }
01379     }
01380 
01381   
01382     /* Here's a constructor for getting image data into the array */
01383     /* cheaply. */
01384     template <class Type>
01385     Array2D<Type>::
01386     Array2D(size_t rows, size_t columns, Type* const dataPtr)
01387       : m_rows(rows),
01388         m_columns(columns),
01389         m_size(rows*columns),
01390         m_dataPtr(dataPtr),
01391         m_refCountPtr(0),
01392         m_isAllocated(false)
01393     {
01394       // Empty
01395     }
01396 
01397   
01398     // Construct an array around external data which was allocated by
01399     // an Array?D instance.
01400     template <class Type>
01401     Array2D<Type>::
01402     Array2D(size_t rows, size_t columns, Type* const dataPtr,
01403             size_t* refCountPtr)
01404       : m_rows(rows),
01405         m_columns(columns),
01406         m_size(rows*columns),
01407         m_dataPtr(dataPtr),
01408         m_refCountPtr(refCountPtr),
01409         m_isAllocated(true)
01410     {
01411       ++(*m_refCountPtr);
01412     }
01413 
01414   
01415     template <class Type>
01416     Array2D<Type>::
01417     ~Array2D()
01418     {
01419       deAllocate();
01420     }
01421 
01422   
01423     template <class Type>
01424     inline void Array2D<Type>::
01425     checkDimension(size_t rows, size_t columns) const
01426     {
01427 #ifdef _DLRNUMERIC_CHECKBOUNDS_
01428       if(rows != this->rows()
01429          || columns != this->columns()) {
01430         std::ostringstream message;
01431         message << "Size mismatch: required dimension is ("
01432                 << rows << ", " << columns << ") "
01433                 << " while *this has dimension "
01434                 << this->rows() << ", " << this->columns() << ").";
01435         DLR_THROW(IndexException, "Array2D::checkDimension()",
01436                   message.str().c_str());
01437       }
01438 #endif
01439     }
01440 
01441 
01442     template <class Type>
01443     Array2D<Type> Array2D<Type>::
01444     copy() const
01445     {
01446       Array2D<Type> newArray(m_rows, m_columns);
01447       newArray.copy(*this);
01448       return newArray;
01449     }
01450 
01451     template <class Type> template <class Type2>
01452     void Array2D<Type>::
01453     copy(const Array2D<Type2>& source)
01454     {
01455       if(source.size() != m_size) {
01456         std::ostringstream message;
01457         message << "Mismatched array sizes. Source array has "
01458                 << source.size() << " elements, while destination array has "
01459                 << m_size << " elements.";
01460         DLR_THROW3(ValueException, "Array2D::copy(const Array2D&)",
01461                    message.str().c_str());
01462       }
01463       if(m_size != 0) {
01464         this->copy(source.data());
01465       }
01466     }
01467 
01468     template <class Type> template <class Type2>
01469     void Array2D<Type>::
01470     copy(const Type2* dataPtr)
01471     {
01472       if(dataPtr == 0) {
01473         DLR_THROW(ValueException, "Array2D::copy(const Type2*)",
01474                   "Argument is a NULL pointer.");
01475       }
01476       std::transform(dataPtr, dataPtr + m_size, m_dataPtr,
01477                      StaticCastFunctor<Type2, Type>());
01478     }
01479 
01480 
01481     template <class Type>
01482     const Array1D<Type> Array2D<Type>::
01483     ravel() const
01484     {
01485       if(m_isAllocated) {
01486         return Array1D<Type>(m_size, m_dataPtr, m_refCountPtr);
01487       }
01488       return Array1D<Type>(m_size, m_dataPtr);
01489     }
01490 
01491     template <class Type>
01492     Array1D<Type> Array2D<Type>::
01493     ravel()
01494     {
01495       if(m_isAllocated) {
01496         return Array1D<Type>(m_size, m_dataPtr, m_refCountPtr);
01497       }
01498       return Array1D<Type>(m_size, m_dataPtr);
01499     }
01500 
01501 
01502     template <class Type>
01503     std::istream&
01504     Array2D<Type>::
01505     readFromStream(std::istream& inputStream)
01506     {
01507       // Most of the time, InputType will be the same as Type.
01508       typedef typename NumericTraits<Type>::TextOutputType InputType;
01509 
01510       // If stream is in a bad state, we can't read from it.
01511       if (!inputStream){
01512         return inputStream;
01513       }
01514     
01515       // It's a lot easier to use a try block than to be constantly
01516       // testing whether the IO has succeeded, so we tell inputStream to
01517       // complain if anything goes wrong.
01518       std::ios_base::iostate oldExceptionState = inputStream.exceptions();
01519       inputStream.exceptions(
01520         std::ios_base::badbit | std::ios_base::failbit | std::ios_base::eofbit);
01521 
01522       // Now on with the show.
01523       try{
01524         // Construct an InputStream instance so we can use our
01525         // convenience functions.
01526         InputStream stream(inputStream);
01527 
01528         // Skip any preceding whitespace.
01529         stream.skipWhiteSpace();
01530       
01531         // We won't require the input format to start with "Array2D(", but
01532         // if it does we read it here.
01533         bool foundIntro = false;
01534         if(stream.peek() == ioIntro()[0]) {
01535           foundIntro = true;
01536           stream.expect(ioIntro());
01537         }
01538 
01539         // OK.  We've dispensed with the intro.  What's left should be of
01540         // the format "[row, row, row, ...]".  We require the square
01541         // brackets to be there.
01542         stream.expect(ioOpening);
01543 
01544         // Read the data.  We'll use the Array1D<Type> stream operator to
01545         // read each row.
01546         Array1D<Type> inputValue;
01547         std::vector< Array1D<Type> > inputBuffer;
01548         while(1) {
01549           // Read the next row.
01550           stream >> inputValue;
01551           inputBuffer.push_back(inputValue);
01552 
01553           // Read the separator, or else the closing character.
01554           char inChar = 0;
01555           stream >> inChar;
01556           if(inChar == ioClosing) {
01557             // Found a closing.  Stop here.
01558             break;
01559           }
01560           if(inChar != ioSeparator) {
01561             // Missing separator?  Fail here.
01562             stream.clear(std::ios_base::failbit);
01563           }
01564         }
01565     
01566         // If we found an intro, we expect the corresponding outro.
01567         if(foundIntro) {
01568           stream.expect(ioOutro());
01569         }
01570 
01571         // Now we're done with all of the parsing, verify that all rows
01572         // have the same length.
01573         size_t rows = inputBuffer.size();
01574         size_t columns = ((inputBuffer.size() != 0) ? inputBuffer[0].size() : 0);
01575         for(size_t index = 1; index < rows; ++index) {
01576           if(inputBuffer[index].size() != columns) {
01577             // Inconsistent row lengths!  Fail here.
01578             stream.clear(std::ios_base::failbit);
01579           }
01580         }
01581 
01582         // And finally, copy the data.
01583         this->reinit(rows, columns);
01584         for(size_t index = 0; index < rows; ++index) {
01585           std::copy(inputBuffer[index].begin(), inputBuffer[index].end(),
01586                     this->begin() + (index * columns));
01587         }
01588       } catch(std::ios_base::failure) {
01589         // Empty
01590       }
01591       inputStream.exceptions(oldExceptionState);
01592       return inputStream;
01593     }
01594   
01595 
01596     template <class Type>
01597     void Array2D<Type>::
01598     reinit(size_t rows, size_t columns)
01599     {
01600       this->deAllocate();
01601       this->m_rows = rows;
01602       this->m_columns = columns;
01603       this->allocate();
01604     }
01605 
01606 
01607     /* After reshaping, matrix is still row major order */
01608     template <class Type>
01609     void Array2D<Type>::
01610     reshape(int rows, int columns)
01611     {
01612       // If one axis is specified as -1, it will be automatically 
01613       // chosen to match the number of elements in the array.
01614       if((rows == -1) && (columns != 0)) {
01615         rows = static_cast<int>(this->size()) / columns;
01616       } else
01617         if((columns == -1) && (rows != 0)) {
01618           columns = static_cast<int>(this->size()) / rows;
01619         }
01620       if((rows * columns) != static_cast<int>(this->size())) {
01621         std::ostringstream message;
01622         message << "Can't reshape a(n) " << this->size()
01623                 << " element array to have " << rows << " rows and "
01624                 << columns << " columns.";
01625         DLR_THROW(ValueException, "Array2D::reshape()", message.str().c_str());
01626       }
01627       m_rows = rows;
01628       m_columns = columns;
01629     }
01630 
01631   
01632     template <class Type>
01633     Array1D<Type> Array2D<Type>::
01634     row(size_t index)
01635     {
01636       this->checkBounds(index, 0);
01637       return Array1D<Type>(this->columns(),
01638                            m_dataPtr + (index * this->m_columns));
01639     }
01640 
01641   
01642     template <class Type>
01643     const Array1D<Type> Array2D<Type>::
01644     row(size_t index) const
01645     {
01646       this->checkBounds(index, 0);
01647       return Array1D<Type>(this->columns(),
01648                            m_dataPtr + (index * this->m_columns));
01649     }
01650 
01651 
01652     template <class Type>
01653     Array1D<size_t> Array2D<Type>::
01654     shape() const
01655     {
01656       Array1D<size_t> rc(2);
01657       rc(0) = this->rows();
01658       rc(1) = this->columns();
01659       return rc;
01660     }
01661 
01662 
01663     template <class Type>
01664     size_t Array2D<Type>::
01665     shape(size_t axis) const
01666     {
01667       size_t shape;
01668       switch(axis) {
01669       case 0:
01670         shape = this->rows();
01671         break;
01672       case 1:
01673         shape = this->columns();
01674         break;
01675       default:
01676         std::ostringstream message;
01677         message << "Invalid Axis: "<< axis << ".";
01678         DLR_THROW(ValueException, "Array2D::shape(size_t)",
01679                   message.str().c_str());
01680         shape = 0;
01681         break;
01682       }
01683       return shape;
01684     }
01685 
01686 
01687     template <class Type>
01688     Array2D<Type>& Array2D<Type>::
01689     operator=(Type value)
01690     {
01691       std::fill(m_dataPtr, m_dataPtr + m_size, value);
01692       return *this;
01693     }
01694 
01695   
01696     template <class Type>
01697     Array2D<Type>& Array2D<Type>::
01698     operator=(const Array2D<Type>& source)
01699     {
01700       // Check for self-assignment
01701       if(&source != this) {
01702         this->deAllocate();
01703         m_rows = source.m_rows;
01704         m_columns = source.m_columns;
01705         m_size = source.m_size;
01706         m_dataPtr = source.m_dataPtr;
01707         m_refCountPtr = source.m_refCountPtr;
01708         m_isAllocated = source.m_isAllocated;
01709         if(m_isAllocated) {
01710           ++(*m_refCountPtr);
01711         }
01712       }
01713       return *this;
01714     }
01715 
01716 
01717     template <class Type> template <class Type2>
01718     Array2D<Type>&
01719     Array2D<Type>::
01720     operator+=(const Array2D<Type2>& arg)
01721     {
01722       if(m_size != arg.size()) {
01723         std::ostringstream message;
01724         message << "Mismatched array sizes. Argument array is "
01725                 << arg.rows() << " x " << arg.columns()
01726                 << ", while destination array is "
01727                 << m_rows << " x " << m_columns << ".";
01728         DLR_THROW(ValueException, "Array2D::operator+=()",
01729                   message.str().c_str());
01730       }
01731       std::transform(m_dataPtr, m_dataPtr + m_size, arg.data(), m_dataPtr,
01732                      std::plus<Type>());
01733       return *this;
01734     }
01735 
01736 
01737     template <class Type> template <class Type2>
01738     Array2D<Type>&
01739     Array2D<Type>::
01740     operator-=(const Array2D<Type2>& arg)
01741     {
01742       if(m_size != arg.size()) {
01743         std::ostringstream message;
01744         message << "Mismatched array sizes. Argument array is "
01745                 << arg.rows() << " x " << arg.columns()
01746                 << ", while destination array is "
01747                 << m_rows << " x " << m_columns << ".";
01748         DLR_THROW(ValueException, "Array2D::operator-=()",
01749                   message.str().c_str());
01750       }
01751       std::transform(m_dataPtr, m_dataPtr + m_size, arg.data(), m_dataPtr,
01752                      std::minus<Type>());
01753       return *this;
01754     }
01755 
01756 
01757     template <class Type> template <class Type2>
01758     Array2D<Type>&
01759     Array2D<Type>::
01760     operator*=(const Array2D<Type2>& arg)
01761     {
01762       if(m_size != arg.size()) {
01763         std::ostringstream message;
01764         message << "Mismatched array sizes. Argument array is "
01765                 << arg.rows() << " x " << arg.columns()
01766                 << ", while destination array is "
01767                 << m_rows << " x " << m_columns << ".";
01768         DLR_THROW(ValueException, "Array2D::operator*=()",
01769                   message.str().c_str());
01770       }
01771       std::transform(m_dataPtr, m_dataPtr + m_size, arg.data(), m_dataPtr,
01772                      std::multiplies<Type>());
01773       return *this;
01774     }
01775 
01776 
01777     template <class Type> template <class Type2>
01778     Array2D<Type>&
01779     Array2D<Type>::
01780     operator/=(const Array2D<Type2>& arg)
01781     {
01782       if(m_size != arg.size()) {
01783         std::ostringstream message;
01784         message << "Mismatched array sizes. Argument array is "
01785                 << arg.rows() << " x " << arg.columns()
01786                 << ", while destination array is "
01787                 << m_rows << " x " << m_columns << ".";
01788         DLR_THROW(ValueException, "Array2D::operator/=()",
01789                   message.str().c_str());
01790       }
01791       std::transform(m_dataPtr, m_dataPtr + m_size, arg.data(), m_dataPtr,
01792                      std::divides<Type>());
01793       return *this;
01794     }
01795 
01796 
01797     template <class Type>
01798     Array2D<Type>&
01799     Array2D<Type>::
01800     operator*=(Type arg)
01801     {
01802       std::transform(m_dataPtr, m_dataPtr + m_size, m_dataPtr,
01803                      std::bind2nd(std::multiplies<Type>(), arg));
01804       return *this;
01805     }
01806 
01807 
01808     template <class Type>
01809     Array2D<Type>&
01810     Array2D<Type>::
01811     operator/=(Type arg)
01812     {
01813       std::transform(m_dataPtr, m_dataPtr + m_size, m_dataPtr,
01814                      std::bind2nd(std::divides<Type>(), arg));
01815       return *this;
01816     }
01817 
01818 
01819     template <class Type>
01820     Array2D<Type>&
01821     Array2D<Type>::
01822     operator+=(Type arg)
01823     {
01824       std::transform(m_dataPtr, m_dataPtr + m_size, m_dataPtr,
01825                      std::bind2nd(std::plus<Type>(), arg));
01826       return *this;
01827     }
01828 
01829 
01830     template <class Type>
01831     Array2D<Type>&
01832     Array2D<Type>::
01833     operator-=(Type arg)
01834     {
01835       std::transform(m_dataPtr, m_dataPtr + m_size, m_dataPtr,
01836                      std::bind2nd(std::minus<Type>(), arg));
01837       return *this;
01838     }
01839 
01840 
01841     template <class Type>
01842     Array2D<Type> Array2D<Type>::
01843     transpose() const
01844     {
01845       Array2D<Type> newMx(m_columns, m_rows);
01846 
01847       // Waiting for row & column iterators
01848       Type *tPtr0 = newMx.m_dataPtr;
01849       for(size_t j = 0; j < m_columns; ++j) {
01850         // const Type *tPtr1 = this->data(0, j);
01851         const Type *tPtr1 = this->data(j);
01852         for(size_t i = 0; i < m_rows; ++i) {
01853           *tPtr0 = *tPtr1;
01854           ++tPtr0;
01855           tPtr1 += m_columns;
01856         }
01857       }
01858       return newMx;
01859     }
01860 
01861 
01862     template <class Type>
01863     void Array2D<Type>::
01864     allocate()
01865     {
01866       m_size = m_rows * m_columns;
01867       if(m_rows > 0 && m_columns > 0) {
01868         m_dataPtr = new(Type[m_rows * m_columns]); // should throw an exception
01869         m_refCountPtr = new size_t;                 // if we're out of memory.
01870         *m_refCountPtr = 1;
01871         m_isAllocated = true;
01872         return;
01873       }
01874       m_dataPtr = 0;
01875       m_refCountPtr = 0;
01876       m_isAllocated = false;
01877       return;
01878     }
01879 
01880 
01881     template <class Type>
01882     inline void Array2D<Type>::
01883     checkBounds(size_t index) const
01884     {
01885 #ifdef _DLRNUMERIC_CHECKBOUNDS_
01886       if(index < 0 || index >= m_size) {
01887         std::ostringstream message;
01888         message << "Index " << index << " is invalid for a(n) " << m_rows
01889                 << " x " << m_columns << " array.";
01890         DLR_THROW(IndexException, "Array2D::checkBounds(size_t)",
01891                   message.str().c_str());
01892       }
01893 #endif
01894     }
01895 
01896 
01897     template <class Type>
01898     inline void Array2D<Type>::
01899     checkBounds(size_t row, size_t column) const
01900     {
01901 #ifdef _DLRNUMERIC_CHECKBOUNDS_
01902       if(row < 0 || row >= m_rows) {
01903         std::ostringstream message;
01904         message << "Row index " << row << " is invalid for a(n) "
01905                 << m_rows << " x " << m_columns << " array.";
01906         DLR_THROW(IndexException, "Array2D::checkBounds(size_t, size_t)",
01907                   message.str().c_str());
01908       }
01909       if(column < 0 || column >= m_columns) {
01910         std::ostringstream message;
01911         message << "Column index " << column << " is invalid for a(n) "
01912                 << m_rows << " x " << m_columns << " array.";
01913         DLR_THROW(IndexException, "Array2D::checkBounds(size_t, size_t)",
01914                   message.str().c_str());
01915       }
01916 #endif
01917     }
01918 
01919 
01920     template <class Type>
01921     void Array2D<Type>::
01922     deAllocate()
01923     {
01924       if(m_isAllocated == true) {
01925         if(--(*m_refCountPtr) == 0) {
01926           delete[] m_dataPtr;
01927           delete m_refCountPtr;
01928           m_isAllocated = false;
01929           m_dataPtr = 0;
01930           m_refCountPtr = 0;
01931         }
01932       } else {
01933         m_dataPtr = 0;
01934         m_refCountPtr = 0;
01935       }
01936     }
01937 
01938     /* Non-member functions which will ultimately wind up in a different file */
01939 
01940     template <class Type>
01941     inline Array2D<Type>
01942     sqrt(const Array2D<Type>& array0)
01943     {
01944       return squareRoot(array0);
01945     }
01946 
01947     // This function returns an Array2D instance of the same shape and
01948     // element type as its input, in which each element contains the
01949     // square root of the corresponding element of the input array.
01950     template <class Type>
01951     Array2D<Type>
01952     squareRoot(const Array2D<Type>& array0)
01953     {
01954       Array2D<Type> result(array0.rows(), array0.columns());
01955       std::transform(array0.begin(), array0.end(),
01956                      result.begin(), SquareRootFunctor<Type>());
01957       return result;
01958     }
01959 
01960     template <class Type>
01961     Array2D<Type> operator+(const Array2D<Type>& array0,
01962                             const Array2D<Type>& array1)
01963     {
01964       if((array0.rows() != array1.rows())
01965          || (array0.columns() != array1.columns())) {
01966         std::ostringstream message;
01967         message << "Array sizes do not match.  Array0 is " << array0.rows()
01968                 << " x " << array0.columns() << ", while array1 is "
01969                 << array1.rows() << " x " << array1.columns() << ".";
01970         DLR_THROW(ValueException, "Array2D::operator+()", message.str().c_str());
01971       }
01972       Array2D<Type> result(array0.rows(), array0.columns());
01973       std::transform(array0.begin(), array0.end(), array1.begin(),
01974                      result.begin(), std::plus<Type>());
01975       return result;
01976     }
01977 
01978     template <class Type>
01979     Array2D<Type> operator-(const Array2D<Type>& array0,
01980                             const Array2D<Type>& array1)
01981     {
01982       if((array0.rows() != array1.rows())
01983          || (array0.columns() != array1.columns())) {
01984         std::ostringstream message;
01985         message << "Array sizes do not match.  Array0 is " << array0.rows()
01986                 << " x " << array0.columns() << ", while array1 is "
01987                 << array1.rows() << " x " << array1.columns() << ".";
01988         DLR_THROW(ValueException, "Array2D::operator-()", message.str().c_str());
01989       }
01990       Array2D<Type> result(array0.rows(), array0.columns());
01991       std::transform(array0.begin(), array0.end(), array1.begin(),
01992                      result.begin(), std::minus<Type>());
01993       return result;
01994     }
01995 
01996     template <class Type>
01997     Array2D<Type> operator*(const Array2D<Type>& array0,
01998                             const Array2D<Type>& array1)
01999     {
02000       if((array0.rows() != array1.rows())
02001          || (array0.columns() != array1.columns())) {
02002         std::ostringstream message;
02003         message << "Array sizes do not match.  Array0 is " << array0.rows()
02004                 << " x " << array0.columns() << ", while array1 is "
02005                 << array1.rows() << " x " << array1.columns() << ".";
02006         DLR_THROW(ValueException, "Array2D::operator*()", message.str().c_str());
02007       }
02008       Array2D<Type> result(array0.rows(), array0.columns());
02009       std::transform(array0.begin(), array0.end(), array1.begin(),
02010                      result.begin(), std::multiplies<Type>());
02011       return result;
02012     }
02013 
02014     template <class Type>
02015     Array2D<Type> operator/(const Array2D<Type>& array0,
02016                             const Array2D<Type>& array1)
02017     {
02018       if((array0.rows() != array1.rows())
02019          || (array0.columns() != array1.columns())) {
02020         std::ostringstream message;
02021         message << "Array sizes do not match.  Array0 is " << array0.rows()
02022                 << " x " << array0.columns() << ", while array1 is "
02023                 << array1.rows() << " x " << array1.columns() << ".";
02024         DLR_THROW(ValueException, "Array2D::operator/()", message.str().c_str());
02025       }
02026       Array2D<Type> result(array0.rows(), array0.columns());
02027       std::transform(array0.begin(), array0.end(), array1.begin(),
02028                      result.begin(), std::divides<Type>());
02029       return result;
02030     }
02031 
02032     template <class Type>
02033     Array2D<Type> operator+(const Array2D<Type>& array0, Type scalar)
02034     {
02035       Array2D<Type> result(array0.rows(), array0.columns());
02036       std::transform(array0.begin(), array0.end(), result.begin(),
02037                      std::bind2nd(std::plus<Type>(), scalar));
02038       return result;
02039     }
02040 
02041     template <class Type>
02042     Array2D<Type> operator-(const Array2D<Type>& array0, Type scalar)
02043     {
02044       Array2D<Type> result(array0.rows(), array0.columns());
02045       std::transform(array0.begin(), array0.end(), result.begin(),
02046                      std::bind2nd(std::minus<Type>(), scalar));
02047       return result;
02048     }
02049 
02050     template <class Type>
02051     Array2D<Type> operator*(const Array2D<Type>& array0, Type scalar)
02052     {
02053       Array2D<Type> result(array0.rows(), array0.columns());
02054       std::transform(array0.begin(), array0.end(), result.begin(),
02055                      std::bind2nd(std::multiplies<Type>(), scalar));
02056       return result;
02057     }
02058 
02059     template <class Type>
02060     Array2D<Type> operator/(const Array2D<Type>& array0, Type scalar)
02061     {
02062       Array2D<Type> result(array0.rows(), array0.columns());
02063       std::transform(array0.begin(), array0.end(), result.begin(),
02064                      std::bind2nd(std::divides<Type>(), scalar));
02065       return result;
02066     }
02067 
02068     template <class Type>
02069     inline Array2D<Type> operator+(Type scalar, const Array2D<Type>& array0)
02070     {
02071       return array0 + scalar;
02072     }
02073 
02074     template <class Type>
02075     inline Array2D<Type> operator*(Type scalar, const Array2D<Type>& array0)
02076     {
02077       return array0 * scalar;
02078     }
02079 
02080 
02081     // Elementwise comparison of an Array2D with a constant.
02082     template <class Type>
02083     Array2D<bool>
02084     operator==(const Array2D<Type>& array0, const Type arg)
02085     {
02086       Array2D<bool> result(array0.rows(), array0.columns());
02087       std::transform(array0.begin(), array0.end(), result.data(),
02088                      std::bind2nd(std::equal_to<Type>(), arg));
02089       return result;
02090     }
02091 
02092     
02093     // Elementwise comparison of an Array2D with another array.
02094     template <class Type>
02095     Array2D<bool>
02096     operator==(const Array2D<Type>& array0, const Array2D<Type>& array1)
02097     {
02098       array0.checkDimension(array1.rows(), array1.columns());
02099       Array2D<bool> result(array0.rows(), array0.columns());
02100       std::transform(array0.begin(), array0.end(), array1.begin(),
02101                      result.begin(), std::equal_to<Type>());
02102       return result;
02103     }
02104 
02105   
02106     template <class Type>
02107     Array2D<bool> operator>(const Array2D<Type>& array0, Type arg)
02108     {
02109       Array2D<bool> result(array0.rows(), array0.columns());
02110       std::transform(array0.begin(), array0.end(), result.begin(),
02111                      std::bind2nd(std::greater<Type>(), arg));
02112       return result;
02113     }
02114 
02115     template <class Type>
02116     Array2D<bool> operator<(const Array2D<Type>& array0, Type arg)
02117     {
02118       Array2D<bool> result(array0.rows(), array0.columns());
02119       std::transform(array0.begin(), array0.end(), result.begin(),
02120                      std::bind2nd(std::less<Type>(), arg));
02121       return result;
02122     }
02123 
02124     template <class Type>
02125     Array2D<bool> operator>=(const Array2D<Type>& array0, Type arg)
02126     {
02127       Array2D<bool> result(array0.rows(), array0.columns());
02128       std::transform(array0.begin(), array0.end(), result.begin(),
02129                      std::bind2nd(std::greater_equal<Type>(), arg));
02130       return result;
02131     }
02132 
02133     template <class Type>
02134     Array2D<bool> operator<=(const Array2D<Type>& array0, Type arg)
02135     {
02136       Array2D<bool> result(array0.rows(), array0.columns());
02137       std::transform(array0.begin(), array0.end(), result.begin(),
02138                      std::bind2nd(std::less_equal<Type>(), arg));
02139       return result;
02140     }
02141 
02142     template <class Type>
02143     std::ostream& operator<<(std::ostream& stream, const Array2D<Type>& array0)
02144     {
02145       // Most of the time, OutputType will be the same as Type.
02146       typedef typename NumericTraits<Type>::TextOutputType OutputType;
02147 
02148       stream << "Array2D([[";
02149       for(size_t row = 0; row < array0.rows(); ++row) {
02150         if (array0.columns() > 0) {
02151           for(size_t column = 0; column < array0.columns() - 1; ++column) {
02152             stream << static_cast<OutputType>(array0(row, column)) << ", ";
02153           }
02154           stream << static_cast<OutputType>(array0(row, array0.columns() - 1));
02155           if(row != array0.rows() - 1) {
02156             stream << "],\n";
02157             stream << "         [";
02158           }
02159         }
02160       } 
02161       stream << "]])";
02162       stream.flush();
02163       return stream;
02164     }
02165 
02166   
02167     template <class Type>
02168     std::istream& operator>>(std::istream& inputStream, Array2D<Type>& array0)
02169     {
02170       return array0.readFromStream(inputStream);
02171     }
02172   
02173   } // namespace numeric
02174 
02175 } // namespace dlr
02176 
02177 #endif /* #ifdef _DLR_ARRAY2D_H_ */

Generated on Tue Jun 24 16:48:37 2008 for dlrUtilities Utility Library by  doxygen 1.5.5