aGrUM  0.21.0
a C++ library for (probabilistic) graphical models
DBCell.cpp
Go to the documentation of this file.
1 /**
2  *
3  * Copyright (c) 2005-2021 by Pierre-Henri WUILLEMIN(@LIP6) & Christophe GONZALES(@AMU)
4  * info_at_agrum_dot_org
5  *
6  * This library is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this library. If not, see <http://www.gnu.org/licenses/>.
18  *
19  */
20 
21 
22 /** @file
23  * @brief The implementation of DBCells
24  *
25  * @author Christophe GONZALES(@AMU) and Pierre-Henri WUILLEMIN(@LIP6)
26  */
27 #include <cstdio>
28 #include <agrum/tools/database/DBCell.h>
29 
30 
31 #ifndef DOXYGEN_SHOULD_SKIP_THIS
32 
33 /// include the inlined functions if necessary
34 # ifdef GUM_NO_INLINE
35 # include <agrum/tools/database/DBCell_inl.h>
36 # endif /* GUM_NO_INLINE */
37 
38 namespace gum {
39 
40  namespace learning {
41 
42  // create the static members
43  int DBCell::_string_max_index_ = 0;
44 
45 
46  Bijection< std::string, int >& DBCell::_strings_() {
47 # ifdef GUM_DEBUG_MODE
48  static bool first_time = true;
49  if (first_time) {
50  first_time = false;
51  __debug__::_dec_creation_("Bijection", " __strings", 0, "BCell string bijection", 0);
52  __debug__::_dec_creation_("BijectionImplementation",
53  " __strings",
54  0,
55  "BCell string bijection",
56  0);
57  __debug__::_dec_creation_("HashTable", " __strings", 0, "BCell string bijection", 0);
58  __debug__::_dec_creation_("HashTable", " __strings", 0, "BCell string bijection", 0);
59  }
60 # endif
61  static Bijection< std::string, int > strings;
62  return strings;
63  }
64 
65 
66  // determines whether a string corresponds to an integer
67  bool DBCell::isInteger(const std::string& str) {
68  if (str.empty()) return false;
69 
70  // trim the string
71  auto start_iter = str.begin() + str.find_first_not_of(" \t");
72  auto end_iter = str.begin() + str.find_last_not_of(" \t\r\n") + 1;
73 
74  if (start_iter == end_iter) return false;
75 
76  // if the number is negative, pass the '-' sign
77  if (*start_iter == '-') ++start_iter;
78 
79  // check wether we have a number
80  for (; start_iter != end_iter; ++start_iter) {
81  if ((*start_iter < '0') || (*start_iter > '9')) return false;
82  }
83 
84  return true;
85  }
86 
87 
88  // determines whether a string corresponds to an integer
89  bool DBCell::isReal(const std::string& str) {
90  if (str.empty()) return false;
91 
92  // trim the string
93  auto start_iter = str.begin() + str.find_first_not_of(" \t");
94  auto end_iter = str.begin() + str.find_last_not_of(" \t\r\n") + 1;
95 
96  if (start_iter == end_iter) return false;
97 
98  // check wether we have a number
99  bool has_dot = false;
100  bool has_exponent = false;
101  bool has_digit = false;
102  bool has_negation = false;
103  for (; start_iter != end_iter; ++start_iter) {
104  if (*start_iter == '-') {
105  if (has_negation) return false;
106  } else if (*start_iter == '.') {
107  if (has_dot || has_exponent) return false;
108  has_dot = true;
109  } else if ((*start_iter == 'e') || (*start_iter == 'E')) {
110  if (has_exponent || !has_digit) return false;
111  has_exponent = true;
112  has_negation = false;
113  } else if ((*start_iter < '0') || (*start_iter > '9'))
114  return false;
115  else
116  has_digit = true;
117  }
118 
119  return true;
120  }
121 
122 
123  // try to convert the content of the DBCell into another type
124  bool DBCell::convertType(const EltType new_type) {
125  if (new_type == _type_) return true;
126  switch (new_type) {
127  // ===================================
128  case EltType::REAL:
129  switch (_type_) {
130  case EltType::INTEGER:
131  _val_real_ = float(_val_integer_);
132  _type_ = EltType::REAL;
133  return true;
134 
135  case EltType::STRING:
136  try {
137  const std::string& str = _strings_().first(_val_index_);
138  if (!isReal(str)) return false;
139  _val_real_ = std::stof(str);
140  _type_ = EltType::REAL;
141  return true;
142  } catch (std::invalid_argument&) { return false; }
143 
144  case EltType::MISSING:
145  return false;
146 
147  default:
148  GUM_ERROR(NotImplementedYet, "type not supported by DBCell convertType")
149  }
150 
151  // ===================================
152  case EltType::INTEGER:
153  switch (_type_) {
154  case EltType::REAL: {
155  const int nb = int(_val_real_);
156  if (nb == _val_real_) {
157  _val_integer_ = nb;
159  return true;
160  } else
161  return false;
162  }
163 
164  case EltType::STRING:
165  try {
166  const std::string& str = _strings_().first(_val_index_);
167  if (!isInteger(str)) return false;
170  return true;
171  } catch (std::invalid_argument&) { return false; }
172 
173  case EltType::MISSING:
174  return false;
175 
176  default:
177  GUM_ERROR(NotImplementedYet, "type not supported by DBCell convertType")
178  }
179 
180  // ===================================
181  case EltType::STRING:
182  switch (_type_) {
183  case EltType::REAL: {
184  char buffer[100];
185  sprintf(buffer, "%g", _val_real_);
186  const std::string str(buffer);
187  if (!_strings_().existsFirst(str)) {
191  } else {
193  }
194  }
195  _type_ = EltType::STRING;
196  return true;
197 
198  case EltType::INTEGER: {
200  if (!_strings_().existsFirst(str)) {
204  } else {
206  }
207  }
208  _type_ = EltType::STRING;
209  return true;
210 
211  case EltType::MISSING:
212  return false;
213 
214  default:
215  GUM_ERROR(NotImplementedYet, "type not supported by DBCell convertType")
216  }
217 
218  // ===================================
219  case EltType::MISSING:
221  return true;
222 
223  default:
224  GUM_ERROR(NotImplementedYet, "type not supported by DBCell convertType")
225  }
226 
227  return false;
228  }
229 
230 
231  // raises an appropriate exception when encountering a type error
232  std::string DBCell::_typeErrorMsg_(const std::string& true_type) const {
234  switch (_type_) {
235  case EltType::REAL:
236  str << "The DBCell contains a real number instead of " << true_type;
237  break;
238 
239  case EltType::INTEGER:
240  str << "The DBCell contains an integer instead of " << true_type;
241  break;
242 
243  case EltType::STRING:
244  str << "The DBCell contains a string instead of " << true_type;
245  break;
246 
247  case EltType::MISSING:
248  str << "The DBCell contains a missing value instead of " << true_type;
249  break;
250 
251  default:
252  GUM_ERROR(NotImplementedYet, "DBCell type not implemented yet")
253  }
254 
255  return str.str();
256  }
257 
258  } /* namespace learning */
259 
260 } /* namespace gum */
261 
262 #endif /* DOXYGEN_SHOULD_SKIP_THIS */
INLINE void emplace(Args &&... args)
Definition: set_tpl.h:643
Database(const std::string &filename, const BayesNet< GUM_SCALAR > &bn, const std::vector< std::string > &missing_symbols)