1 // @HEADER
2 // ***********************************************************************
3 //
4 //                    Teuchos: Common Tools Package
5 //                 Copyright (2004) Sandia Corporation
6 //
7 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
8 // license for use of this work by or on behalf of the U.S. Government.
9 //
10 // Redistribution and use in source and binary forms, with or without
11 // modification, are permitted provided that the following conditions are
12 // met:
13 //
14 // 1. Redistributions of source code must retain the above copyright
15 // notice, this list of conditions and the following disclaimer.
16 //
17 // 2. Redistributions in binary form must reproduce the above copyright
18 // notice, this list of conditions and the following disclaimer in the
19 // documentation and/or other materials provided with the distribution.
20 //
21 // 3. Neither the name of the Corporation nor the names of the
22 // contributors may be used to endorse or promote products derived from
23 // this software without specific prior written permission.
24 //
25 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
26 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
29 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 //
37 // Questions? Contact Michael A. Heroux (maherou@sandia.gov)
38 //
39 // ***********************************************************************
40 // @HEADER
41 
42 #ifndef TEUCHOS_TWODARRAY_HPP
43 #define TEUCHOS_TWODARRAY_HPP
44 
45 
46 /*! \file Teuchos_TwoDArray.hpp
47   \brief A thin wrapper around the Teuchos Array class that allows for
48   2 dimensional arrays.
49 */
50 
51 #include "Teuchos_Array.hpp"
52 
53 
54 namespace Teuchos{
55 
56 /**
57  * \brief A thin wrapper around the Array class which causes it to be interpreted
58  * as a 2D Array.
59  *
60  * 2D Array's can also be "symetric". This means that anyone viewing the
61  * Array should only consider the lower half of the array as valid. The
62  *
63  * \warning The TwoDArray will not enforce symetry. However, when two
64  * symmetrical TwoDArrays are compared, only the the lower half of the
65  * TwoDArray's will be compared.
66  */
67 template<class T>
68 class TwoDArray{
69 public:
70   /**
71    * \brief .
72    */
73   typedef Ordinal size_type;
74 
75   /** \name Constructors and Destructors */
76   //@{
77 
78   /**
79    * \brief Constructs a TwoDArray with the given number of rows and columns with each
80    * entry being populated with the specified value.
81    *
82    * @param numCols The number of columns in the TwoDArray.
83    * @param numRows The number of rows in the TwoDArray.
84    * @param value The value with which to populate the TwoDArray.
85    */
TwoDArray(size_type numRows,size_type numCols,T value=T ())86   TwoDArray(size_type numRows, size_type numCols, T value=T()):
87     _numRows(numRows),
88     _numCols(numCols),
89     _data(Array<T>(numCols*numRows, value)),
90     _symmetrical(false)
91     {}
92   /**
93    * \brief Constructs an empty TwoDArray.
94    */
TwoDArray()95   TwoDArray():
96     _numRows(0),_numCols(0),_data(Array<T>()),_symmetrical(false){}
97 
98   /** \brief . */
~TwoDArray()99   virtual ~TwoDArray(){}
100 
101   //@}
102 
103   /** \name Getters and Setters */
104   //@{
105 
106   /** \brief Returns an ArrayView containing the contents of row i */
107   inline ArrayView<T> operator[](size_type i);
108 
109   /** \brief Returns a const ArrayView containing the contents of row i */
110   inline ArrayView<const T> operator[](size_type i) const;
111 
112   /** \brief returns the number of rows in the TwoDArray. */
getNumRows() const113   inline size_type getNumRows() const{
114     return _numRows;
115   }
116 
117   /** \brief returns the number of columns in the TwoDArray. */
getNumCols() const118   inline size_type getNumCols() const{
119     return _numCols;
120   }
121 
122   /** \brief Returns the 1D array that is backing this TwoDArray. */
getDataArray() const123   inline const Array<T>& getDataArray() const{
124     return _data;
125   }
126 
127   /** \brief Returns the element located at i,j */
operator ()(size_type i,size_type j)128   inline T& operator()(size_type i, size_type j){
129     return _data[(i*_numCols)+j];
130   }
131 
132   /** \brief Returns the element located at i,j */
operator ()(size_type i,size_type j) const133   inline const T& operator()(size_type i, size_type j) const{
134     return _data[(i*_numCols)+j];
135   }
136 
137   /** \brief delets all the entries from the TwoDArray */
clear()138   inline void clear(){
139     _data.clear();
140     _numRows =0;
141     _numCols =0;
142   }
143 
isEmpty()144   inline bool isEmpty(){
145     return _numRows == 0 &&
146       _numCols == 0 &&
147       _data.size() == 0;
148   }
149 
150   /** \brief A simple flag indicating whether or not
151    * this TwoDArray should be interpurted as symmetrical.
152    *
153    * \note A symmetrical TwoDArray is defined as an TwoDArray where
154    * entry i,j is the same as entry j,i.
155    *
156    * \note This does not change any of the TwoDArrays behavior.
157    * It merely serves as an indicator to any one using a TwoDArray
158    * that the TwoDArray can be read as if it were symmetrical. In other words,
159    * the TwoDArray class does not enforce the symetry.
160    *
161    * @return True if the array is "symmetrical", false otherwise.
162    */
isSymmetrical() const163   inline bool isSymmetrical() const{
164     return _symmetrical;
165   }
166 
167   /**
168    * \brief Sets whether or not the the TwoDArray should be
169    * interpurted as symetric.
170    *
171    * \note A symmetrical TwoDArray is defined as an TwoDArray where
172    * entry i,j is the same as entry j,i.
173    *
174    * \note This does not change any of the TwoDArrays behavior.
175    * It merely serves as an indicator to any one using a TwoDArray
176    * that the TwoDArray can be read as if it were symmetrical. In other words,
177    * the TwoDArray class does not enforce the symetry.
178    *
179    * @param symmetrical Whether or not the matrix should be interpurted
180    * as symetric.
181    */
setSymmetrical(bool symmetrical)182   inline void setSymmetrical(bool symmetrical){
183     _symmetrical = symmetrical;
184   }
185 
186   //@}
187 
188   /** @name Resizing Functions */
189   //@{
190 
191   /** \brief Changes the number of rows in the matrix.
192    *
193    * If the new number of rows is less than the current number, the
194    * last rows in the array will be deleted (i.e. if an array has 10 rows and
195    * it is resized to have only 5 rows, rows 5-9 are deleted). If the new number
196    * of rows is greater than the current number of rows, the rows are appended on
197    * to the end of the array and the new entries are initialized to T's
198    * default value.
199    *
200    * @param numberOfRows The new number of rows the TwoDArray should have.
201    */
202   void resizeRows(size_type numberOfRows);
203 
204   /** \brief Changes the number of rows in the matrix.
205    *
206    * If the new number of columns is less than the current number, the
207    * last columns in the array will be deleted (i.e. if an array has 10 columns and
208    * it is resized to have only 5 columns, columns 5-9 are deleted). If the new number
209    * of columns is greater than the current number of columns, the columns are appended on
210    * to the end of the array and the new entries are initialized to T's default value.
211    *
212    * \warning This operation has the potential to be very expensive
213    * as it essentially creates an entirely new 2DArray.
214    * Please take this into account when using this function.
215    *
216    * @param numberOfCols The new number of rows the TwoDArray should have.
217    */
218   void resizeCols(size_type numberOfCols);
219 
220   //@}
221 
222 
223   /** \name String conversion functions */
224   //@{
225 
226   /** \brief returns the string used to seperate meta information from
227    * actual data information when converting a TwoDArray to a string.
228    */
getMetaSeperator()229   static const std::string& getMetaSeperator(){
230     static const std::string metaSeperator = ":";
231     return metaSeperator;
232   }
233 
234   /** \brief returns the string used as the dimension dilimeter when convering
235    * the TwoDArray to a string.
236    */
getDimensionsDelimiter()237   static const std::string& getDimensionsDelimiter(){
238     static const std::string dimensionsDelimiter = "x";
239     return dimensionsDelimiter;
240   }
241 
242   /** \brief Converts a given TwoDArray to a valid string representation. */
243   static std::string toString(const TwoDArray<T> array);
244 
245   /** \brief Converts a valid string to it's corresponding TwoDArray. */
246   static TwoDArray<T> fromString(const std::string& string);
247 
248   //@}
249 
250 private:
251   size_type _numRows,_numCols;
252   Array<T> _data;
TwoDArray(size_type numRows,size_type numCols,Array<T> data)253   TwoDArray(size_type numRows, size_type numCols, Array<T> data):
254     _numRows(numRows),
255     _numCols(numCols),
256     _data(data),
257     _symmetrical(false)
258   {}
259 
260   bool _symmetrical;
261 };
262 
263 template<class T> inline
operator [](size_type i)264 ArrayView<T> TwoDArray<T>::operator[](size_type i){
265   return _data.view(_numCols*i, _numCols);
266 }
267 
268 template<class T> inline
operator [](size_type i) const269 ArrayView<const T> TwoDArray<T>::operator[](size_type i) const{
270   return _data.view(_numCols*i, _numCols);
271 }
272 
273 template<class T>
resizeRows(size_type numberOfRows)274 void TwoDArray<T>::resizeRows(size_type numberOfRows){
275   _data.resize(_numCols*numberOfRows);
276   _numRows = numberOfRows;
277 }
278 
279 
280 template<class T>
resizeCols(size_type numberOfCols)281 void TwoDArray<T>::resizeCols(size_type numberOfCols){
282   Array<T> newData(numberOfCols*_numRows);
283   size_type colLimit = (numberOfCols < _numCols ? numberOfCols : _numCols);
284   for(size_type i = 0; i<_numRows; i++){
285     for(size_type j = 0; j<colLimit; j++){
286       newData[i*numberOfCols+j] = _data[i*_numCols+j];
287     }
288   }
289   _data = newData;
290   _numCols=numberOfCols;
291 }
292 
293 
294 template<class T>
toString(const TwoDArray<T> array)295 std::string TwoDArray<T>::toString(const TwoDArray<T> array){
296   std::stringstream numColsStream;
297   std::stringstream numRowsStream;
298   numColsStream << array.getNumCols();
299   numRowsStream << array.getNumRows();
300   std::string metaSeperator = TwoDArray<T>::getMetaSeperator();
301   return
302     numRowsStream.str() +
303     TwoDArray<T>::getDimensionsDelimiter() +
304     numColsStream.str() +
305     metaSeperator +
306     (array.isSymmetrical() ? "sym"+metaSeperator : "") +
307     array.getDataArray().toString();
308 }
309 
310 template<class T>
fromString(const std::string & string_in)311 TwoDArray<T> TwoDArray<T>::fromString(const std::string& string_in){
312   std::string curString = string_in;
313   std::string metaSeperator = TwoDArray<T>::getMetaSeperator();
314   size_t curPos = curString.find(metaSeperator);
315   std::string dimString = curString.substr(0, curPos);
316   curString = curString.substr(curPos+1);
317 
318   //process dimensions
319   size_t dimCharPos =
320     dimString.find(TwoDArray<T>::getDimensionsDelimiter());
321   std::istringstream numRowsStream(dimString.substr(0,dimCharPos));
322   std::istringstream numColsStream(dimString.substr(dimCharPos+1));
323   size_t numRows, numCols;
324   numRowsStream >> numRows;
325   numColsStream >> numCols;
326 
327   //determine symetry state
328   bool symmetrical = false;
329   curPos = curString.find(metaSeperator);
330   if(curPos != std::string::npos){
331     symmetrical = true;
332     curString = curString.substr(curPos+1);
333   }
334 
335   //Get actual data
336   Array<T> array = fromStringToArray<T>(curString);
337 
338   TEUCHOS_TEST_FOR_EXCEPTION(array.size() != (typename Array<T>::size_type)(numRows*numCols),
339     InvalidArrayStringRepresentation,
340     "Error: You've specified an TwoDArray as having the dimensions of "
341     << numRows << "x" << numCols << ". This means you should have " <<
342     (numRows*numCols) << " entries specified in your array. However you "
343     "only specified " << array.size() << " entries."
344   )
345 
346   //Construct object to return
347   TwoDArray<T> toReturn(numRows, numCols, array);
348   toReturn.setSymmetrical(symmetrical);
349   return toReturn;
350 }
351 
352 /* \brief .
353  * \relates TwoDArray
354  */
355 template<class T>
operator >>(std::istringstream & in,TwoDArray<T> & array)356 std::istringstream& operator>> (std::istringstream& in, TwoDArray<T>& array){
357   array = TwoDArray<T>::fromString(in.str());
358   return in;
359 }
360 
361 /* \brief .
362  * \relates TwoDArray
363  */
364 template<class T> inline
operator <<(std::ostream & os,const TwoDArray<T> & array)365 std::ostream& operator<<(std::ostream& os, const TwoDArray<T>& array){
366   return os << TwoDArray<T>::toString(array);
367 }
368 
369 
370 namespace TwoDDetails {
371 
372 /**
373  * \brief A function for comparing symmetrical arrarys.
374  *
375  * @param a1 The first array to compare.
376  * @param a2 The second array to compare.
377  * @return True if the two TwoDArrays are symmetricaly the same, false
378  * otherwise.
379  */
380 template<typename T>
symmetricCompare(const TwoDArray<T> & a1,const TwoDArray<T> & a2)381 bool symmetricCompare(const TwoDArray<T> &a1, const TwoDArray<T> &a2 ){
382   if(a1.getNumRows() != a2.getNumRows() ||
383     a1.getNumRows() != a2.getNumRows())
384   {
385     return false;
386   }
387   else{
388     typedef typename TwoDArray<T>::size_type ST;
389     for(ST i=0;i<a1.getNumRows(); ++i){
390       for(ST j=0;j<a1.getNumCols()-a1.getNumRows()+i; ++j){
391         if(a1(i,j) != a2(i,j)){
392           return false;
393         }
394       }
395     }
396     return true;
397   }
398 }
399 
400 
401 }
402 
403 /* \brief Returns true of the two TwoDArrays have the same contents and
404  * their dimensions are the same.
405  *
406  * \note If the arrays are symmetrical, only the values in the upper half
407  * of the array are compared. For example: in a 4x4 array, only the values
408  * indicated with x's in the figure below would be compared.
409  *
410  *   o o o o
411  *   x o o o
412  *   x x o o
413  *   x x x o
414  *
415  * \relates TwoDArray
416  */
417 template<typename T>
operator ==(const TwoDArray<T> & a1,const TwoDArray<T> & a2)418 bool operator==( const TwoDArray<T> &a1, const TwoDArray<T> &a2 ){
419   if(a1.isSymmetrical() != a2.isSymmetrical()){
420     return false;
421   }
422   if(a1.isSymmetrical()){
423     return TwoDDetails::symmetricCompare(a1,a2);
424   }
425   else{
426     return a1.getDataArray() == a2.getDataArray() &&
427     a1.getNumRows() == a2.getNumRows() &&
428     a1.getNumCols() == a2.getNumCols();
429   }
430 }
431 
432 /**
433  * \brief Get the format that is used for the specialization of the TypeName
434  * traits class for TwoDArray.
435  *
436  * The string returned will contain only one
437  * "*" character. The "*" character should then be replaced with the actual
438  * template type of the array.
439  * \relates TwoDArray.
440  */
441 inline
getTwoDArrayTypeNameTraitsFormat()442 std::string getTwoDArrayTypeNameTraitsFormat(){
443   return "TwoDArray(*)";
444 }
445 
446 /** \brief TypeNameTraits specialization for Array.  */
447 template<typename T>
448 class TEUCHOSCORE_LIB_DLL_EXPORT TypeNameTraits<TwoDArray<T> > {
449 public:
name()450   static std::string name(){
451     std::string formatString = getTwoDArrayTypeNameTraitsFormat();
452     size_t starPos = formatString.find("*");
453     std::string prefix = formatString.substr(0,starPos);
454     std::string postFix = formatString.substr(starPos+1);
455     return prefix+TypeNameTraits<T>::name()+postFix;
456   }
concreteName(const TwoDArray<T> &)457   static std::string concreteName(const TwoDArray<T>&)
458     { return name(); }
459 };
460 
461 } //namespace Teuchos
462 
463 
464 #endif // TEUCHOS_TWODARRAY_H
465