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

Last change on this file since 824 was 824, checked in by Peter Johansson, 13 years ago

adding missing file Exception.h.diff

  • Property svn:eol-style set to native
File size: 8.2 KB
Line 
1#ifndef _theplu_yat_utility_utility_
2#define _theplu_yat_utility_utility_
3
4// $Id: utility.h 2055 2009-09-08 18:23:43Z 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     @return true if string \a s fulfills regular expression \verbatim
91     ^\w* \endverbatim \a other \verbatim \w*$ \endverbatim (case
92     insensitive)
93  */
94  bool is_equal(std::string s, std::string other);
95
96  ///
97  /// @return true if string is a float
98  ///
99  /// \deprecated Provided for backward compatibility with the 0.4
100  /// API. Use is<float>(const std::string&)
101  ///
102  bool is_float(const std::string&) YAT_DEPRECATE;
103
104  ///
105  /// @return true if string is an int
106  ///
107  /// \deprecated Provided for backward compatibility with the 0.4
108  /// API. Use is<int>(const std::string&)
109  ///
110  bool is_int(const std::string&) YAT_DEPRECATE;
111
112  ///
113  /// @return true if string is "nan" (case-insensitive)
114  ///
115  bool is_nan(const std::string& s);
116
117  /**
118     The std::istream will be interpreted as outlined here:
119
120     Lines are separated by character \a line_sep and rows are
121     separated by character \a sep.
122     
123     The first line is read into a stringstream, which is used to
124     load the first vector (vec[0]) with elements using
125     load(stringstream, vec[0], sep).
126     
127     Therefore, column elements separation has two modes depending
128     on the value of \a sep.
129     
130     - If \a sep is the default '\\0' value then column elements are
131     separated with white space characters except the new line
132     character. Multiple sequential white space characters are treated
133     as one separator.
134     
135     - Setting \a sep to something else than the default value will
136     change the behaviour to use the \a sep character as the separator
137     between column elements. Multiple sequential \a sep characters
138     will be treated as separating elements with missing values.
139
140     If \a rectangle is true, rows must contain same number of
141     elements or function will throw.
142
143     If \a ignore_empty is true empty lines are ignored.
144
145     \see load(std::istream&, std::vector<T>&, char sep='\\0')
146
147     \note Requirement on T: utility::convert<T> must be supported
148
149     \since New in yat 0.6
150   */
151  template<typename T>
152  void load(std::istream& is, std::vector<std::vector<T> >& vec, char sep='\0', 
153            char line_sep='\n', bool ignore_empty=false, bool rectangle=true);
154
155  /**
156     \brief Fill a vector<T> with elements from istream
157
158     Element separation has two modes depending on the value of \a
159     sep.
160     
161     - If \a sep is the default '\\0' value then elements are
162     separated with white space characters. Multiple sequential white
163     space characters are treated as one separator.
164     
165     - Setting \a sep to something else than the default value will
166     change the behaviour to use the \a sep character as the
167     separator between column elements. Multiple sequential \a sep
168     characters will be treated as separating elements with missing
169     values. Missing values are set to std::numeric_limits<T>::quiet_NaN
170     
171     \note Requirement on T: utility::convert<T> must be supported
172
173     \since New in yat 0.6
174   */
175  template<typename T>
176  void load(std::istream& is, std::vector<T>& vec, char sep='\0');
177 
178  // template implementations
179
180  template<typename InputIterator, typename OutputIterator>
181  bool binary_weight(InputIterator first, InputIterator last, 
182                     OutputIterator result)
183  {
184    bool nan=false;
185    while (first!=last) {
186      if (std::isnan(*first)) {
187        *result=0;
188        nan=true;
189      }
190      else
191        *result = 1.0;
192      ++first;
193      ++result;
194    }
195    return nan;
196  }
197
198
199  // template implementations
200  template<typename T>
201  T convert(const std::string& s)
202  {
203    if (is_nan(s))
204      return std::numeric_limits<T>::quiet_NaN();
205    if (is_equal(s, "inf"))
206      return std::numeric_limits<T>::infinity();
207    if (is_equal(s, "-inf")) {
208      if (std::numeric_limits<T>::is_signed)
209        return -std::numeric_limits<T>::infinity();
210      else
211        throw std::runtime_error(std::string("yat::utility::convert(\"")+s+
212                                 std::string("\"): type is unsigned") );
213    }
214    std::stringstream ss(s);
215    T a;
216    ss >> a;
217    bool ok = true;
218    if(ss.fail()) 
219      ok = false;
220    // Check that nothing is left on stream
221    std::string b;
222    ss >> b;
223    if (!b.empty() || !ok)
224      throw std::runtime_error(std::string("yat::utility::convert(\"")+s+
225                               std::string("\")"));
226    return a;
227  }
228
229  template<typename T>
230  bool is(const std::string& s)
231  {
232    if (is_nan(s))
233      return std::numeric_limits<T>::has_quiet_NaN;
234    if (is_equal(s, "inf"))
235      return std::numeric_limits<T>::has_infinity;
236    if (is_equal(s, "-inf"))
237      return std::numeric_limits<T>::has_infinity && 
238        std::numeric_limits<T>::is_signed;
239    std::stringstream ss(s);
240    T a;
241    ss >> a;
242    if(ss.fail())
243      return false;
244    // Check that nothing is left on stream
245    std::string b;
246    ss >> b;
247    return b.empty();
248  }
249
250  template<typename T>
251  void load(std::istream& is, std::vector<std::vector<T> >& matrix, 
252            char sep, char line_sep, bool ignore_empty, 
253            bool rectangle)
254  {
255    size_t nof_columns=0;
256    std::string line;
257    while(getline(is, line, line_sep)){
258      if (line.empty() && ignore_empty)
259        continue;
260      matrix.resize(matrix.size()+1);
261      std::vector<double>& v=matrix.back();
262      v.reserve(nof_columns);
263      std::stringstream ss(line);
264      load(ss, v, sep);
265      // add NaN for final separator
266      if(sep!='\0' && !line.empty() && line[line.size()-1]==sep) 
267        v.push_back(std::numeric_limits<T>::quiet_NaN());
268     
269      if (rectangle && nof_columns && v.size()!=nof_columns) {
270        std::ostringstream s;
271        s << "load data file error: "
272          << "line " << matrix.size() << " has " << v.size()
273          << " columns; expected " << nof_columns << " columns.";
274        throw utility::IO_error(s.str());
275      }       
276      nof_columns = std::max(nof_columns, v.size());
277    }
278
279    // manipulate the state of the stream to be good
280    is.clear(std::ios::goodbit);
281  }
282
283  template<typename T>
284  void load(std::istream& is, std::vector<T>& vec, char sep='\0')
285  {
286    std::string element;
287    bool ok=true;
288    while(ok) {
289      if(sep=='\0')
290        ok=(is>>element);
291      else
292        ok=getline(is, element, sep);
293      if(!ok)
294        break;
295     
296      if (!element.size())
297        vec.push_back(std::numeric_limits<T>::quiet_NaN());
298      else {
299        vec.push_back(convert<T>(element));
300      }
301    }
302  }           
303
304}}} // of namespace utility, yat, and theplu
305
306#endif
Note: See TracBrowser for help on using the repository browser.