source: trunk/lib/yat/utility.h @ 1039

Last change on this file since 1039 was 1039, checked in by Peter Johansson, 12 years ago

updating to the latest yat. refs #410

  • Property svn:eol-style set to native
File size: 8.3 KB
Line 
1#ifndef _theplu_yat_utility_utility_
2#define _theplu_yat_utility_utility_
3
4// $Id: utility.h 2210 2010-03-05 22:59:01Z peter $
5
6/*
7  Copyright (C) 2005 Jari Häkkinen, Peter Johansson, Markus Ringnér
8  Copyright (C) 2006 Jari Häkkinen
9  Copyright (C) 2007, 2008 Jari Häkkinen, Peter Johansson
10  Copyright (C) 2009 Peter Johansson
11
12  This file is part of the yat library, http://dev.thep.lu.se/yat
13
14  The yat library is free software; you can redistribute it and/or
15  modify it under the terms of the GNU General Public License as
16  published by the Free Software Foundation; either version 3 of the
17  License, or (at your option) any later version.
18
19  The yat library is distributed in the hope that it will be useful,
20  but WITHOUT ANY WARRANTY; without even the implied warranty of
21  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22  General Public License for more details.
23
24  You should have received a copy of the GNU General Public License
25  along with yat. If not, see <http://www.gnu.org/licenses/>.
26*/
27
28///
29/// \file yat/utility/utility.h
30///
31/// @brief Some useful functions are placed here
32///
33
34#include "deprecate.h"
35#include "Exception.h"
36
37#include <cmath>
38#include <limits>
39#include <istream>
40#include <string>
41#include <stdexcept>
42#include <sstream>
43#include <utility>
44#include <vector>
45
46namespace theplu {
47namespace yat {
48namespace utility {
49
50  /**
51     For each element in resulting range assign it to 0.0 if
52     corresponding element in input range is NaN else assign it to
53     1.0.
54
55     \return true if there is at least one NaN in input range
56     [first, last).
57
58     \since New in yat 0.5
59  */
60  template<typename InputIterator, typename OutputIterator>
61  bool binary_weight(InputIterator first, InputIterator last, 
62                     OutputIterator result);
63
64
65  /**
66     \brief convert string to (numerical) type
67
68     \throw runtime_error if conversion fails
69   */
70  template<typename T>
71  T convert(const std::string& s);
72
73  /**
74     \brief check if string is convertible to (numerical) type
75
76     \since New in yat 0.5
77   */
78  template<typename T>
79  bool is(const std::string& s);
80
81  ///
82  /// @return true if string is a double
83  ///
84  /// \deprecated Provided for backward compatibility with the 0.4
85  /// API. Use is<double>(const std::string&)
86  ///
87  bool is_double(const std::string&) YAT_DEPRECATE;
88
89  /**
90     This function takes the first word (separated by whitespace) in
91     \a s, replaces all upper case with lower case, and compares it
92     with \a other.
93
94     \return true if processed \a s is equal to \a other. It returns
95     false otherwise or if \a s contains more than one word.
96  */
97  bool is_equal(std::string s, std::string other);
98
99  ///
100  /// @return true if string is a float
101  ///
102  /// \deprecated Provided for backward compatibility with the 0.4
103  /// API. Use is<float>(const std::string&)
104  ///
105  bool is_float(const std::string&) YAT_DEPRECATE;
106
107  ///
108  /// @return true if string is an int
109  ///
110  /// \deprecated Provided for backward compatibility with the 0.4
111  /// API. Use is<int>(const std::string&)
112  ///
113  bool is_int(const std::string&) YAT_DEPRECATE;
114
115  ///
116  /// @return true if string is "nan" (case-insensitive)
117  ///
118  bool is_nan(const std::string& s);
119
120  /**
121     The std::istream will be interpreted as outlined here:
122
123     Lines are separated by character \a line_sep and rows are
124     separated by character \a sep.
125     
126     The first line is read into a stringstream, which is used to
127     load the first vector (vec[0]) with elements using
128     load(stringstream, vec[0], sep).
129     
130     Therefore, column elements separation has two modes depending
131     on the value of \a sep.
132     
133     - If \a sep is the default '\\0' value then column elements are
134     separated with white space characters except the new line
135     character. Multiple sequential white space characters are treated
136     as one separator.
137     
138     - Setting \a sep to something else than the default value will
139     change the behaviour to use the \a sep character as the separator
140     between column elements. Multiple sequential \a sep characters
141     will be treated as separating elements with missing values.
142
143     If \a rectangle is true, rows must contain same number of
144     elements or function will throw.
145
146     If \a ignore_empty is true empty lines are ignored.
147
148     \see load(std::istream&, std::vector<T>&, char sep='\\0')
149
150     \note Requirement on T: utility::convert<T> must be supported
151
152     \since New in yat 0.6
153   */
154  template<typename T>
155  void load(std::istream& is, std::vector<std::vector<T> >& vec, char sep='\0', 
156            char line_sep='\n', bool ignore_empty=false, bool rectangle=true);
157
158  /**
159     \brief Fill a vector<T> with elements from istream
160
161     Element separation has two modes depending on the value of \a
162     sep.
163     
164     - If \a sep is the default '\\0' value then elements are
165     separated with white space characters. Multiple sequential white
166     space characters are treated as one separator.
167     
168     - Setting \a sep to something else than the default value will
169     change the behaviour to use the \a sep character as the
170     separator between column elements. Multiple sequential \a sep
171     characters will be treated as separating elements with missing
172     values. Missing values are set to std::numeric_limits<T>::quiet_NaN
173     
174     \note Requirement on T: utility::convert<T> must be supported
175
176     \since New in yat 0.6
177   */
178  template<typename T>
179  void load(std::istream& is, std::vector<T>& vec, char sep='\0');
180 
181  // template implementations
182
183  template<typename InputIterator, typename OutputIterator>
184  bool binary_weight(InputIterator first, InputIterator last, 
185                     OutputIterator result)
186  {
187    bool nan=false;
188    while (first!=last) {
189      if (std::isnan(*first)) {
190        *result=0;
191        nan=true;
192      }
193      else
194        *result = 1.0;
195      ++first;
196      ++result;
197    }
198    return nan;
199  }
200
201
202  // template implementations
203  template<typename T>
204  T convert(const std::string& s)
205  {
206    if (is_nan(s))
207      return std::numeric_limits<T>::quiet_NaN();
208    if (is_equal(s, "inf"))
209      return std::numeric_limits<T>::infinity();
210    if (is_equal(s, "-inf")) {
211      if (std::numeric_limits<T>::is_signed)
212        return -std::numeric_limits<T>::infinity();
213      else
214        throw runtime_error(std::string("yat::utility::convert(\"")+s+
215                            std::string("\"): type is unsigned") );
216    }
217    std::stringstream ss(s);
218    T a;
219    ss >> a;
220    bool ok = true;
221    if(ss.fail()) 
222      ok = false;
223    // Check that nothing is left on stream
224    std::string b;
225    ss >> b;
226    if (!b.empty() || !ok)
227      throw runtime_error(std::string("yat::utility::convert(\"")+s+
228                          std::string("\")"));
229    return a;
230  }
231
232  template<typename T>
233  bool is(const std::string& s)
234  {
235    if (is_nan(s))
236      return std::numeric_limits<T>::has_quiet_NaN;
237    if (is_equal(s, "inf"))
238      return std::numeric_limits<T>::has_infinity;
239    if (is_equal(s, "-inf"))
240      return std::numeric_limits<T>::has_infinity && 
241        std::numeric_limits<T>::is_signed;
242    std::stringstream ss(s);
243    T a;
244    ss >> a;
245    if(ss.fail())
246      return false;
247    // Check that nothing is left on stream
248    std::string b;
249    ss >> b;
250    return b.empty();
251  }
252
253  template<typename T>
254  void load(std::istream& is, std::vector<std::vector<T> >& matrix, 
255            char sep, char line_sep, bool ignore_empty, 
256            bool rectangle)
257  {
258    size_t nof_columns=0;
259    std::string line;
260    while(getline(is, line, line_sep)){
261      if (line.empty() && ignore_empty)
262        continue;
263      matrix.resize(matrix.size()+1);
264      std::vector<double>& v=matrix.back();
265      v.reserve(nof_columns);
266      std::stringstream ss(line);
267      load(ss, v, sep);
268      // add NaN for final separator
269      if(sep!='\0' && !line.empty() && line[line.size()-1]==sep) 
270        v.push_back(std::numeric_limits<T>::quiet_NaN());
271     
272      if (rectangle && nof_columns && v.size()!=nof_columns) {
273        std::ostringstream s;
274        s << "load data file error: "
275          << "line " << matrix.size() << " has " << v.size()
276          << " columns; expected " << nof_columns << " columns.";
277        throw utility::IO_error(s.str());
278      }       
279      nof_columns = std::max(nof_columns, v.size());
280    }
281
282    // manipulate the state of the stream to be good
283    is.clear(std::ios::goodbit);
284  }
285
286  template<typename T>
287  void load(std::istream& is, std::vector<T>& vec, char sep='\0')
288  {
289    std::string element;
290    bool ok=true;
291    while(ok) {
292      if(sep=='\0')
293        ok=(is>>element);
294      else
295        ok=getline(is, element, sep);
296      if(!ok)
297        break;
298     
299      if (!element.size())
300        vec.push_back(std::numeric_limits<T>::quiet_NaN());
301      else {
302        vec.push_back(convert<T>(element));
303      }
304    }
305  }           
306
307}}} // of namespace utility, yat, and theplu
308
309#endif
Note: See TracBrowser for help on using the repository browser.