Teuchos - Trilinos Tools Package Version of the Day
Loading...
Searching...
No Matches
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
19namespace 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
Standard test and throw macros.
Parse a Matrix Market banner line.
Banner(const std::string &line, const bool tolerant=false)
const std::string & symmType() const
Symmetric storage type.
const std::string & objectType() const
The object type.
const std::string & dataType() const
Data type of matrix entries.
const std::string & matrixType() const
Storage type of the matrix.
Smart reference counting pointer class for automatic garbage collection.
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
Macro for throwing an exception with breakpointing to ease debugging.
Matrix Market file utilities.
The Teuchos namespace contains all of the classes, structs and enums used by Teuchos,...