Teuchos - Trilinos Tools Package  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Teuchos_MatrixMarket_Banner.cpp
1 // @HEADER
2 // ***********************************************************************
3 //
4 // Tpetra: Templated Linear Algebra Services Package
5 // Copyright (2008) Sandia Corporation
6 //
7 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
8 // the U.S. Government retains certain rights in this software.
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 #include "Teuchos_MatrixMarket_Banner.hpp"
43 #include "Teuchos_MatrixMarket_split.hpp"
45 #include <algorithm>
46 #include <iostream>
47 #include <sstream>
48 #include <stdexcept>
49 
50 
51 namespace Teuchos {
52  namespace MatrixMarket {
53 
54  using details::split;
55  using details::trim_and_lowercase;
56 
57  std::string
58  Banner::validateObjectType (const std::string& objectType, const bool tolerant)
59  {
60  // Canonical representation is lowercase
61  std::string out = trim_and_lowercase (objectType);
62 
63  const char* const validValues[] = {"matrix"};
64  const int numValidValues = 1;
65  if (tolerant)
66  // This is the only value currently defined for this token in
67  // the Matrix Market format, so we just return it.
68  return std::string (validValues[0]);
69  else if (validValues + numValidValues ==
70  std::find (validValues, validValues + numValidValues, out))
71  throw std::invalid_argument("Object type \"" + out + "\" is "
72  "not one of the valid values");
73  else
74  return out;
75  }
76 
77  std::string
78  Banner::validateMatrixType (const std::string& matrixType, const bool /* tolerant */)
79  {
80  // Canonical representation is lowercase
81  std::string out = trim_and_lowercase (matrixType);
82 
83  const char* const validValues[] = {"coordinate", "array"};
84  const int numValidValues = 2;
85  if (validValues + numValidValues == std::find (validValues, validValues + numValidValues, out))
86  throw std::invalid_argument("Matrix type \"" + out + "\" is not one of the valid values");
87  else
88  return out;
89  }
90 
91  std::string
92  Banner::validateDataType (const std::string& dataType, const bool /* tolerant */)
93  {
94  // Canonical representation is lowercase
95  std::string out = trim_and_lowercase (dataType);
96 
97  const char* const validValues[] = {"real", "complex", "integer", "pattern"};
98  const int numValidValues = 4;
99  if (validValues + numValidValues == std::find (validValues, validValues + numValidValues, out))
100  throw std::invalid_argument("Data type \"" + out + "\" is not one of the valid values");
101  else
102  return out;
103  }
104 
105  std::string
106  Banner::validateSymmType (const std::string& symmType, const bool tolerant)
107  {
108  // Canonical representation is lowercase
109  std::string out = trim_and_lowercase (symmType);
110 
111  if (tolerant)
112  {
113  const char* const validValues[] =
114  {"general", "nonsymmetric", "unsymmetric", "symmetric",
115  "skew-symmetric", "skew", "hermitian"};
116  const int numValidValues = 7;
117  if (validValues + numValidValues == std::find (validValues, validValues + numValidValues, out))
118  throw std::invalid_argument("Symmetry type \"" + out + "\" is not one of the valid values");
119  else
120  {
121  if (out == "nonsymmetric" || out == "unsymmetric")
122  return std::string("general");
123  else if (out == "skew")
124  return std::string("skew-symmetric");
125  else
126  return out;
127  }
128  }
129  else
130  {
131  const char* const validValues[] = {"general", "symmetric", "skew-symmetric", "hermitian"};
132  const int numValidValues = 4;
133  if (validValues + numValidValues == std::find (validValues, validValues + numValidValues, out))
134  throw std::invalid_argument("Symmetry type \"" + out + "\" is not one of the valid values");
135  else
136  return out;
137  }
138  }
139 
140 
141  void
142  Banner::setDefaults (const int howMany)
143  {
144  if (howMany >= 4)
145  objectType_ = "matrix";
146  if (howMany >= 3)
147  matrixType_ = "coordinate";
148  if (howMany >= 2)
149  dataType_ = "real";
150  if (howMany >= 1)
151  symmType_ = "general";
152  }
153 
154  Banner::Banner (const std::string& line, const bool tolerant)
155  {
156  size_t start;
157 
158  if (line.empty()) {
159  if (tolerant) {
160  setDefaults (4);
161  return;
162  }
163  else {
164  throw std::invalid_argument ("The banner line is empty");
165  }
166  }
167  start = line.find_first_not_of (" \t");
168  if (start == std::string::npos) {
169  if (tolerant) {
170  setDefaults (4);
171  return;
172  }
173  else {
174  throw std::invalid_argument ("The banner line contains only "
175  "whitespace characters");
176  }
177  }
178  else if (start != 0 && ! tolerant) {
179  // If tolerant, we allow the banner line to start with
180  // whitespace characters, and keep reading.
181  throw std::invalid_argument ("The banner line is not allowed to start "
182  "with whitespace characters");
183  }
184 
185  // Find "%%MatrixMarket" -- it should be the first thing in the
186  // banner line, and all other data should come after it.
187  // Optionally relax to allow any case, and possibly a space
188  // between "%%" and "MatrixMarket".
189  size_t ppStart = line.find ("%%", start);
190  size_t tokenStart;
191  if (ppStart == std::string::npos) {
192  if (tolerant) {
193  tokenStart = start; // Just ignore the missing %%
194  }
195  else {
196  TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, "The Matrix "
197  "Market file's banner line should always start with \"%%\". Here "
198  "is the offending line: " << std::endl << line);
199  }
200  }
201  else {
202  tokenStart = ppStart + 2;
203  if (tokenStart >= line.size()) {
204  // There's no banner information after the %%.
205  if (tolerant) {
206  setDefaults (4);
207  return;
208  }
209  else {
210  TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, "The Matrix "
211  "Market file's banner line needs to contain information after the "
212  "\"%%\" marker. Here is the offending line: " << std::endl << line);
213  }
214  }
215  }
216  //
217  // In tolerant mode, fill in missing tokens with their default
218  // values.
219  //
220  // After extracting the %%, search for the five tokens.
221  std::vector<std::string> tokens = split (line, " \t", 2);
222  const int numTokens = tokens.size();
223  if (numTokens < 1) {
224  if (tolerant) {
225  setDefaults (4);
226  return;
227  }
228  else {
229  TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, "The Matrix "
230  "Market file's banner line must always begin with the \"Matrix"
231  "Market\" keyword. Here is the offending line: " << std::endl
232  << line);
233  }
234  }
235  // In tolerant mode, just ignore the first token.
236  if (! tolerant && tokens[0] != "MatrixMarket") {
237  TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, "The Matrix "
238  "Market file's banner line must always begin with the \"Matrix"
239  "Market\" keyword. Here is the offending line: " << std::endl
240  << line);
241  }
242  if (numTokens < 5) {
243  if (tolerant) {
244  setDefaults (5 - numTokens); // how many defaults to set
245  }
246  else {
247  TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, "The Matrix "
248  "Market file's banner line must always have 5 tokens, but yours "
249  "only has " << numTokens << "token" << (numTokens != 1 ? "s" : "")
250  << ". Here is the offending line: " << std::endl << line);
251  }
252  }
253  if (numTokens >= 2) {
254  objectType_ = validateObjectType (tokens[1], tolerant);
255  }
256  if (numTokens >= 3) {
257  matrixType_ = validateMatrixType (tokens[2], tolerant);
258  }
259  if (numTokens >= 4) {
260  dataType_ = validateDataType (tokens[3], tolerant);
261  }
262  if (numTokens >= 5) {
263  symmType_ = validateSymmType (tokens[4], tolerant);
264  }
265  }
266 
267  std::ostream&
268  operator<< (std::ostream& out, const Banner& banner)
269  {
270  out << "%%MatrixMarket"
271  << " " << banner.objectType()
272  << " " << banner.matrixType()
273  << " " << banner.dataType()
274  << " " << banner.symmType();
275  return out;
276  }
277  } // namespace MatrixMarket
278 } // namespace Teuchos
279 
const std::string & matrixType() const
Storage type of the matrix.
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
Macro for throwing an exception with breakpointing to ease debugging.
const std::string & dataType() const
Data type of matrix entries.
const std::string & symmType() const
Symmetric storage type.
const std::string & objectType() const
The object type.
Banner(const std::string &line, const bool tolerant=false)
Standard test and throw macros.
Parse a Matrix Market banner line.