aGrUM 2.3.2
a C++ library for (probabilistic) graphical models
discretizedVariable_tpl.h
Go to the documentation of this file.
1/****************************************************************************
2 * This file is part of the aGrUM/pyAgrum library. *
3 * *
4 * Copyright (c) 2005-2025 by *
5 * - Pierre-Henri WUILLEMIN(_at_LIP6) *
6 * - Christophe GONZALES(_at_AMU) *
7 * *
8 * The aGrUM/pyAgrum library is free software; you can redistribute it *
9 * and/or modify it under the terms of either : *
10 * *
11 * - the GNU Lesser General Public License as published by *
12 * the Free Software Foundation, either version 3 of the License, *
13 * or (at your option) any later version, *
14 * - the MIT license (MIT), *
15 * - or both in dual license, as here. *
16 * *
17 * (see https://agrum.gitlab.io/articles/dual-licenses-lgplv3mit.html) *
18 * *
19 * This aGrUM/pyAgrum library is distributed in the hope that it will be *
20 * useful, but WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
21 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES MERCHANTABILITY or FITNESS *
22 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
25 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
26 * OTHER DEALINGS IN THE SOFTWARE. *
27 * *
28 * See LICENCES for more details. *
29 * *
30 * SPDX-FileCopyrightText: Copyright 2005-2025 *
31 * - Pierre-Henri WUILLEMIN(_at_LIP6) *
32 * - Christophe GONZALES(_at_AMU) *
33 * SPDX-License-Identifier: LGPL-3.0-or-later OR MIT *
34 * *
35 * Contact : info_at_agrum_dot_org *
36 * homepage : http://agrum.gitlab.io *
37 * gitlab : https://gitlab.com/agrumery/agrum *
38 * *
39 ****************************************************************************/
40#pragma once
41#pragma once
42
43#ifndef DOXYGEN_SHOULD_SKIP_THIS
44# include <limits>
45# include <sstream>
46
48
51
52namespace gum {
53 template < typename T_TICKS >
55 eraseTicks();
57 _is_empirical = aDRV._is_empirical;
58 _ticks_ = aDRV._ticks_;
59 }
60
61 template < typename T_TICKS >
62 INLINE Idx DiscretizedVariable< T_TICKS >::pos_(const T_TICKS& target) const {
63 if (target < _ticks_[0]) return static_cast< Idx >(0);
64 if (target > _ticks_[_ticks_.size() - 1]) return static_cast< Idx >(_ticks_.size() - 2);
65 // now target is in the range [T1,Tn]
66 const Idx res = std::lower_bound(_ticks_.begin(), _ticks_.end(), target) - _ticks_.begin();
67 if (res + 1 >= _ticks_.size()) return static_cast< Idx >(_ticks_.size() - 2);
68 if (_ticks_[res] == target) return res;
69 // here res>0 because target>=_ticks_[0]
70 return res - 1;
71 }
72
73 template < typename T_TICKS >
74 INLINE Idx DiscretizedVariable< T_TICKS >::index(const T_TICKS target) const {
75 const Idx ind = std::lower_bound(_ticks_.begin(), _ticks_.end(), target) - _ticks_.begin();
76 if (ind + 1 >= _ticks_.size()) {
77 GUM_ERROR(OutOfBounds, target << " is not a tick in " << *this)
78 }
79 if (_ticks_[ind] == target) return ind;
80
81 GUM_ERROR(OutOfBounds, target << " is not a tick in " << *this)
82 }
83
84 template < typename T_TICKS >
85 INLINE bool DiscretizedVariable< T_TICKS >::isTick(const T_TICKS& target) const {
86 const Size ind = std::lower_bound(_ticks_.begin(), _ticks_.end(), target) - _ticks_.begin();
87 if (ind >= _ticks_.size()) { return false; }
88 return (_ticks_[ind] == target);
89 }
90
91 template < typename T_TICKS >
92 INLINE DiscretizedVariable< T_TICKS >::DiscretizedVariable(const std::string& aName,
93 const std::string& aDesc) :
94 IDiscretizedVariable(aName, aDesc) {
95 GUM_CONSTRUCTOR(DiscretizedVariable);
96 _is_empirical = false;
97 _ticks_.reserve(10);
98 }
99
100 template < typename T_TICKS >
101 INLINE DiscretizedVariable< T_TICKS >::DiscretizedVariable(const std::string& aName,
102 const std::string& aDesc,
103 const std::vector< T_TICKS >& ticks,
104 bool is_empirical) :
105 IDiscretizedVariable(aName, aDesc) {
106 GUM_CONSTRUCTOR(DiscretizedVariable)
107 _is_empirical = is_empirical;
108 _ticks_.reserve(ticks.size());
109 for (const auto tick: ticks) {
110 if (!gum::isfinite< double >(tick)) {
111 GUM_ERROR(DefaultInLabel, "Value '" << tick << "' is not allowed for variable " << aName)
112 }
113 if (!isTick(tick)) { _ticks_.push_back(tick); }
114 }
115 std::sort(_ticks_.begin(), _ticks_.end());
116 }
117
118 template < typename T_TICKS >
119 DiscretizedVariable< T_TICKS >::DiscretizedVariable(const DiscretizedVariable< T_TICKS >& aDRV) :
120 IDiscretizedVariable(aDRV) {
121 GUM_CONS_CPY(DiscretizedVariable);
122 copy_(aDRV);
123 }
124
125 template < typename T_TICKS >
126 DiscretizedVariable< T_TICKS >::~DiscretizedVariable() {
127 GUM_DESTRUCTOR(DiscretizedVariable);
128 }
129
130 template < typename T_TICKS >
131 DiscretizedVariable< T_TICKS >* DiscretizedVariable< T_TICKS >::clone() const {
132 return new DiscretizedVariable< T_TICKS >(*this);
133 }
134
135 template < typename T_TICKS >
136 INLINE DiscretizedVariable< T_TICKS >&
137 DiscretizedVariable< T_TICKS >::operator=(const DiscretizedVariable< T_TICKS >& aDRV) {
138 copy_(aDRV);
139 return *this;
140 }
141
142 template < typename T_TICKS >
143 DiscretizedVariable< T_TICKS >& DiscretizedVariable< T_TICKS >::addTick(const T_TICKS& aTick) {
144 // check if aTick is a float or a special value (infinity or not a number)
145 if (!gum::isfinite(aTick)) {
146 GUM_ERROR(DefaultInLabel, "Tick '" << aTick << "' is not allowed for variable " << name())
147 }
148 if (isTick(aTick)) {
149 GUM_ERROR(DefaultInLabel, "Tick '" << aTick << "' already used for variable " << name())
150 }
151
152 _ticks_.push_back(aTick);
153 std::sort(_ticks_.begin(), _ticks_.end());
154
155 return *this;
156 }
157
158 template < typename T_TICKS >
159 INLINE void DiscretizedVariable< T_TICKS >::eraseTicks() {
160 _ticks_.clear();
161 }
162
163 template < typename T_TICKS >
164 INLINE std::string DiscretizedVariable< T_TICKS >::label(Idx i) const {
165 std::stringstream ss;
166
167 if (i >= _ticks_.size() - 1) { GUM_ERROR(OutOfBounds, "Unexisting label index") }
168
169 if ((i == 0) && _is_empirical) ss << "(";
170 else ss << "[";
171
172 ss << std::format("{};{}", _ticks_[i], _ticks_[i + 1]);
173
174 if (i == _ticks_.size() - 2) {
175 if (_is_empirical) ss << ")";
176 else ss << "]";
177 } else ss << "[";
178
179 return ss.str();
180 }
181
187 template < typename T_TICKS >
188 INLINE double DiscretizedVariable< T_TICKS >::numerical(Idx index) const {
189 if (index >= _ticks_.size() - 1) {
190 GUM_ERROR(OutOfBounds, "Unexisting label index (" << index << ") for " << *this << ".")
191 }
192 const auto& a = static_cast< double >(_ticks_[index]);
193 const auto& b = static_cast< double >(_ticks_[index + 1]);
194
195 return (b + a) / 2.0;
196 }
197
203 template < typename T_TICKS >
204 INLINE double DiscretizedVariable< T_TICKS >::draw(Idx indice) const {
205 if (indice >= _ticks_.size() - 1) {
206 GUM_ERROR(OutOfBounds, "Unexisting label index (" << indice << ") for " << *this << ".")
207 }
208 const auto& a = static_cast< double >(_ticks_[indice]);
209 const auto& b = static_cast< double >(_ticks_[indice + 1]);
210
211 auto p = gum::randomProba() * (b - a) + a;
212 if (indice < _ticks_.size() - 2) { // p can not be b. We iterate 3 times before returning the
213 // median (should not be possible)
214 if (p == b) p = gum::randomProba() * (b - a) + a;
215 if (p == b) p = gum::randomProba() * (b - a) + a;
216 if (p == b) p = (b - a) / 2;
217 }
218
219 return p;
220 }
221
222 template < typename T_TICKS >
223 INLINE Idx DiscretizedVariable< T_TICKS >::index(const std::string& label) const {
224 if (empty()) { GUM_ERROR(OutOfBounds, "empty variable : " + toString()) }
225
226 // first check if label contains a numeric value
227 std::istringstream i(label);
228 T_TICKS target;
229 if (i >> target) {
230 if (target < _ticks_[0]) {
231 if (_ticks_[0] - target < 1e-10) return 0;
232 if (_is_empirical) return 0;
233 else
235 "less than first range (< " << _ticks_[0] << ") for " << target << " in "
236 << *this)
237 }
238
239 if (const auto size = _ticks_.size(); target > _ticks_[size - 1]) {
240 if (target - _ticks_[size - 1] < 1e-10) return size - 2;
241 if (_is_empirical) return size - 2;
242 else
244 "more than last range (> " << _ticks_[size - 1] << ") for " << target << " in "
245 << *this << ":" << target - _ticks_[size - 1])
246 }
247
248 return pos_(target);
249 }
250
251 // second check if label contains an interval '[t1;t2]'
252 std::istringstream ii(label);
253 T_TICKS t2;
254 char c1;
255 char c2;
256 char c3;
257 if (!(ii >> c1 >> target >> c2 >> t2 >> c3)) {
258 GUM_ERROR(NotFound, "Bad label : " << label << " for " << *this)
259 }
260
261 // check if a char is in a string
262 const std::string s1{"[]()"};
263 if (const std::string s2{",;"}; s1.find(c1) == std::string::npos
264 || (s1.find(c3) == std::string::npos)
265 || (s2.find(c2) == std::string::npos)) {
266 GUM_ERROR(NotFound, "Bad syntax for interval : " << label << " for " << *this)
267 }
268
269 const Idx it1 = pos_(target);
270
271 if ((it1 + 1 >= _ticks_.size()) || (t2 != _ticks_[it1 + 1])) {
272 GUM_ERROR(NotFound, "Bad interval : " << label << " for " << *this)
273 }
274
275 return it1;
276 }
277
278 template < typename T_TICKS >
279 INLINE bool DiscretizedVariable< T_TICKS >::_checkSameDomain_(const gum::Variable& aRV) const {
280 // we can assume that aRV is a ContinuousVariable
281 const auto& cv = static_cast< const DiscretizedVariable< T_TICKS >& >(aRV);
282 if (domainSize() != cv.domainSize()) return false;
283 return cv._ticks_ == _ticks_ && cv._is_empirical == _is_empirical;
284 }
285
286 template < typename T_TICKS >
287 INLINE Idx DiscretizedVariable< T_TICKS >::closestIndex(double val) const {
288 if (val <= _ticks_[0]) { return 0; }
289 if (val >= _ticks_[_ticks_.size() - 1]) { return _ticks_.size() - 2; }
290 return pos_(static_cast< T_TICKS >(val));
291 }
292
297 template < typename T_TICKS >
298 INLINE Size DiscretizedVariable< T_TICKS >::domainSize() const {
299 return (_ticks_.size() < 2) ? static_cast< Size >(0) : static_cast< Size >(_ticks_.size() - 1);
300 }
301
302 template < typename T_TICKS >
303 INLINE VarType DiscretizedVariable< T_TICKS >::varType() const {
304 return VarType::DISCRETIZED;
305 }
306
307 template < typename T_TICKS >
308 INLINE const T_TICKS& DiscretizedVariable< T_TICKS >::tick(Idx i) const {
309 if (i >= _ticks_.size()) {
310 GUM_ERROR(OutOfBounds, "There is no such tick " << i << " for " << *this << ".")
311 }
312
313 return _ticks_[i];
314 }
315
316 template < typename T_TICKS >
317 std::string DiscretizedVariable< T_TICKS >::domain() const {
318 std::stringstream s;
319 s << "<";
320
321 if (domainSize() > 0) {
322 s << label(0);
323
324 for (Idx i = 1; i < domainSize(); ++i) {
325 s << ",";
326 s << label(i);
327 }
328 }
329
330 s << ">";
331
332 return s.str();
333 }
334
335 template < typename T_TICKS >
336 INLINE const std::vector< T_TICKS >& DiscretizedVariable< T_TICKS >::ticks() const {
337 return this->_ticks_;
338 }
339
340 template < typename T_TICKS >
341 INLINE std::vector< double > DiscretizedVariable< T_TICKS >::ticksAsDoubles() const {
342 const std::size_t size = _ticks_.size();
343 std::vector< double > ticks(size);
344 for (auto i = static_cast< std::size_t >(0); i < size; ++i)
345 ticks[i] = static_cast< double >(_ticks_[i]);
346 return ticks;
347 }
348
349 template < typename T_TICKS >
350 std::string DiscretizedVariable< T_TICKS >::toFast() const {
351 std::stringstream s;
352 bool first = true;
353 s << name();
354 if (_is_empirical) s << "+";
355 s << "[";
356 for (const auto& t: _ticks_) {
357 if (!first) s << ",";
358 else first = false;
359 s << std::format("{}", t);
360 }
361 s << "]";
362 return s.str();
363 }
364
365} /* namespace gum */
366
367#endif /* DOXYGEN_SHOULD_SKIP_THIS */
Exception : default in label.
Class for discretized random variable.
Idx index(const std::string &label) const override
from the label to its index in var.
DiscretizedVariable(const std::string &aName, const std::string &aDesc)
Constructor.
bool isTick(const T_TICKS &aTick) const
void copy_(const DiscretizedVariable< T_TICKS > &aDRV)
make a copy
Idx pos_(const T_TICKS &target) const
search the class of target (internally use dichotomy_)
A base class for discretized variables, independent of the ticks type.
Exception : the element we looked for cannot be found.
Exception : out of bound.
Base class for every random variable.
Definition variable.h:79
void copy_(const Variable &aRV)
protected copy
#define GUM_ERROR(type, msg)
Definition exceptions.h:72
std::size_t Size
In aGrUM, hashed values are unsigned long int.
Definition types.h:74
Size Idx
Type for indexes.
Definition types.h:79
double randomProba()
Returns a random double between 0 and 1 included (i.e.
Useful macros for maths.
gum is the global namespace for all aGrUM entities
Definition agrum.h:46
bool isfinite(T arg)
Definition math_utils.h:75
VarType
Definition variable.h:60
Contains useful methods for random stuff.