aGrUM  0.20.2
a C++ library for (probabilistic) graphical models
DBCell.cpp
Go to the documentation of this file.
1 /**
2  *
3  * Copyright 2005-2020 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",
52  "__strings",
53  0,
54  "BCell string bijection",
55  0);
56  __debug__::dec_creation__("BijectionImplementation",
57  "__strings",
58  0,
59  "BCell string bijection",
60  0);
61  __debug__::dec_creation__("HashTable",
62  "__strings",
63  0,
64  "BCell string bijection",
65  0);
66  __debug__::dec_creation__("HashTable",
67  "__strings",
68  0,
69  "BCell string bijection",
70  0);
71  }
72 # endif
73  static Bijection< std::string, int > strings;
74  return strings;
75  }
76 
77 
78  // determines whether a string corresponds to an integer
79  bool DBCell::isInteger(const std::string& str) {
80  if (str.empty()) return false;
81 
82  // trim the string
83  auto start_iter = str.begin() + str.find_first_not_of(" \t");
84  auto end_iter = str.begin() + str.find_last_not_of(" \t\r\n") + 1;
85 
86  if (start_iter == end_iter) return false;
87 
88  // if the number is negative, pass the '-' sign
89  if (*start_iter == '-') ++start_iter;
90 
91  // check wether we have a number
92  for (; start_iter != end_iter; ++start_iter) {
93  if ((*start_iter < '0') || (*start_iter > '9')) return false;
94  }
95 
96  return true;
97  }
98 
99 
100  // determines whether a string corresponds to an integer
101  bool DBCell::isReal(const std::string& str) {
102  if (str.empty()) return false;
103 
104  // trim the string
105  auto start_iter = str.begin() + str.find_first_not_of(" \t");
106  auto end_iter = str.begin() + str.find_last_not_of(" \t\r\n") + 1;
107 
108  if (start_iter == end_iter) return false;
109 
110  // check wether we have a number
111  bool has_dot = false;
112  bool has_exponent = false;
113  bool has_digit = false;
114  bool has_negation = false;
115  for (; start_iter != end_iter; ++start_iter) {
116  if (*start_iter == '-') {
117  if (has_negation) return false;
118  } else if (*start_iter == '.') {
119  if (has_dot || has_exponent) return false;
120  has_dot = true;
121  } else if ((*start_iter == 'e') || (*start_iter == 'E')) {
122  if (has_exponent || !has_digit) return false;
123  has_exponent = true;
124  has_negation = false;
125  } else if ((*start_iter < '0') || (*start_iter > '9'))
126  return false;
127  else
128  has_digit = true;
129  }
130 
131  return true;
132  }
133 
134 
135  // try to convert the content of the DBCell into another type
136  bool DBCell::convertType(const EltType new_type) {
137  if (new_type == type__) return true;
138  switch (new_type) {
139  // ===================================
140  case EltType::REAL:
141  switch (type__) {
142  case EltType::INTEGER:
143  val_real__ = float(val_integer__);
144  type__ = EltType::REAL;
145  return true;
146 
147  case EltType::STRING:
148  try {
149  const std::string& str = strings__().first(val_index__);
150  if (!isReal(str)) return false;
151  val_real__ = std::stof(str);
152  type__ = EltType::REAL;
153  return true;
154  } catch (std::invalid_argument&) { return false; }
155 
156  case EltType::MISSING:
157  return false;
158 
159  default:
161  "type not supported by DBCell convertType");
162  }
163 
164  // ===================================
165  case EltType::INTEGER:
166  switch (type__) {
167  case EltType::REAL: {
168  const int nb = int(val_real__);
169  if (nb == val_real__) {
170  val_integer__ = nb;
172  return true;
173  } else
174  return false;
175  }
176 
177  case EltType::STRING:
178  try {
179  const std::string& str = strings__().first(val_index__);
180  if (!isInteger(str)) return false;
183  return true;
184  } catch (std::invalid_argument&) { return false; }
185 
186  case EltType::MISSING:
187  return false;
188 
189  default:
191  "type not supported by DBCell convertType");
192  }
193 
194  // ===================================
195  case EltType::STRING:
196  switch (type__) {
197  case EltType::REAL: {
198  char buffer[100];
199  sprintf(buffer, "%g", val_real__);
200  const std::string str(buffer);
201  if (!strings__().existsFirst(str)) {
205  } else {
207  }
208  }
209  type__ = EltType::STRING;
210  return true;
211 
212  case EltType::INTEGER: {
214  if (!strings__().existsFirst(str)) {
218  } else {
220  }
221  }
222  type__ = EltType::STRING;
223  return true;
224 
225  case EltType::MISSING:
226  return false;
227 
228  default:
230  "type not supported by DBCell convertType");
231  }
232 
233  // ===================================
234  case EltType::MISSING:
236  return true;
237 
238  default:
239  GUM_ERROR(NotImplementedYet, "type not supported by DBCell convertType");
240  }
241 
242  return false;
243  }
244 
245 
246  // raises an appropriate exception when encountering a type error
247  std::string DBCell::typeErrorMsg__(const std::string& true_type) const {
249  switch (type__) {
250  case EltType::REAL:
251  str << "The DBCell contains a real number instead of " << true_type;
252  break;
253 
254  case EltType::INTEGER:
255  str << "The DBCell contains an integer instead of " << true_type;
256  break;
257 
258  case EltType::STRING:
259  str << "The DBCell contains a string instead of " << true_type;
260  break;
261 
262  case EltType::MISSING:
263  str << "The DBCell contains a missing value instead of " << true_type;
264  break;
265 
266  default:
267  GUM_ERROR(NotImplementedYet, "DBCell type not implemented yet");
268  }
269 
270  return str.str();
271  }
272 
273  } /* namespace learning */
274 
275 } /* namespace gum */
276 
277 #endif /* DOXYGEN_SHOULD_SKIP_THIS */
INLINE void emplace(Args &&... args)
Definition: set_tpl.h:669
Database(const std::string &filename, const BayesNet< GUM_SCALAR > &bn, const std::vector< std::string > &missing_symbols)