Tpetra Matrix/Vector Services Version of the Day
MatrixMarket_Banner.cpp
00001 // @HEADER
00002 // ***********************************************************************
00003 // 
00004 //          Tpetra: Templated Linear Algebra Services Package
00005 //                 Copyright (2008) Sandia Corporation
00006 // 
00007 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
00008 // the U.S. Government retains certain rights in this software.
00009 // 
00010 // Redistribution and use in source and binary forms, with or without
00011 // modification, are permitted provided that the following conditions are
00012 // met:
00013 //
00014 // 1. Redistributions of source code must retain the above copyright
00015 // notice, this list of conditions and the following disclaimer.
00016 //
00017 // 2. Redistributions in binary form must reproduce the above copyright
00018 // notice, this list of conditions and the following disclaimer in the
00019 // documentation and/or other materials provided with the distribution.
00020 //
00021 // 3. Neither the name of the Corporation nor the names of the
00022 // contributors may be used to endorse or promote products derived from
00023 // this software without specific prior written permission.
00024 //
00025 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
00026 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00027 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
00028 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
00029 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00030 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00031 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00032 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00033 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00034 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00035 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00036 //
00037 // Questions? Contact Michael A. Heroux (maherou@sandia.gov) 
00038 // 
00039 // ************************************************************************
00040 // @HEADER
00041 
00042 #include "MatrixMarket_Banner.hpp"
00043 #include "MatrixMarket_split.hpp"
00044 #include <algorithm>
00045 #include <iostream>
00046 #include <sstream>
00047 #include <stdexcept>
00048 
00049 namespace Tpetra {
00050   namespace MatrixMarket {
00051 
00052     using details::split;
00053     using details::trim_and_lowercase;
00054 
00055     std::string
00056     Banner::validateObjectType (const std::string& objectType, const bool tolerant)
00057     {
00058       // Canonical representation is lowercase
00059       std::string out = trim_and_lowercase (objectType);
00060 
00061       const char* const validValues[] = {"matrix"};
00062       const int numValidValues = 1;
00063       if (tolerant)
00064   // This is the only value currently defined for this token in
00065   // the Matrix Market format, so we just return it.
00066   return std::string (validValues[0]);
00067       else if (validValues + numValidValues == 
00068          std::find (validValues, validValues + numValidValues, out))
00069   throw std::invalid_argument("Object type \"" + out + "\" is "
00070             "not one of the valid values");
00071       else
00072   return out;
00073     }
00074 
00075     std::string 
00076     Banner::validateMatrixType (const std::string& matrixType, const bool tolerant)
00077     {
00078       // Canonical representation is lowercase
00079       std::string out = trim_and_lowercase (matrixType);
00080     
00081       const char* const validValues[] = {"coordinate", "array"};
00082       const int numValidValues = 2;
00083       if (validValues + numValidValues == std::find (validValues, validValues + numValidValues, out))
00084   throw std::invalid_argument("Matrix type \"" + out + "\" is not one of the valid values");
00085       else
00086   return out;
00087     }
00088 
00089     std::string 
00090     Banner::validateDataType (const std::string& dataType, const bool tolerant)
00091     {
00092       // Canonical representation is lowercase
00093       std::string out = trim_and_lowercase (dataType);
00094     
00095       const char* const validValues[] = {"real", "complex", "integer", "pattern"};
00096       const int numValidValues = 4;
00097       if (validValues + numValidValues == std::find (validValues, validValues + numValidValues, out))
00098   throw std::invalid_argument("Data type \"" + out + "\" is not one of the valid values");
00099       else
00100   return out;
00101     }
00102 
00103     std::string 
00104     Banner::validateSymmType (const std::string& symmType, const bool tolerant)
00105     {
00106       // Canonical representation is lowercase
00107       std::string out = trim_and_lowercase (symmType);
00108 
00109       if (tolerant)
00110   {
00111     const char* const validValues[] = 
00112       {"general", "nonsymmetric", "unsymmetric", "symmetric", 
00113        "skew-symmetric", "skew", "hermitian"};
00114     const int numValidValues = 7;
00115     if (validValues + numValidValues == std::find (validValues, validValues + numValidValues, out))
00116       throw std::invalid_argument("Symmetry type \"" + out + "\" is not one of the valid values");
00117     else
00118       {
00119         if (out == "nonsymmetric" || out == "unsymmetric")
00120     return std::string("general");
00121         else if (out == "skew")
00122     return std::string("skew-symmetric");       
00123         else
00124     return out;
00125       }
00126   }
00127       else
00128   {
00129     const char* const validValues[] = {"general", "symmetric", "skew-symmetric", "hermitian"};
00130     const int numValidValues = 4;
00131     if (validValues + numValidValues == std::find (validValues, validValues + numValidValues, out))
00132       throw std::invalid_argument("Symmetry type \"" + out + "\" is not one of the valid values");
00133     else
00134       return out;
00135   }
00136     }
00137 
00138 
00139     void
00140     Banner::setDefaults (const int howMany)
00141     {
00142       if (howMany >= 4)
00143   objectType_ = "matrix";
00144       if (howMany >= 3)
00145   matrixType_ = "coordinate";
00146       if (howMany >= 2)
00147   dataType_ = "real";
00148       if (howMany >= 1)
00149   symmType_ = "general";
00150     }
00151 
00152     Banner::Banner (const std::string& line, const bool tolerant)
00153     {
00154       size_t start;
00155 
00156       if (line.empty())
00157   {
00158     if (tolerant)
00159       {
00160         setDefaults (4);
00161         return;
00162       }
00163     else
00164       throw std::invalid_argument ("The banner line is empty");
00165   }
00166       start = line.find_first_not_of (" \t");
00167       if (start == std::string::npos)
00168   {
00169     if (tolerant)
00170       {
00171         setDefaults (4);
00172         return;
00173       }
00174     else
00175       throw std::invalid_argument ("The banner line contains only "
00176            "whitespace characters");
00177   }
00178       else if (start != 0 && ! tolerant)
00179   // If tolerant, we allow the banner line to start with
00180   // whitespace characters, and keep reading.
00181   throw std::invalid_argument ("The banner line is not allowed to start "
00182              "with whitespace characters");
00183 
00184       // Find "%%MatrixMarket" -- it should be the first thing in the
00185       // banner line, and all other data should come after it.
00186       // Optionally relax to allow any case, and possibly a space
00187       // between "%%" and "MatrixMarket".
00188       size_t ppStart = line.find ("%%", start);
00189       size_t tokenStart;
00190       if (ppStart == std::string::npos)
00191   {
00192     if (tolerant)
00193       tokenStart = start; // Just ignore the missing %%
00194     else
00195       throw std::invalid_argument ("The banner line should always start "
00196            "with \"%%\".");
00197   }
00198       else 
00199   {
00200     tokenStart = ppStart + 2;
00201     if (tokenStart >= line.size())
00202       { // There's no banner information after the %%.
00203         if (tolerant)
00204     {
00205       setDefaults (4);
00206       return;
00207     }
00208         else
00209     throw std::invalid_argument ("The banner line needs to contain "
00210                "information after the \"%%\" marker.");
00211       }
00212   }
00213       //
00214       // In tolerant mode, fill in missing tokens with their default
00215       // values.
00216       //
00217       // After extracting the %%, search for the five tokens.
00218       std::vector<std::string> tokens = split (line, " \t", 2);
00219       if (false)
00220   {
00221     using std::cerr;
00222     using std::endl;
00223     cerr << "Tokens on banner line:" << endl;
00224     for (std::vector<std::string>::size_type k = 0; k < tokens.size(); ++k)
00225       cerr << tokens[k] << " ";
00226     cerr << endl;
00227   }
00228       const int numTokens = tokens.size();
00229       if (numTokens < 1)
00230   {
00231     if (tolerant)
00232       {
00233         setDefaults (4);
00234         return;
00235       }
00236     else
00237       throw std::invalid_argument("The banner line must begin with "
00238           "the \"MatrixMarket\" keyword.");
00239   }
00240       // In tolerant mode, just ignore the first token.
00241       if (! tolerant && tokens[0] != "MatrixMarket")
00242   throw std::invalid_argument("The banner line must begin with "
00243             "the \"MatrixMarket\" keyword.");
00244       if (numTokens < 5)
00245   {
00246     if (tolerant)
00247       setDefaults (5 - numTokens); // how many defaults to set
00248     else
00249       {
00250         std::ostringstream os;
00251         os << "In the banner line, 5 tokens are required, but only " 
00252      << numTokens << (numTokens == 1 ? " are " : " is ")
00253      << "provided.";
00254         throw std::invalid_argument (os.str());
00255       }
00256   }
00257       if (numTokens >= 2)
00258   objectType_ = validateObjectType (tokens[1], tolerant);
00259       if (numTokens >= 3)
00260   matrixType_ = validateMatrixType (tokens[2], tolerant);
00261       if (numTokens >= 4)
00262   dataType_ = validateDataType (tokens[3], tolerant);
00263       if (numTokens >= 5)
00264   symmType_ = validateSymmType (tokens[4], tolerant);
00265     }
00266 
00267     std::ostream& 
00268     operator<< (std::ostream& out, const Banner& banner) 
00269     {
00270       out << "%%MatrixMarket" 
00271     << " " << banner.objectType()
00272     << " " << banner.matrixType()
00273     << " " << banner.dataType()
00274     << " " << banner.symmType();
00275       return out;
00276     }
00277   } // namespace MatrixMarket
00278 } // namespace Tpetra
00279 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines