aGrUM  0.16.0
DBTranslator4ContinuousVariable_tpl.h
Go to the documentation of this file.
1 
28 #ifndef DOXYGEN_SHOULD_SKIP_THIS
29 
30 # include <utility>
31 # include <vector>
32 # include <limits>
33 
36 
37 namespace gum {
38 
39  namespace learning {
40 
41 
43  template < template < typename > class ALLOC >
44  template < template < typename > class XALLOC >
46  const std::vector< std::string, XALLOC< std::string > >& missing_symbols,
47  const bool fit_range,
49  alloc) :
50  DBTranslator< ALLOC >(DBTranslatedValueType::CONTINUOUS,
51  missing_symbols,
52  fit_range,
53  1,
54  alloc),
55  __variable("var", ""), __fit_range(fit_range) {
56  // Here, if fit_range is set to false, and the range of the
57  // random variable will remain (-inf,+inf). So all the missing symbols
58  // that are numbers should be discarded since they lie in the domain
59  // of the variable. On the other hand, if fit_range is true, each newly
60  // observed value will update the range of the variable, so that, again,
61  // all the missing symbols that are numbers should be discarded since
62  // they always end up lying in the domain of the variable.
63  for (auto iter = this->_missing_symbols.beginSafe();
64  iter != this->_missing_symbols.endSafe();
65  ++iter) {
66  if (DBCell::isReal(*iter)) { this->_missing_symbols.erase(iter); }
67  }
68 
69  // the remaining symbols are not numbers. Take the first one as
70  // the default missing symbols for back translations.
71  if (!this->_missing_symbols.empty()) {
72  __nonfloat_missing_symbol = *(this->_missing_symbols.begin());
73  }
74 
75  // if fit_range is true, we shall be able to update the ranges of
76  // the continuous variable. To indicate that we did not encountered any
77  // value yet in the database, we fix the lower bound of __variable to +max
78  if (__fit_range)
79  __variable.setLowerBound(std::numeric_limits< float >::infinity());
80 
81  // store a copy of the variable, that should be used by method variable ()
82  __real_variable = __variable.clone();
83 
84  GUM_CONSTRUCTOR(DBTranslator4ContinuousVariable);
85  }
86 
87 
89  template < template < typename > class ALLOC >
91  const bool fit_range,
93  alloc) :
94  DBTranslator< ALLOC >(
95  DBTranslatedValueType::CONTINUOUS, fit_range, 1, alloc),
96  __variable("var", ""), __fit_range(fit_range) {
97  // if fit_range is true, we shall be able to update the ranges of
98  // the continuous variable. To indicate that we did not encountered any
99  // value yet in the database, we fix the lower bound of __variable to +max
100  if (__fit_range)
101  __variable.setLowerBound(std::numeric_limits< float >::infinity());
102 
103  // store a copy of the variable, that should be used by method variable ()
104  __real_variable = __variable.clone();
105 
106  GUM_CONSTRUCTOR(DBTranslator4ContinuousVariable);
107  }
108 
109 
111  template < template < typename > class ALLOC >
112  template < typename GUM_SCALAR, template < typename > class XALLOC >
114  const ContinuousVariable< GUM_SCALAR >& var,
115  const std::vector< std::string, XALLOC< std::string > >& missing_symbols,
116  const bool fit_range,
118  alloc) :
120  missing_symbols,
121  fit_range,
122  1,
123  alloc),
124  __variable(var.name(), var.description()), __fit_range(fit_range) {
125  // get the bounds of the range variable
126  const float lower_bound = float(var.lowerBound());
127  const float upper_bound = float(var.upperBound());
128  __variable.setLowerBound(lower_bound);
129  __variable.setUpperBound(upper_bound);
130 
131  // remove all the missing symbols corresponding to a number between
132  // lower_bound and upper_bound
133  bool non_float_symbol_found = false;
134  for (auto iter = this->_missing_symbols.beginSafe();
135  iter != this->_missing_symbols.endSafe();
136  ++iter) {
137  if (DBCell::isReal(*iter)) {
138  const float missing_val = std::stof(*iter);
139  if ((missing_val >= lower_bound) && (missing_val <= upper_bound)) {
140  this->_missing_symbols.erase(iter);
141  } else
142  __status_float_missing_symbols.insert(*iter, false);
143  } else if (!non_float_symbol_found) {
144  non_float_symbol_found = true;
145  __nonfloat_missing_symbol = *iter;
146  }
147  }
148 
149  // store a copy of the variable, that should be used by method variable ()
150  __real_variable = var.clone();
151 
152  GUM_CONSTRUCTOR(DBTranslator4ContinuousVariable);
153  }
154 
155 
157  template < template < typename > class ALLOC >
158  template < typename GUM_SCALAR >
160  const ContinuousVariable< GUM_SCALAR >& var,
161  const bool fit_range,
163  alloc) :
164  DBTranslator< ALLOC >(
165  DBTranslatedValueType::CONTINUOUS, fit_range, 1, alloc),
166  __variable(var.name(), var.description()), __fit_range(fit_range) {
167  // get the bounds of the range variable
168  const float lower_bound = float(var.lowerBound());
169  const float upper_bound = float(var.upperBound());
170  __variable.setLowerBound(lower_bound);
171  __variable.setUpperBound(upper_bound);
172 
173  // store a copy of the variable, that should be used by method variable ()
174  __real_variable = var.clone();
175 
176  GUM_CONSTRUCTOR(DBTranslator4ContinuousVariable);
177  }
178 
179 
181  template < template < typename > class ALLOC >
182  template < template < typename > class XALLOC >
184  const IContinuousVariable& var,
185  const std::vector< std::string, XALLOC< std::string > >& missing_symbols,
186  const bool fit_range,
188  alloc) :
190  missing_symbols,
191  fit_range,
192  1,
193  alloc),
194  __variable(var.name(), var.description()), __fit_range(fit_range) {
195  // get the bounds of the range variable
196  const float lower_bound = float(var.lowerBoundAsDouble());
197  const float upper_bound = float(var.upperBoundAsDouble());
198  __variable.setLowerBound(lower_bound);
199  __variable.setUpperBound(upper_bound);
200 
201  // remove all the missing symbols corresponding to a number between
202  // lower_bound and upper_bound
203  bool non_float_symbol_found = false;
204  for (auto iter = this->_missing_symbols.beginSafe();
205  iter != this->_missing_symbols.endSafe();
206  ++iter) {
207  if (DBCell::isReal(*iter)) {
208  const float missing_val = std::stof(*iter);
209  if ((missing_val >= lower_bound) && (missing_val <= upper_bound)) {
210  this->_missing_symbols.erase(iter);
211  } else
212  __status_float_missing_symbols.insert(*iter, false);
213  } else if (!non_float_symbol_found) {
214  non_float_symbol_found = true;
215  __nonfloat_missing_symbol = *iter;
216  }
217  }
218 
219  // store a copy of the variable, that should be used by method variable ()
220  __real_variable = var.clone();
221 
222  GUM_CONSTRUCTOR(DBTranslator4ContinuousVariable);
223  }
224 
225 
227  template < template < typename > class ALLOC >
229  const IContinuousVariable& var,
230  const bool fit_range,
232  alloc) :
233  DBTranslator< ALLOC >(
234  DBTranslatedValueType::CONTINUOUS, fit_range, 1, alloc),
235  __variable(var.name(), var.description()), __fit_range(fit_range) {
236  // get the bounds of the range variable
237  const float lower_bound = var.lowerBoundAsDouble();
238  const float upper_bound = var.upperBoundAsDouble();
239  __variable.setLowerBound(lower_bound);
240  __variable.setUpperBound(upper_bound);
241 
242  // store a copy of the variable, that should be used by method variable ()
243  __real_variable = var.clone();
244 
245  GUM_CONSTRUCTOR(DBTranslator4ContinuousVariable);
246  }
247 
248 
250  template < template < typename > class ALLOC >
252  const DBTranslator4ContinuousVariable< ALLOC >& from,
254  alloc) :
255  DBTranslator< ALLOC >(from, alloc),
256  __variable(from.__variable),
257  __status_float_missing_symbols(from.__status_float_missing_symbols),
258  __nonfloat_missing_symbol(from.__nonfloat_missing_symbol),
259  __fit_range(from.__fit_range) {
260  // store a copy of the variable, that should be used by method variable ()
261  __real_variable = from.__real_variable->clone();
262 
263  GUM_CONS_CPY(DBTranslator4ContinuousVariable);
264  }
265 
266 
268  template < template < typename > class ALLOC >
270  const DBTranslator4ContinuousVariable< ALLOC >& from) :
271  DBTranslator4ContinuousVariable< ALLOC >(from, from.getAllocator()) {}
272 
273 
275  template < template < typename > class ALLOC >
277  DBTranslator4ContinuousVariable< ALLOC >&& from,
279  alloc) :
280  DBTranslator< ALLOC >(std::move(from), alloc),
281  __variable(std::move(from.__variable)),
282  __status_float_missing_symbols(
283  std::move(from.__status_float_missing_symbols)),
284  __nonfloat_missing_symbol(std::move(from.__nonfloat_missing_symbol)),
285  __fit_range(from.__fit_range) {
286  // store a copy of the variable, that should be used by method variable ()
287  __real_variable = from.__real_variable;
288  from.__real_variable = nullptr;
289 
290  GUM_CONS_MOV(DBTranslator4ContinuousVariable);
291  }
292 
293 
295  template < template < typename > class ALLOC >
297  DBTranslator4ContinuousVariable< ALLOC >&& from) :
298  DBTranslator4ContinuousVariable< ALLOC >(std::move(from),
299  from.getAllocator()) {}
300 
301 
303  template < template < typename > class ALLOC >
304  DBTranslator4ContinuousVariable< ALLOC >*
307  alloc) const {
308  ALLOC< DBTranslator4ContinuousVariable< ALLOC > > allocator(alloc);
309  DBTranslator4ContinuousVariable< ALLOC >* translator = allocator.allocate(1);
310  try {
311  allocator.construct(translator, *this, alloc);
312  } catch (...) {
313  allocator.deallocate(translator, 1);
314  throw;
315  }
316  return translator;
317  }
318 
319 
321  template < template < typename > class ALLOC >
322  INLINE DBTranslator4ContinuousVariable< ALLOC >*
324  return clone(this->getAllocator());
325  }
326 
327 
329  template < template < typename > class ALLOC >
332  if (__real_variable != nullptr) delete __real_variable;
333 
334  GUM_DESTRUCTOR(DBTranslator4ContinuousVariable);
335  }
336 
337 
339  template < template < typename > class ALLOC >
340  DBTranslator4ContinuousVariable< ALLOC >&
342  operator=(const DBTranslator4ContinuousVariable< ALLOC >& from) {
343  if (this != &from) {
345  __variable = from.__variable;
346  __status_float_missing_symbols = from.__status_float_missing_symbols;
347  __nonfloat_missing_symbol = from.__nonfloat_missing_symbol;
348  __fit_range = from.__fit_range;
349 
350  if (__real_variable != nullptr) delete __real_variable;
351  __real_variable = from.__real_variable->clone();
352  }
353 
354  return *this;
355  }
356 
357 
359  template < template < typename > class ALLOC >
360  DBTranslator4ContinuousVariable< ALLOC >&
362  operator=(DBTranslator4ContinuousVariable< ALLOC >&& from) {
363  if (this != &from) {
364  DBTranslator< ALLOC >::operator=(std::move(from));
365  __variable = std::move(from.__variable);
366  __status_float_missing_symbols =
367  std::move(from.__status_float_missing_symbols);
368  __nonfloat_missing_symbol = std::move(from.__nonfloat_missing_symbol);
369  __fit_range = from.__fit_range;
370 
371  if (__real_variable != nullptr) delete __real_variable;
372  __real_variable = from.__real_variable;
373  from.__real_variable = nullptr;
374  }
375 
376  return *this;
377  }
378 
379 
381  template < template < typename > class ALLOC >
383  const std::string& str) {
384  // check if the string is actually a number
385  if (!DBCell::isReal(str)) {
386  if (this->isMissingSymbol(str)) {
387  return DBTranslatedValue{std::numeric_limits< float >::max()};
388  } else
389  GUM_ERROR(TypeError,
390  "String \""
391  << str
392  << "\" cannot be translated because it is not a number");
393  }
394 
395  // here we know that the string is a number
396  const float number = std::stof(str);
397 
398  // if we are in the range of the variable, return the number
399  if (__variable.belongs(number)) return DBTranslatedValue{number};
400 
401  // check that this is not a missing value
402  if (this->isMissingSymbol(str)) {
403  if (!__status_float_missing_symbols[str]) {
404  __status_float_missing_symbols[str] = true;
405  }
406  return DBTranslatedValue{std::numeric_limits< float >::max()};
407  }
408 
409  // check if we are allowed to update the domain of the variable
410  if (!__fit_range) {
411  GUM_ERROR(UnknownLabelInDatabase,
412  "String \"" << str
413  << "\" cannot be translated because it is "
414  "out of the domain of the continuous variable");
415  }
416 
417  // now, we can try to add str as a new bound of the range variable
418  // if possible
419 
420  // if the variable is empty, set the min and max ranges. Here,
421  // there is no need to check whether the new range would contain an
422  // already translated missing symbol because this was already tested
423  // in the above test.
424  if (__variable.lowerBound() == std::numeric_limits< float >::infinity()) {
425  __variable.setLowerBound(number);
426  __variable.setUpperBound(number);
427  return DBTranslatedValue{number};
428  }
429 
430  // here, the domain is not empty. So we should update either the
431  // lower bound or the upper bound of the variable, unless
432  // a missing symbol lies within the new bounds and we have already
433  // translated it.
434  const float lower_bound = __variable.lowerBound();
435  const float upper_bound = __variable.upperBound();
436  if (number < lower_bound) {
437  // check that there does not already exist a translated missing
438  // value within the new bounds of the variable
439  for (const auto& missing : __status_float_missing_symbols) {
440  if (missing.second) {
441  const float miss_val = std::stof(missing.first);
442  if ((miss_val >= number) && (miss_val <= upper_bound)) {
443  GUM_ERROR(OperationNotAllowed,
444  "String \""
445  << str << "\" cannot be translated because "
446  << "it would induce a new domain containing an already "
447  << "translated missing symbol");
448  }
449  }
450  }
451 
452  // remove all the missing symbols that were not translated yet and
453  // that lie within the new bounds of the variable
454  for (auto iter = __status_float_missing_symbols.beginSafe();
455  iter != __status_float_missing_symbols.endSafe();
456  ++iter) {
457  if (iter.val() == false) {
458  const float miss_val = std::stof(iter.key());
459  if ((miss_val >= number) && (miss_val <= upper_bound)) {
460  this->_missing_symbols.erase(iter.key());
461  __status_float_missing_symbols.erase(iter);
462  }
463  }
464  }
465 
466  // update the domain of the continuous variable
467  __variable.setLowerBound(number);
468 
469  return DBTranslatedValue{number};
470  } else {
471  // check that there does not already exist a translated missing
472  // value within the new bounds of the variable
473  for (const auto& missing : __status_float_missing_symbols) {
474  if (missing.second) {
475  const float miss_val = std::stof(missing.first);
476  if ((miss_val >= lower_bound) && (miss_val <= number)) {
477  GUM_ERROR(OperationNotAllowed,
478  "String \""
479  << str << "\" cannot be translated because "
480  << "it would induce a new domain containing an already "
481  << "translated missing symbol");
482  }
483  }
484  }
485 
486  // remove all the missing symbols that were not translated yet and
487  // that lie within the new bounds of the variable
488  for (auto iter = __status_float_missing_symbols.beginSafe();
489  iter != __status_float_missing_symbols.endSafe();
490  ++iter) {
491  if (iter.val() == false) {
492  const float miss_val = std::stof(iter.key());
493  if ((miss_val >= lower_bound) && (miss_val <= number)) {
494  this->_missing_symbols.erase(iter.key());
495  __status_float_missing_symbols.erase(iter);
496  }
497  }
498  }
499 
500  // update the domain of the continuous variable
501  __variable.setUpperBound(number);
502 
503  return DBTranslatedValue{number};
504  }
505  }
506 
507 
509  template < template < typename > class ALLOC >
511  const DBTranslatedValue translated_val) const {
512  if (translated_val.cont_val == std::numeric_limits< float >::max()) {
513  if (!__nonfloat_missing_symbol.empty()) return __nonfloat_missing_symbol;
514  if (this->_missing_symbols.empty())
515  return *(this->_missing_symbols.begin());
516  }
517 
518  if ((translated_val.cont_val < __variable.lowerBound())
519  || (translated_val.cont_val > __variable.upperBound())) {
520  GUM_ERROR(UnknownLabelInDatabase,
521  "The back translation of "
522  << translated_val.cont_val
523  << " could not be found because the value is outside the "
524  << "domain of the continuous variable");
525  }
526 
527  char buffer[100];
528  sprintf(buffer, "%g", translated_val.cont_val);
529  return std::string(buffer);
530  }
531 
532 
534  template < template < typename > class ALLOC >
536  return false;
537  }
538 
539 
541  template < template < typename > class ALLOC >
542  INLINE HashTable< std::size_t,
543  std::size_t,
544  ALLOC< std::pair< std::size_t, std::size_t > > >
546  return HashTable< std::size_t,
547  std::size_t,
548  ALLOC< std::pair< std::size_t, std::size_t > > >();
549  }
550 
551 
553  template < template < typename > class ALLOC >
554  INLINE std::size_t
556  return std::numeric_limits< std::size_t >::max();
557  }
558 
559 
561  template < template < typename > class ALLOC >
562  INLINE const IContinuousVariable*
564  __real_variable->setLowerBoundFromDouble(__variable.lowerBound());
565  __real_variable->setUpperBoundFromDouble(__variable.upperBound());
566  return __real_variable;
567  }
568 
569 
571  template < template < typename > class ALLOC >
572  INLINE DBTranslatedValue
574  return DBTranslatedValue{std::numeric_limits< float >::max()};
575  }
576 
577 
578  } /* namespace learning */
579 
580 } /* namespace gum */
581 
582 
583 #endif /* DOXYGEN_SHOULD_SKIP_THIS */
virtual DBTranslatedValue translate(const std::string &str) final
returns the translation of a string
virtual void setLowerBoundFromDouble(const double new_bound)=0
updates the lower bound of the domain of the variable
bool empty() const noexcept
Indicates whether the set is the empty set.
Definition: set_tpl.h:707
typename DBTranslator< ALLOC >::allocator_type allocator_type
type for the allocators passed in arguments of methods
virtual DBTranslator4ContinuousVariable< ALLOC > * clone() const
virtual copy constructor
STL namespace.
Copyright 2005-2019 Pierre-Henri WUILLEMIN et Christophe GONZALES (LIP6) {prenom.nom}_at_lip6.fr.
void erase(const Key &k)
Erases an element from the set.
Definition: set_tpl.h:656
Copyright 2005-2019 Pierre-Henri WUILLEMIN et Christophe GONZALES (LIP6) {prenom.nom}_at_lip6.fr.
Definition: agrum.h:25
DBTranslator(DBTranslatedValueType val_type, const std::vector< std::string, XALLOC< std::string > > &missing_symbols, const bool editable_dictionary=true, std::size_t max_dico_entries=std::numeric_limits< std::size_t >::max(), const allocator_type &alloc=allocator_type())
default constructor
iterator begin() const
The usual unsafe begin iterator to parse the set.
Definition: set_tpl.h:517
DBTranslator4ContinuousVariable< ALLOC > & operator=(const DBTranslator4ContinuousVariable< ALLOC > &from)
copy operator
const iterator_safe & endSafe() const noexcept
The usual safe end iterator to parse the set.
Definition: set_tpl.h:502
virtual std::size_t domainSize() const final
returns std::numeric_limits<std::size_t>::max ()
DBTranslator4ContinuousVariable(const std::vector< std::string, XALLOC< std::string > > &missing_symbols, const bool fit_range=false, const allocator_type &alloc=allocator_type())
default constructor without any initial variable
virtual bool needsReordering() const final
indicates that the translations should never be reordered
allocator_type getAllocator() const
returns the allocator used by the translator
Copyright 2005-2019 Pierre-Henri WUILLEMIN et Christophe GONZALES (LIP6) {prenom.nom}_at_lip6.fr.
DBTranslatedValueType
The nature of the elements handled by translators (discrete, continuous).
static bool isReal(const std::string &str)
determine whether a string corresponds precisely to a real number
Set< std::string, ALLOC< std::string > > _missing_symbols
the set of missing symbols
Definition: DBTranslator.h:385
DBTranslator< ALLOC > & operator=(const DBTranslator< ALLOC > &from)
copy operator
virtual HashTable< std::size_t, std::size_t, ALLOC< std::pair< std::size_t, std::size_t > > > reorder() final
returns an empty mapping, indicating that old tanslations are equal to the newly reordered ones...
virtual std::string translateBack(const DBTranslatedValue translated_val) const final
returns the original value for a given translation
iterator_safe beginSafe() const
The usual safe begin iterator to parse the set.
Definition: set_tpl.h:488
bool isMissingSymbol(const std::string &str) const
indicates whether a string corresponds to a missing symbol
#define GUM_ERROR(type, msg)
Definition: exceptions.h:55
virtual const IContinuousVariable * variable() const final
returns the variable stored into the translator
virtual DBTranslatedValue missingValue() const final
returns the translation of a missing value