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 // Tpetra: Templated Linear Algebra Services Package
4 //
5 // Copyright 2008 NTESS and the Tpetra contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 // @HEADER
9 
10 #include "Teuchos_MatrixMarket_Banner.hpp"
11 #include "Teuchos_MatrixMarket_split.hpp"
13 #include <algorithm>
14 #include <iostream>
15 #include <sstream>
16 #include <stdexcept>
17 
18 
19 namespace Teuchos {
20  namespace MatrixMarket {
21 
22  using details::split;
23  using details::trim_and_lowercase;
24 
25  std::string
26  Banner::validateObjectType (const std::string& objectType, const bool tolerant)
27  {
28  // Canonical representation is lowercase
29  std::string out = trim_and_lowercase (objectType);
30 
31  const char* const validValues[] = {"matrix"};
32  const int numValidValues = 1;
33  if (tolerant)
34  // This is the only value currently defined for this token in
35  // the Matrix Market format, so we just return it.
36  return std::string (validValues[0]);
37  else if (validValues + numValidValues ==
38  std::find (validValues, validValues + numValidValues, out))
39  throw std::invalid_argument("Object type \"" + out + "\" is "
40  "not one of the valid values");
41  else
42  return out;
43  }
44 
45  std::string
46  Banner::validateMatrixType (const std::string& matrixType, const bool /* tolerant */)
47  {
48  // Canonical representation is lowercase
49  std::string out = trim_and_lowercase (matrixType);
50 
51  const char* const validValues[] = {"coordinate", "array"};
52  const int numValidValues = 2;
53  if (validValues + numValidValues == std::find (validValues, validValues + numValidValues, out))
54  throw std::invalid_argument("Matrix type \"" + out + "\" is not one of the valid values");
55  else
56  return out;
57  }
58 
59  std::string
60  Banner::validateDataType (const std::string& dataType, const bool /* tolerant */)
61  {
62  // Canonical representation is lowercase
63  std::string out = trim_and_lowercase (dataType);
64 
65  const char* const validValues[] = {"real", "complex", "integer", "pattern"};
66  const int numValidValues = 4;
67  if (validValues + numValidValues == std::find (validValues, validValues + numValidValues, out))
68  throw std::invalid_argument("Data type \"" + out + "\" is not one of the valid values");
69  else
70  return out;
71  }
72 
73  std::string
74  Banner::validateSymmType (const std::string& symmType, const bool tolerant)
75  {
76  // Canonical representation is lowercase
77  std::string out = trim_and_lowercase (symmType);
78 
79  if (tolerant)
80  {
81  const char* const validValues[] =
82  {"general", "nonsymmetric", "unsymmetric", "symmetric",
83  "skew-symmetric", "skew", "hermitian"};
84  const int numValidValues = 7;
85  if (validValues + numValidValues == std::find (validValues, validValues + numValidValues, out))
86  throw std::invalid_argument("Symmetry type \"" + out + "\" is not one of the valid values");
87  else
88  {
89  if (out == "nonsymmetric" || out == "unsymmetric")
90  return std::string("general");
91  else if (out == "skew")
92  return std::string("skew-symmetric");
93  else
94  return out;
95  }
96  }
97  else
98  {
99  const char* const validValues[] = {"general", "symmetric", "skew-symmetric", "hermitian"};
100  const int numValidValues = 4;
101  if (validValues + numValidValues == std::find (validValues, validValues + numValidValues, out))
102  throw std::invalid_argument("Symmetry type \"" + out + "\" is not one of the valid values");
103  else
104  return out;
105  }
106  }
107 
108 
109  void
110  Banner::setDefaults (const int howMany)
111  {
112  if (howMany >= 4)
113  objectType_ = "matrix";
114  if (howMany >= 3)
115  matrixType_ = "coordinate";
116  if (howMany >= 2)
117  dataType_ = "real";
118  if (howMany >= 1)
119  symmType_ = "general";
120  }
121 
122  Banner::Banner (const std::string& line, const bool tolerant)
123  {
124  size_t start;
125 
126  if (line.empty()) {
127  if (tolerant) {
128  setDefaults (4);
129  return;
130  }
131  else {
132  throw std::invalid_argument ("The banner line is empty");
133  }
134  }
135  start = line.find_first_not_of (" \t");
136  if (start == std::string::npos) {
137  if (tolerant) {
138  setDefaults (4);
139  return;
140  }
141  else {
142  throw std::invalid_argument ("The banner line contains only "
143  "whitespace characters");
144  }
145  }
146  else if (start != 0 && ! tolerant) {
147  // If tolerant, we allow the banner line to start with
148  // whitespace characters, and keep reading.
149  throw std::invalid_argument ("The banner line is not allowed to start "
150  "with whitespace characters");
151  }
152 
153  // Find "%%MatrixMarket" -- it should be the first thing in the
154  // banner line, and all other data should come after it.
155  // Optionally relax to allow any case, and possibly a space
156  // between "%%" and "MatrixMarket".
157  size_t ppStart = line.find ("%%", start);
158  size_t tokenStart;
159  if (ppStart == std::string::npos) {
160  if (tolerant) {
161  tokenStart = start; // Just ignore the missing %%
162  }
163  else {
164  TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, "The Matrix "
165  "Market file's banner line should always start with \"%%\". Here "
166  "is the offending line: " << std::endl << line);
167  }
168  }
169  else {
170  tokenStart = ppStart + 2;
171  if (tokenStart >= line.size()) {
172  // There's no banner information after the %%.
173  if (tolerant) {
174  setDefaults (4);
175  return;
176  }
177  else {
178  TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, "The Matrix "
179  "Market file's banner line needs to contain information after the "
180  "\"%%\" marker. Here is the offending line: " << std::endl << line);
181  }
182  }
183  }
184  //
185  // In tolerant mode, fill in missing tokens with their default
186  // values.
187  //
188  // After extracting the %%, search for the five tokens.
189  std::vector<std::string> tokens = split (line, " \t", 2);
190  const int numTokens = tokens.size();
191  if (numTokens < 1) {
192  if (tolerant) {
193  setDefaults (4);
194  return;
195  }
196  else {
197  TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, "The Matrix "
198  "Market file's banner line must always begin with the \"Matrix"
199  "Market\" keyword. Here is the offending line: " << std::endl
200  << line);
201  }
202  }
203  // In tolerant mode, just ignore the first token.
204  if (! tolerant && tokens[0] != "MatrixMarket") {
205  TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, "The Matrix "
206  "Market file's banner line must always begin with the \"Matrix"
207  "Market\" keyword. Here is the offending line: " << std::endl
208  << line);
209  }
210  if (numTokens < 5) {
211  if (tolerant) {
212  setDefaults (5 - numTokens); // how many defaults to set
213  }
214  else {
215  TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, "The Matrix "
216  "Market file's banner line must always have 5 tokens, but yours "
217  "only has " << numTokens << "token" << (numTokens != 1 ? "s" : "")
218  << ". Here is the offending line: " << std::endl << line);
219  }
220  }
221  if (numTokens >= 2) {
222  objectType_ = validateObjectType (tokens[1], tolerant);
223  }
224  if (numTokens >= 3) {
225  matrixType_ = validateMatrixType (tokens[2], tolerant);
226  }
227  if (numTokens >= 4) {
228  dataType_ = validateDataType (tokens[3], tolerant);
229  }
230  if (numTokens >= 5) {
231  symmType_ = validateSymmType (tokens[4], tolerant);
232  }
233  }
234 
235  std::ostream&
236  operator<< (std::ostream& out, const Banner& banner)
237  {
238  out << "%%MatrixMarket"
239  << " " << banner.objectType()
240  << " " << banner.matrixType()
241  << " " << banner.dataType()
242  << " " << banner.symmType();
243  return out;
244  }
245  } // namespace MatrixMarket
246 } // namespace Teuchos
247 
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.