Line data Source code
1 : /****************************************************************************/ 2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo 3 : // Copyright (C) 2005-2024 German Aerospace Center (DLR) and others. 4 : // This program and the accompanying materials are made available under the 5 : // terms of the Eclipse Public License 2.0 which is available at 6 : // https://www.eclipse.org/legal/epl-2.0/ 7 : // This Source Code may also be made available under the following Secondary 8 : // Licenses when the conditions for such availability set forth in the Eclipse 9 : // Public License 2.0 are satisfied: GNU General Public License, version 2 10 : // or later which is available at 11 : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html 12 : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later 13 : /****************************************************************************/ 14 : /// @file RandomDistributor.h 15 : /// @author Daniel Krajzewicz 16 : /// @author Michael Behrisch 17 : /// @author Jakob Erdmann 18 : /// @date 2005-09-15 19 : /// 20 : // Represents a generic random distribution 21 : /****************************************************************************/ 22 : #pragma once 23 : #include <config.h> 24 : 25 : #include <cassert> 26 : #include <limits> 27 : #include <utils/common/RandHelper.h> 28 : #include <utils/common/UtilExceptions.h> 29 : 30 : 31 : // =========================================================================== 32 : // class definitions 33 : // =========================================================================== 34 : /** 35 : * @class RandomDistributor 36 : * @brief Represents a generic random distribution 37 : * 38 : * This class allows to create random distributions by assigning 39 : * arbitrary (non-negative) probabilities to its elements. The 40 : * random number generator used is specified in RandHelper. 41 : * 42 : * @see RandHelper 43 : */ 44 : 45 : template<class T> 46 74 : class RandomDistributor { 47 : public: 48 : /** @brief Constructor for an empty distribution 49 : */ 50 118815 : RandomDistributor() : 51 766470 : myProb(0) { 52 : } 53 : 54 : /// @brief Destructor 55 803421 : ~RandomDistributor() { } 56 : 57 : /** @brief Adds a value with an assigned probability to the distribution. 58 : * 59 : * If the value is already member of the distribution and checkDuplicates is 60 : * true (the default) the given probability is added to the current. 61 : * The probability has to be non-negative but values larger than one are 62 : * allowed (and scaled accordingly when an element is drawn). 63 : * 64 : * @param[in] val The value to add to the distribution 65 : * @param[in] prob The probability assigned to the value 66 : * @return true if a new value was added, false if just the probability of an existing one was updated 67 : */ 68 2175293 : bool add(T val, double prob, bool checkDuplicates = true) { 69 2175293 : myProb += prob; 70 : assert(myProb >= 0); 71 2175293 : if (checkDuplicates) { 72 4780301 : for (int i = 0; i < (int)myVals.size(); i++) { 73 2623633 : if (val == myVals[i]) { 74 16765 : myProbs[i] += prob; 75 : assert(myProbs[i] >= 0); 76 16765 : return false; 77 : } 78 : } 79 : } else { 80 : assert(prob >= 0); 81 : } 82 2158528 : myVals.push_back(val); 83 2158528 : myProbs.push_back(prob); 84 2158528 : return true; 85 : } 86 : 87 : /** @brief Removes a value with an assigned probability from the distribution. 88 : * 89 : * @param[in] val The value to remove from the distribution 90 : * @return true if a new value was added, false if just the probability of an existing one was updated 91 : */ 92 192 : bool remove(T val) { 93 536 : for (int i = 0; i < (int)myVals.size(); i++) { 94 454 : if (myVals[i] == val) { 95 110 : myProb -= myProbs[i]; 96 110 : myProbs.erase(myProbs.begin() + i); 97 110 : myVals.erase(myVals.begin() + i); 98 110 : return true; 99 : } 100 : } 101 : return false; 102 : } 103 : 104 : /** @brief Draw a sample of the distribution. 105 : * 106 : * A random sample is drawn according to the assigned probabilities. 107 : * 108 : * @param[in] which The random number generator to use; the static one will be used if 0 is passed 109 : * @return the drawn member 110 : */ 111 1322567 : T get(SumoRNG* which = nullptr) const { 112 1322567 : if (myProb == 0) { 113 0 : throw OutOfBoundsException(); 114 : } 115 : double prob = RandHelper::rand(myProb, which); 116 2067642 : for (int i = 0; i < (int)myVals.size(); i++) { 117 2067642 : if (prob < myProbs[i]) { 118 780363 : return myVals[i]; 119 : } 120 745075 : prob -= myProbs[i]; 121 : } 122 0 : return myVals.back(); 123 : } 124 : 125 : /** @brief Return the sum of the probabilites assigned to the members. 126 : * 127 : * This should be zero if and only if the distribution is empty. 128 : * 129 : * @return the total probability 130 : */ 131 : double getOverallProb() const { 132 2559964 : return myProb; 133 : } 134 : 135 : /// @brief Clears the distribution 136 : void clear() { 137 : myProb = 0; 138 : myVals.clear(); 139 : myProbs.clear(); 140 : } 141 : 142 : /** @brief Returns the members of the distribution. 143 : * 144 : * See getProbs for the corresponding probabilities. 145 : * 146 : * @return the members of the distribution 147 : * @see RandomDistributor::getProbs 148 : */ 149 : const std::vector<T>& getVals() const { 150 23418 : return myVals; 151 : } 152 : 153 : /** @brief Returns the probabilities assigned to the members of the distribution. 154 : * 155 : * See getVals for the corresponding members. 156 : * 157 : * @return the probabilities assigned to the distribution 158 : * @see RandomDistributor::getVals 159 : */ 160 : const std::vector<double>& getProbs() const { 161 198 : return myProbs; 162 : } 163 : 164 : private: 165 : /// @brief the total probability 166 : double myProb; 167 : /// @brief the members 168 : std::vector<T> myVals; 169 : /// @brief the corresponding probabilities 170 : std::vector<double> myProbs; 171 : 172 : };