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