1 /** 2 * 3 * Copyright (c) 2005-2021 by Pierre-Henri WUILLEMIN(_at_LIP6) et Christophe GONZALES(_at_AMU) 4 * (_at_AMU) 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 /** 23 * @file 24 * @brief Implementation of the Potential class. 25 * @author Pierre-Henri WUILLEMIN(_at_LIP6) & Christophe GONZALES(_at_AMU) 26 */ 27 28 #include <agrum/agrum.h> 29 #include <agrum/tools/core/math/math_utils.h> 30 #include <agrum/tools/multidim/potential.h> 31 32 namespace gum { 33 34 // Default constructor: creates an empty null dimensional matrix 35 // choose a MultiDimArray<> as decorated implementation 36 template < typename GUM_SCALAR > Potential()37 INLINE Potential< GUM_SCALAR >::Potential() : 38 MultiDimDecorator< GUM_SCALAR >(new MultiDimArray< GUM_SCALAR >(), GUM_SCALAR(1)) { 39 GUM_CONSTRUCTOR(Potential); 40 } 41 42 // constructor using aContent as content 43 template < typename GUM_SCALAR > Potential(MultiDimImplementation<GUM_SCALAR> * aContent)44 INLINE Potential< GUM_SCALAR >::Potential(MultiDimImplementation< GUM_SCALAR >* aContent) : 45 MultiDimDecorator< GUM_SCALAR >(aContent, GUM_SCALAR(1)) { 46 // for debugging purposes 47 GUM_CONSTRUCTOR(Potential); 48 } 49 // copy constructor 50 template < typename GUM_SCALAR > Potential(const Potential<GUM_SCALAR> & src)51 INLINE Potential< GUM_SCALAR >::Potential(const Potential< GUM_SCALAR >& src) : 52 Potential< GUM_SCALAR >( 53 static_cast< MultiDimImplementation< GUM_SCALAR >* >(src.content()->newFactory()), 54 *(src.content())) { 55 this->empty_value_ = src.empty_value_; 56 // GUM_CONS_CPY not here because in called Potential 57 // GUM_CONS_CPY( Potential ); 58 } 59 60 /// move constructor 61 template < typename GUM_SCALAR > Potential(Potential<GUM_SCALAR> && from)62 INLINE Potential< GUM_SCALAR >::Potential(Potential< GUM_SCALAR >&& from) : 63 MultiDimDecorator< GUM_SCALAR >(std::forward< MultiDimDecorator< GUM_SCALAR > >(from)) { 64 GUM_CONS_MOV(Potential); 65 } 66 67 // complex copy constructor : we choose the implementation 68 template < typename GUM_SCALAR > Potential(MultiDimImplementation<GUM_SCALAR> * aContent,const MultiDimContainer<GUM_SCALAR> & src)69 Potential< GUM_SCALAR >::Potential(MultiDimImplementation< GUM_SCALAR >* aContent, 70 const MultiDimContainer< GUM_SCALAR >& src) : 71 MultiDimDecorator< GUM_SCALAR >(aContent) { 72 // for debugging purposes 73 GUM_CONSTRUCTOR(Potential); 74 75 if (!src.empty()) { 76 this->beginMultipleChanges(); 77 78 for (Idx i = 0; i < src.variablesSequence().size(); i++) { 79 this->add(*(src.variablesSequence()[i])); 80 } 81 82 this->endMultipleChanges(); 83 this->content()->copyFrom(*src.content()); 84 } 85 } 86 87 // operator = copy 88 template < typename GUM_SCALAR > 89 Potential< GUM_SCALAR >& Potential< GUM_SCALAR >::operator=(const Potential< GUM_SCALAR >& src) { 90 GUM_OP_CPY(Potential); 91 if (&src == this) return *this; 92 MultiDimDecorator< GUM_SCALAR >::operator=(src); 93 return *this; 94 } 95 96 // operator = move 97 template < typename GUM_SCALAR > 98 Potential< GUM_SCALAR >& Potential< GUM_SCALAR >::operator=(Potential< GUM_SCALAR >&& src) { 99 GUM_OP_MOV(Potential); 100 if (&src == this) return *this; 101 MultiDimDecorator< GUM_SCALAR >::operator=( 102 std::forward< MultiDimDecorator< GUM_SCALAR > >(src)); 103 return *this; 104 } 105 106 // destructor 107 108 template < typename GUM_SCALAR > ~Potential()109 Potential< GUM_SCALAR >::~Potential() { 110 // for debugging purposes 111 GUM_DESTRUCTOR(Potential); 112 } 113 114 template < typename GUM_SCALAR > newFactory()115 INLINE Potential< GUM_SCALAR >* Potential< GUM_SCALAR >::newFactory() const { 116 return new Potential< GUM_SCALAR >( 117 static_cast< MultiDimImplementation< GUM_SCALAR >* >(this->content()->newFactory())); 118 } 119 120 // sum of all elements in this 121 template < typename GUM_SCALAR > sum()122 INLINE GUM_SCALAR Potential< GUM_SCALAR >::sum() const { 123 if (static_cast< MultiDimContainer< GUM_SCALAR >* >(this->content_)->empty()) { 124 return this->empty_value_; 125 } 126 return gum::projectSum(*this->content()); 127 } 128 // product of all elements in this 129 template < typename GUM_SCALAR > product()130 INLINE GUM_SCALAR Potential< GUM_SCALAR >::product() const { 131 if (static_cast< MultiDimContainer< GUM_SCALAR >* >(this->content_)->empty()) { 132 return this->empty_value_; 133 } 134 return gum::projectProduct(*this->content()); 135 } 136 // max of all elements in this 137 template < typename GUM_SCALAR > max()138 INLINE GUM_SCALAR Potential< GUM_SCALAR >::max() const { 139 if (static_cast< MultiDimContainer< GUM_SCALAR >* >(this->content_)->empty()) { 140 return this->empty_value_; 141 } 142 return gum::projectMax(*this->content()); 143 } 144 // min of all elements in this 145 template < typename GUM_SCALAR > min()146 INLINE GUM_SCALAR Potential< GUM_SCALAR >::min() const { 147 if (static_cast< MultiDimContainer< GUM_SCALAR >* >(this->content_)->empty()) { 148 return this->empty_value_; 149 } 150 return gum::projectMin(*this->content()); 151 } 152 153 // max of all non one elements in this 154 // warning can return 1 if no other value than 1 ... 155 template < typename GUM_SCALAR > maxNonOne()156 GUM_SCALAR Potential< GUM_SCALAR >::maxNonOne() const { 157 GUM_SCALAR res; 158 159 if (static_cast< MultiDimContainer< GUM_SCALAR >* >(this->content_)->empty()) { 160 res = this->empty_value_; 161 } else { 162 res = this->reduce( 163 [](GUM_SCALAR z, GUM_SCALAR p) { 164 return (p == static_cast< GUM_SCALAR >(1)) ? z 165 : (z == static_cast< GUM_SCALAR >(1)) ? p 166 : (p > z ? p : z); 167 }, 168 static_cast< GUM_SCALAR >(1)); 169 } 170 171 return res; 172 } 173 174 // min of all non zero elements in this 175 // warning can return 0 if no other value than 0 ... 176 template < typename GUM_SCALAR > minNonZero()177 INLINE GUM_SCALAR Potential< GUM_SCALAR >::minNonZero() const { 178 GUM_SCALAR res; 179 180 if (static_cast< MultiDimContainer< GUM_SCALAR >* >(this->content_)->empty()) { 181 res = this->empty_value_; 182 } else { 183 res = this->reduce( 184 [](GUM_SCALAR z, GUM_SCALAR p) { 185 return (p == static_cast< GUM_SCALAR >(0)) ? z 186 : (z == static_cast< GUM_SCALAR >(0)) ? p 187 : (p < z ? p : z); 188 }, 189 static_cast< GUM_SCALAR >(0)); 190 } 191 return res; 192 } 193 194 // entropy of this 195 template < typename GUM_SCALAR > entropy()196 INLINE GUM_SCALAR Potential< GUM_SCALAR >::entropy() const { 197 if (static_cast< MultiDimContainer< GUM_SCALAR >* >(this->content_)->empty()) { 198 return static_cast< GUM_SCALAR >(0); 199 } 200 201 return this->reduce( 202 [](GUM_SCALAR z, GUM_SCALAR p) { return (p == 0.0) ? z : (z - p * std::log2(p)); }, 203 0.0); 204 } 205 206 template < typename GUM_SCALAR > 207 INLINE const Potential< GUM_SCALAR >& fillWith(const std::vector<GUM_SCALAR> & data)208 Potential< GUM_SCALAR >::fillWith(const std::vector< GUM_SCALAR >& data) const { 209 this->populate(data); 210 return *this; 211 } 212 213 template < typename GUM_SCALAR > 214 INLINE const Potential< GUM_SCALAR >& fillWith(const GUM_SCALAR & val)215 Potential< GUM_SCALAR >::fillWith(const GUM_SCALAR& val) const { 216 this->fill(val); 217 return *this; 218 } 219 220 template < typename GUM_SCALAR > 221 INLINE const Potential< GUM_SCALAR >& fillWith(const Potential<GUM_SCALAR> & src)222 Potential< GUM_SCALAR >::fillWith(const Potential< GUM_SCALAR >& src) const { 223 if (src.domainSize() != this->domainSize()) { 224 GUM_ERROR(InvalidArgument, "Potential to copy has not the same dimension.") 225 } 226 gum::Set< std::string > son; // set of names 227 for (const auto& v: src.variablesSequence()) { 228 son.insert(v->name()); 229 } 230 for (const auto& v: this->variablesSequence()) { 231 if (!son.contains(v->name())) { 232 GUM_ERROR(InvalidArgument, 233 "Variable <" << v->name() << "> not present in src (" << son << ")."); 234 } 235 // we check size, labels and order of labels in the same time 236 if (v->toString() != src.variable(v->name()).toString()) { 237 GUM_ERROR(InvalidArgument, "Variables <" << v->name() << "> are not identical.") 238 } 239 } 240 241 Instantiation Isrc(src); 242 Instantiation Idst(*this); 243 for (Isrc.setFirst(); !Isrc.end(); ++Isrc) { 244 for (Idx i = 0; i < this->nbrDim(); i++) { 245 Idst.chgVal(Isrc.variable(i).name(), Isrc.val(i)); 246 } 247 this->set(Idst, src.get(Isrc)); 248 } 249 250 return *this; 251 } 252 253 template < typename GUM_SCALAR > 254 INLINE const Potential< GUM_SCALAR >& fillWith(const Potential<GUM_SCALAR> & src,const std::vector<std::string> & mapSrc)255 Potential< GUM_SCALAR >::fillWith(const Potential< GUM_SCALAR >& src, 256 const std::vector< std::string >& mapSrc) const { 257 if (src.nbrDim() != this->nbrDim()) { 258 GUM_ERROR(InvalidArgument, "Potential to copy has not the same dimension.") 259 } 260 if (src.nbrDim() != mapSrc.size()) { 261 GUM_ERROR(InvalidArgument, "Potential and vector have not the same dimension.") 262 } 263 Instantiation Isrc; 264 for (Idx i = 0; i < src.nbrDim(); i++) { 265 if (src.variable(mapSrc[i]).domainSize() != this->variable(i).domainSize()) { 266 GUM_ERROR(InvalidArgument, 267 "Variables " << mapSrc[i] << " (in the argument) and " << this->variable(i).name() 268 << " have not the same dimension."); 269 } else { 270 Isrc.add(src.variable(mapSrc[i])); 271 } 272 } 273 Instantiation Idst(*this); 274 for (Isrc.setFirst(); !Isrc.end(); ++Isrc, ++Idst) { 275 this->set(Idst, src.get(Isrc)); 276 } 277 278 return *this; 279 } 280 281 template < typename GUM_SCALAR > sq()282 INLINE const Potential< GUM_SCALAR >& Potential< GUM_SCALAR >::sq() const { 283 this->apply([](GUM_SCALAR x) { return x * x; }); 284 return *this; 285 } 286 287 template < typename GUM_SCALAR > log2()288 INLINE const Potential< GUM_SCALAR >& Potential< GUM_SCALAR >::log2() const { 289 this->apply([](GUM_SCALAR x) { return std::log2(x); }); 290 return *this; 291 } 292 293 template < typename GUM_SCALAR > KL(const Potential<GUM_SCALAR> & p)294 INLINE GUM_SCALAR Potential< GUM_SCALAR >::KL(const Potential< GUM_SCALAR >& p) const { 295 if (this->nbrDim() != p.nbrDim()) 296 GUM_ERROR(InvalidArgument, 297 "BNdistance between potentials with different numbers of dimensions"); 298 for (const auto var: p.variablesSequence()) { 299 if (!this->contains(*var)) 300 GUM_ERROR(InvalidArgument, "A variable in the argument does not belong to the potential.") 301 } 302 for (const auto var: this->variablesSequence()) { 303 if (!p.contains(*var)) 304 GUM_ERROR(InvalidArgument, "A variable does not belong to the argument.") 305 } 306 307 Instantiation inst(*this); 308 GUM_SCALAR res = static_cast< GUM_SCALAR >(0); 309 for (inst.setFirst(); !inst.end(); inst.inc()) { 310 GUM_SCALAR x = this->get(inst); 311 GUM_SCALAR y = p.get(inst); 312 if (static_cast< GUM_SCALAR >(0) == x) // 0*log(0/y)=0 313 continue; 314 315 if (static_cast< GUM_SCALAR >(0) == y) 316 // we know that x!=0; 317 GUM_ERROR(FatalError, "The argument has a 0 at " << inst << " while the potential has not.") 318 319 res += x * std::log2(x / y); 320 } 321 return res; 322 } 323 324 template < typename GUM_SCALAR > abs()325 INLINE const Potential< GUM_SCALAR >& Potential< GUM_SCALAR >::abs() const { 326 this->apply([](GUM_SCALAR x) { 327 if (x >= 0) 328 return x; 329 else 330 return -x; 331 }); 332 return *this; 333 } 334 335 // normalisation of this 336 // do nothing is sum is 0 337 template < typename GUM_SCALAR > normalize()338 INLINE const Potential< GUM_SCALAR >& Potential< GUM_SCALAR >::normalize() const { 339 if (static_cast< MultiDimContainer< GUM_SCALAR >* >(this->content_)->empty()) { 340 if (this->empty_value_ != static_cast< GUM_SCALAR >(0)) 341 this->empty_value_ = static_cast< GUM_SCALAR >(1.0); 342 } else { 343 GUM_SCALAR s = sum(); 344 345 if (s != (GUM_SCALAR)0) { 346 this->apply([s](GUM_SCALAR x) { return x / s; }); 347 } 348 } 349 return *this; 350 } 351 352 template < typename GUM_SCALAR > 353 INLINE const Potential< GUM_SCALAR >& normalizeAsCPT(const Idx & varId)354 Potential< GUM_SCALAR >::normalizeAsCPT(const Idx& varId) const { 355 if (static_cast< MultiDimContainer< GUM_SCALAR >* >(this->content_)->empty()) { 356 if (this->empty_value_ != static_cast< GUM_SCALAR >(0)) { 357 this->empty_value_ = static_cast< GUM_SCALAR >(1.0); 358 } else { 359 GUM_ERROR(FatalError, "Normalization for a potential that sum to 0 in " << *this) 360 } 361 } else { 362 if (varId >= this->nbrDim()) { 363 GUM_ERROR(FatalError, varId << " is not a position for " << *this) 364 } 365 Instantiation inst(*this); 366 const auto& v = this->variable(varId); 367 368 for (inst.setFirst(); !inst.end(); inst.incNotVar(v)) { 369 GUM_SCALAR s = (GUM_SCALAR)0.0; 370 for (inst.setFirstVar(v); !inst.end(); inst.incVar(v)) 371 s += this->get(inst); 372 if (s == (GUM_SCALAR)0.0) { 373 GUM_ERROR(FatalError, "Normalization for a potential that sum to 0 in " << *this) 374 } 375 if (s != (GUM_SCALAR)1.0) { 376 for (inst.setFirstVar(v); !inst.end(); inst.incVar(v)) 377 this->set(inst, this->get(inst) / s); 378 } 379 inst.setFirstVar(v); // to remove inst.end() 380 } 381 } 382 return *this; 383 } 384 385 template < typename GUM_SCALAR > scale(GUM_SCALAR v)386 INLINE const Potential< GUM_SCALAR >& Potential< GUM_SCALAR >::scale(GUM_SCALAR v) const { 387 this->apply([v](GUM_SCALAR x) { return x * v; }); 388 return *this; 389 } 390 391 template < typename GUM_SCALAR > translate(GUM_SCALAR v)392 INLINE const Potential< GUM_SCALAR >& Potential< GUM_SCALAR >::translate(GUM_SCALAR v) const { 393 this->apply([v](GUM_SCALAR x) { return x + v; }); 394 return *this; 395 } 396 397 template < typename GUM_SCALAR > inverse()398 INLINE const Potential< GUM_SCALAR >& Potential< GUM_SCALAR >::inverse() const { 399 this->apply([](GUM_SCALAR x) { return 1 / x; }); 400 return *this; 401 } 402 403 template < typename GUM_SCALAR > 404 INLINE Potential< GUM_SCALAR > margSumOut(const Set<const DiscreteVariable * > & del_vars)405 Potential< GUM_SCALAR >::margSumOut(const Set< const DiscreteVariable* >& del_vars) const { 406 if (static_cast< MultiDimContainer< GUM_SCALAR >* >(this->content_)->empty()) { 407 return Potential< GUM_SCALAR >().fillWith(this->empty_value_); 408 } 409 return Potential< GUM_SCALAR >(gum::projectSum(*this->content(), del_vars)); 410 } 411 412 template < typename GUM_SCALAR > 413 INLINE Potential< GUM_SCALAR > margProdOut(const Set<const DiscreteVariable * > & del_vars)414 Potential< GUM_SCALAR >::margProdOut(const Set< const DiscreteVariable* >& del_vars) const { 415 if (static_cast< MultiDimContainer< GUM_SCALAR >* >(this->content_)->empty()) { 416 return Potential< GUM_SCALAR >().fillWith(this->empty_value_); 417 } 418 return Potential< GUM_SCALAR >(gum::projectProduct(*this->content(), del_vars)); 419 } 420 421 template < typename GUM_SCALAR > 422 INLINE Potential< GUM_SCALAR > margMinOut(const Set<const DiscreteVariable * > & del_vars)423 Potential< GUM_SCALAR >::margMinOut(const Set< const DiscreteVariable* >& del_vars) const { 424 if (static_cast< MultiDimContainer< GUM_SCALAR >* >(this->content_)->empty()) { 425 return Potential< GUM_SCALAR >().fillWith(this->empty_value_); 426 } 427 return Potential< GUM_SCALAR >(gum::projectMin(*this->content(), del_vars)); 428 } 429 430 template < typename GUM_SCALAR > 431 INLINE Potential< GUM_SCALAR > margMaxOut(const Set<const DiscreteVariable * > & del_vars)432 Potential< GUM_SCALAR >::margMaxOut(const Set< const DiscreteVariable* >& del_vars) const { 433 if (static_cast< MultiDimContainer< GUM_SCALAR >* >(this->content_)->empty()) { 434 return Potential< GUM_SCALAR >().fillWith(this->empty_value_); 435 } 436 return Potential< GUM_SCALAR >(gum::projectMax(*this->content(), del_vars)); 437 } 438 template < typename GUM_SCALAR > 439 INLINE Potential< GUM_SCALAR > margSumIn(const Set<const DiscreteVariable * > & kept_vars)440 Potential< GUM_SCALAR >::margSumIn(const Set< const DiscreteVariable* >& kept_vars) const { 441 if (static_cast< MultiDimContainer< GUM_SCALAR >* >(this->content_)->empty()) { 442 return Potential< GUM_SCALAR >().fillWith(this->empty_value_); 443 } 444 return Potential< GUM_SCALAR >(gum::projectSum(*this->content(), complementVars_(kept_vars))); 445 } 446 447 template < typename GUM_SCALAR > 448 INLINE Potential< GUM_SCALAR > margProdIn(const Set<const DiscreteVariable * > & kept_vars)449 Potential< GUM_SCALAR >::margProdIn(const Set< const DiscreteVariable* >& kept_vars) const { 450 if (static_cast< MultiDimContainer< GUM_SCALAR >* >(this->content_)->empty()) { 451 return Potential< GUM_SCALAR >().fillWith(this->empty_value_); 452 } 453 return Potential< GUM_SCALAR >( 454 gum::projectProduct(*this->content(), complementVars_(kept_vars))); 455 } 456 457 template < typename GUM_SCALAR > 458 INLINE Potential< GUM_SCALAR > margMinIn(const Set<const DiscreteVariable * > & kept_vars)459 Potential< GUM_SCALAR >::margMinIn(const Set< const DiscreteVariable* >& kept_vars) const { 460 if (static_cast< MultiDimContainer< GUM_SCALAR >* >(this->content_)->empty()) { 461 return Potential< GUM_SCALAR >().fillWith(this->empty_value_); 462 } 463 return Potential< GUM_SCALAR >(gum::projectMin(*this->content(), complementVars_(kept_vars))); 464 } 465 466 template < typename GUM_SCALAR > 467 INLINE Potential< GUM_SCALAR > margMaxIn(const Set<const DiscreteVariable * > & kept_vars)468 Potential< GUM_SCALAR >::margMaxIn(const Set< const DiscreteVariable* >& kept_vars) const { 469 if (static_cast< MultiDimContainer< GUM_SCALAR >* >(this->content_)->empty()) { 470 return Potential< GUM_SCALAR >().fillWith(this->empty_value_); 471 } 472 return Potential< GUM_SCALAR >(gum::projectMax(*this->content(), complementVars_(kept_vars))); 473 } 474 475 template < typename GUM_SCALAR > isNonZeroMap()476 INLINE Potential< GUM_SCALAR > Potential< GUM_SCALAR >::isNonZeroMap() const { 477 auto p = Potential< GUM_SCALAR >(*this); 478 p.apply([](GUM_SCALAR x) { 479 if (x != static_cast< GUM_SCALAR >(0)) 480 return static_cast< GUM_SCALAR >(1); 481 else 482 return static_cast< GUM_SCALAR >(0); 483 }); 484 return p; 485 } 486 487 template < typename GUM_SCALAR > 488 Set< const DiscreteVariable* > complementVars_(const Set<const DiscreteVariable * > & vars)489 Potential< GUM_SCALAR >::complementVars_(const Set< const DiscreteVariable* >& vars) const { 490 Set< const DiscreteVariable* > cplt; 491 492 for (const auto x: this->variablesSequence()) 493 if (!vars.contains(x)) cplt.insert(x); 494 495 return cplt; 496 } 497 498 template < typename GUM_SCALAR > 499 Potential< GUM_SCALAR > reorganize(const std::vector<const DiscreteVariable * > & vars)500 Potential< GUM_SCALAR >::reorganize(const std::vector< const DiscreteVariable* >& vars) const { 501 if (vars.size() != this->nbrDim()) 502 GUM_ERROR(InvalidArgument, 503 "The vector contains " << vars.size() << " variables instead of " << this->nbrDim() 504 << "."); 505 for (const auto var: vars) { 506 if (!this->contains(*var)) 507 GUM_ERROR(InvalidArgument, "A variable in the vector does not belong to the potential.") 508 } 509 510 Potential< GUM_SCALAR > p; 511 p.beginMultipleChanges(); 512 for (const auto var: vars) 513 p.add(*var); 514 p.endMultipleChanges(); 515 p.copyFrom(*this, nullptr); // copy *this in p using the same order 516 517 return p; 518 } 519 520 template < typename GUM_SCALAR > 521 Potential< GUM_SCALAR > reorganize(const std::vector<std::string> & vars)522 Potential< GUM_SCALAR >::reorganize(const std::vector< std::string >& vars) const { 523 std::vector< const DiscreteVariable* > res; 524 525 gum::HashTable< std::string, const gum::DiscreteVariable* > namesToVars; 526 for (gum::Idx i = 0; i < this->nbrDim(); i++) 527 namesToVars.insert(this->variable(i).name(), &(this->variable(i))); 528 529 for (const auto& name: vars) { 530 if (!namesToVars.exists(name)) { 531 GUM_ERROR(gum::InvalidArgument, 532 "'" << name << "' is a not a name of a variable in this potential"); 533 } 534 res.push_back(namesToVars[name]); 535 } 536 return reorganize(res); 537 } 538 539 template < typename GUM_SCALAR > putFirst(const DiscreteVariable * var)540 Potential< GUM_SCALAR > Potential< GUM_SCALAR >::putFirst(const DiscreteVariable* var) const { 541 if (!this->contains(*var)) { 542 GUM_ERROR(InvalidArgument, "The variable to put first does not belong to the potential") 543 } 544 if (&(this->variable(0)) == var) return Potential< GUM_SCALAR >(*this); 545 546 std::vector< const DiscreteVariable* > vars; 547 vars.push_back(var); 548 for (Idx i = 0; i < this->nbrDim(); i++) 549 if (&(this->variable(i)) != var) vars.push_back(&(this->variable(i))); 550 551 return this->reorganize(vars); 552 } 553 554 template < typename GUM_SCALAR > putFirst(const std::string & varname)555 Potential< GUM_SCALAR > Potential< GUM_SCALAR >::putFirst(const std::string& varname) const { 556 const DiscreteVariable* var = nullptr; 557 558 for (gum::Idx i = 0; i < this->nbrDim(); i++) 559 if (this->variable(i).name() == varname) { 560 var = &(this->variable(i)); 561 break; 562 } 563 if (var == nullptr) 564 GUM_ERROR(InvalidArgument, 565 "The variable '" << varname << "' to put first does not belong to the potential"); 566 return this->putFirst(var); 567 } 568 569 template < typename GUM_SCALAR > extract(const Instantiation & inst)570 Potential< GUM_SCALAR > Potential< GUM_SCALAR >::extract(const Instantiation& inst) const { 571 Potential< GUM_SCALAR > p; 572 p.extractFrom(*this, inst); 573 574 return p; 575 } 576 577 template < typename GUM_SCALAR > draw()578 Idx Potential< GUM_SCALAR >::draw() const { 579 if (this->nbrDim() != 1) { 580 GUM_ERROR(FatalError, "To draw from a potential, the dimension must be 1") 581 } 582 583 GUM_SCALAR r = static_cast< GUM_SCALAR >(randomProba()); 584 Instantiation Ip(*this); 585 for (Ip.setFirst(); !Ip.end(); Ip.inc()) { 586 r -= this->get(Ip); 587 if (r <= 0) return Ip.val(0); 588 } 589 return this->variable(0).domainSize() - 1; 590 } 591 592 template < typename GUM_SCALAR > 593 std::ostream& operator<<(std::ostream& out, const Potential< GUM_SCALAR >& array) { 594 out << array.toString(); 595 return out; 596 } 597 598 // argmax of all elements in this 599 template < typename GUM_SCALAR > findAll(GUM_SCALAR v)600 Set< Instantiation > Potential< GUM_SCALAR >::findAll(GUM_SCALAR v) const { 601 Instantiation I(*this); 602 Set< Instantiation > res; 603 604 if (static_cast< MultiDimContainer< GUM_SCALAR >* >(this->content_)->empty()) { return res; } 605 for (I.setFirst(); !I.end(); ++I) { 606 if (this->get(I) == v) res.insert(I); 607 } 608 return res; 609 } 610 // argmax of all elements in this 611 template < typename GUM_SCALAR > argmax()612 INLINE Set< Instantiation > Potential< GUM_SCALAR >::argmax() const { 613 return findAll(max()); 614 } 615 // argmin of all elements in this 616 template < typename GUM_SCALAR > argmin()617 INLINE Set< Instantiation > Potential< GUM_SCALAR >::argmin() const { 618 return findAll(min()); 619 } 620 621 template < typename GUM_SCALAR > random()622 const Potential< GUM_SCALAR >& Potential< GUM_SCALAR >::random() const { 623 if (this->domainSize() == 0) return *this; 624 625 std::vector< GUM_SCALAR > v; 626 GUM_SCALAR sum; 627 v.reserve(this->domainSize()); 628 sum = 0.0; 629 for (Size i = 0; i < this->domainSize(); ++i) { 630 auto r = (GUM_SCALAR)randomProba(); 631 v.push_back(r); 632 sum += r; 633 } 634 if (sum == 0.0) v[gum::randomValue(this->domainSize())] = 1.0; // a 1 somewhere 635 636 this->fillWith(v); 637 return *this; 638 } 639 640 template < typename GUM_SCALAR > randomDistribution()641 INLINE const Potential< GUM_SCALAR >& Potential< GUM_SCALAR >::randomDistribution() const { 642 return this->random().normalize(); 643 } 644 645 template < typename GUM_SCALAR > randomCPT()646 INLINE const Potential< GUM_SCALAR >& Potential< GUM_SCALAR >::randomCPT() const { 647 return this->random().normalizeAsCPT(); 648 } 649 650 template < typename GUM_SCALAR > noising(GUM_SCALAR alpha)651 const Potential< GUM_SCALAR >& Potential< GUM_SCALAR >::noising(GUM_SCALAR alpha) const { 652 if ((alpha < GUM_SCALAR(0.0)) || (alpha > GUM_SCALAR(1.0))) { 653 GUM_ERROR(InvalidArgument, "alpha must be in [0,1]") 654 } 655 Potential< GUM_SCALAR > noise(*this); 656 return fillWith(scale(1 - alpha) + noise.randomCPT().scale(alpha)).normalizeAsCPT(); 657 } 658 659 template < typename GUM_SCALAR > new_abs()660 const Potential< GUM_SCALAR > Potential< GUM_SCALAR >::new_abs() const { 661 return Potential< GUM_SCALAR >(*this).abs(); 662 } 663 664 template < typename GUM_SCALAR > new_sq()665 const Potential< GUM_SCALAR > Potential< GUM_SCALAR >::new_sq() const { 666 return Potential< GUM_SCALAR >(*this).sq(); 667 } 668 669 template < typename GUM_SCALAR > new_log2()670 const Potential< GUM_SCALAR > Potential< GUM_SCALAR >::new_log2() const { 671 return Potential< GUM_SCALAR >(*this).log2(); 672 } 673 674 } /* namespace gum */ 675