aGrUM 3.1.1
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-2026 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-2026 *
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
41#pragma once
42#include <agrum/base/variables/discretizedVariable.h> // to ease IDE parser
43#pragma once
44
45#ifndef DOXYGEN_SHOULD_SKIP_THIS
46# include <limits>
47# include <sstream>
48
50
53
54namespace gum {
55 template < typename T_TICKS >
57 eraseTicks();
59 _is_empirical = aDRV._is_empirical;
60 _ticks_ = aDRV._ticks_;
61 }
62
63 template < typename T_TICKS >
64 Idx DiscretizedVariable< T_TICKS >::pos_(const T_TICKS& target) const {
65 if (_ticks_.empty()) { GUM_ERROR(OutOfBounds, "No tick defined for variable " << name()) }
66
67 if (target < _ticks_[0]) return static_cast< Idx >(0);
68 if (target > _ticks_[_ticks_.size() - 1]) return static_cast< Idx >(_ticks_.size() - 2);
69 // now target is in the range [T1,Tn]
70 const Idx res = std::lower_bound(_ticks_.begin(), _ticks_.end(), target) - _ticks_.begin();
71 if (res + 1 >= _ticks_.size()) return static_cast< Idx >(_ticks_.size() - 2);
72 if (_ticks_[res] == target) return res;
73 // here res>0 because target>=_ticks_[0]
74 return res - 1;
75 }
76
77 template < typename T_TICKS >
78 Idx DiscretizedVariable< T_TICKS >::index(const T_TICKS target) const {
79 const Idx ind = std::lower_bound(_ticks_.begin(), _ticks_.end(), target) - _ticks_.begin();
80 if (ind + 1 >= _ticks_.size()) {
81 GUM_ERROR(OutOfBounds, target << " is not a tick in " << *this)
82 }
83 if (_ticks_[ind] == target) return ind;
84
85 GUM_ERROR(OutOfBounds, target << " is not a tick in " << *this)
86 }
87
88 template < typename T_TICKS >
89 bool DiscretizedVariable< T_TICKS >::isTick(const T_TICKS& target) const {
90 const Size ind = std::lower_bound(_ticks_.begin(), _ticks_.end(), target) - _ticks_.begin();
91 if (ind >= _ticks_.size()) { return false; }
92 return (_ticks_[ind] == target);
93 }
94
95 template < typename T_TICKS >
97 std::string_view aDesc) :
98 IDiscretizedVariable(aName, aDesc) {
99 GUM_CONSTRUCTOR(DiscretizedVariable);
100 _is_empirical = false;
101 _ticks_.reserve(10);
102 }
103
104 template < typename T_TICKS >
105 DiscretizedVariable< T_TICKS >::DiscretizedVariable(std::string_view aName,
106 std::string_view aDesc,
107 const std::vector< T_TICKS >& ticks,
108 bool is_empirical) :
109 IDiscretizedVariable(aName, aDesc) {
110 GUM_CONSTRUCTOR(DiscretizedVariable)
111 _is_empirical = is_empirical;
112 _ticks_.reserve(ticks.size());
113 for (const auto tick: ticks) {
114 if (!gum::isfinite< double >(tick)) {
115 GUM_ERROR(DefaultInLabel, "Value '" << tick << "' is not allowed for variable " << aName)
116 }
117 if (!isTick(tick)) { _ticks_.push_back(tick); }
118 }
119 std::sort(_ticks_.begin(), _ticks_.end());
120 }
121
122 template < typename T_TICKS >
123 DiscretizedVariable< T_TICKS >::DiscretizedVariable(const DiscretizedVariable< T_TICKS >& aDRV) :
124 IDiscretizedVariable(aDRV) {
125 GUM_CONS_CPY(DiscretizedVariable);
126 copy_(aDRV);
127 }
128
129 template < typename T_TICKS >
130 DiscretizedVariable< T_TICKS >::~DiscretizedVariable() {
131 GUM_DESTRUCTOR(DiscretizedVariable);
132 }
133
134 template < typename T_TICKS >
135 DiscretizedVariable< T_TICKS >* DiscretizedVariable< T_TICKS >::clone() const {
136 return new DiscretizedVariable< T_TICKS >(*this);
137 }
138
139 template < typename T_TICKS >
140 DiscretizedVariable< T_TICKS >&
141 DiscretizedVariable< T_TICKS >::operator=(const DiscretizedVariable< T_TICKS >& aDRV) {
142 copy_(aDRV);
143 return *this;
144 }
145
146 template < typename T_TICKS >
147 DiscretizedVariable< T_TICKS >& DiscretizedVariable< T_TICKS >::addTick(const T_TICKS& aTick) {
148 // check if aTick is a float or a special value (infinity or not a number)
149 if (!gum::isfinite(aTick)) {
150 GUM_ERROR(DefaultInLabel, "Tick '" << aTick << "' is not allowed for variable " << name())
151 }
152 if (isTick(aTick)) {
153 GUM_ERROR(DefaultInLabel, "Tick '" << aTick << "' already used for variable " << name())
154 }
155
156 _ticks_.push_back(aTick);
157 std::sort(_ticks_.begin(), _ticks_.end());
158
159 return *this;
160 }
161
162 template < typename T_TICKS >
163 void DiscretizedVariable< T_TICKS >::eraseTicks() {
164 _ticks_.clear();
165 }
166
167 template < typename T_TICKS >
168 std::string DiscretizedVariable< T_TICKS >::label(Idx i) const {
169 if (i + 1 >= _ticks_.size()) { GUM_ERROR(OutOfBounds, "Unexisting label index") }
170
171 const char open = ((i == 0) && _is_empirical) ? '(' : '[';
172 const char close = (i == _ticks_.size() - 2) ? (_is_empirical ? ')' : ']') : '[';
173
174 return std::format("{}{};{}{}", open, _ticks_[i], _ticks_[i + 1], close);
175 }
176
182 template < typename T_TICKS >
183 double DiscretizedVariable< T_TICKS >::numerical(Idx index) const {
184 if (index >= _ticks_.size() - 1) {
185 GUM_ERROR(OutOfBounds, "Unexisting label index (" << index << ") for " << *this << ".")
186 }
187 const auto& a = static_cast< double >(_ticks_[index]);
188 const auto& b = static_cast< double >(_ticks_[index + 1]);
189
190 return (b + a) / 2.0;
191 }
192
198 template < typename T_TICKS >
199 double DiscretizedVariable< T_TICKS >::draw(Idx indice) const {
200 if (indice >= _ticks_.size() - 1) {
201 GUM_ERROR(OutOfBounds, "Unexisting label index (" << indice << ") for " << *this << ".")
202 }
203 const auto& a = static_cast< double >(_ticks_[indice]);
204 const auto& b = static_cast< double >(_ticks_[indice + 1]);
205
206 auto p = gum::randomProba() * (b - a) + a;
207 if (indice < _ticks_.size() - 2) { // p can not be b. We iterate 3 times before returning the
208 // median (should not be possible)
209 if (p == b) p = gum::randomProba() * (b - a) + a;
210 if (p == b) p = gum::randomProba() * (b - a) + a;
211 if (p == b) p = (b - a) / 2;
212 }
213
214 return p;
215 }
216
217 template < typename T_TICKS >
218 Idx DiscretizedVariable< T_TICKS >::index(std::string_view label) const {
219 if (empty()) { GUM_ERROR(OutOfBounds, "empty variable : " + toString()) }
220
221 // first check if label contains a numeric value
222 std::istringstream i(std::string{label});
223 T_TICKS target;
224 if (i >> target) {
225 if (target < _ticks_[0]) {
226 if (_ticks_[0] - target < 1e-10 * (1.0 + std::abs(static_cast< double >(_ticks_[0]))))
227 return 0;
228 if (_is_empirical) return 0;
229 else
231 "less than first range (< " << _ticks_[0] << ") for " << target << " in "
232 << *this)
233 }
234
235 if (const auto size = _ticks_.size(); target > _ticks_[size - 1]) {
236 if (target - _ticks_[size - 1]
237 < 1e-10 * (1.0 + std::abs(static_cast< double >(_ticks_[size - 1])))) {
238 return size - 2;
239 }
240 if (_is_empirical) {
241 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(std::string{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 bool DiscretizedVariable< T_TICKS >::_checkSameDomain_(const gum::Variable& aRV) const {
280 // we can assume that aRV is a DiscretizedVariable
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 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 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 VarType DiscretizedVariable< T_TICKS >::varType() const {
304 return VarType::DISCRETIZED;
305 }
306
307 template < typename T_TICKS >
308 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::string result = "<";
319
320 if (domainSize() > 0) {
321 result += label(0);
322
323 for (Idx i = 1; i < domainSize(); ++i) {
324 result += ",";
325 result += label(i);
326 }
327 }
328
329 result += ">";
330
331 return result;
332 }
333
334 template < typename T_TICKS >
335 const std::vector< T_TICKS >& DiscretizedVariable< T_TICKS >::ticks() const {
336 return this->_ticks_;
337 }
338
339 template < typename T_TICKS >
340 std::vector< double > DiscretizedVariable< T_TICKS >::ticksAsDoubles() const {
341 const std::size_t size = _ticks_.size();
342 std::vector< double > ticks(size);
343 for (auto i = static_cast< std::size_t >(0); i < size; ++i)
344 ticks[i] = static_cast< double >(_ticks_[i]);
345 return ticks;
346 }
347
348 template < typename T_TICKS >
349 std::string DiscretizedVariable< T_TICKS >::toFast() const {
350 std::string result = name();
351 if (_is_empirical) result += "+";
352 result += "[";
353 bool first = true;
354 for (const auto& t: _ticks_) {
355 if (!first) result += ",";
356 else first = false;
357 result += std::format("{}", t);
358 }
359 result += "]";
360 return result;
361 }
362
363 template < typename T_TICKS >
364 std::string DiscretizedVariable< T_TICKS >::stype() const {
365 return "Discretized";
366 }
367} /* namespace gum */
368
369#endif /* DOXYGEN_SHOULD_SKIP_THIS */
Exception : default in label.
Class for discretized random variable.
DiscretizedVariable(std::string_view aName, std::string_view 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_)
Idx index(std::string_view label) const override
from the label to its index in var.
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:81
void copy_(const Variable &aRV)
protected copy
#define GUM_ERROR(type, msg)
Definition exceptions.h:76
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)
VarType
Definition variable.h:62
Contains useful methods for random stuff.