|
bpp-core
2.1.0
|
00001 // 00002 // File: MixtureOfDiscreteDistributions 00003 // Created by: Laurent Guéguen 00004 // Created on: mercredi 9 juin 2010, à 23h 09 00005 // 00006 00007 /* 00008 Copyright or © or Copr. Bio++ Development Team, (November 17, 2004) 00009 00010 This software is a computer program whose purpose is to provide classes 00011 for numerical calculus. 00012 00013 This software is governed by the CeCILL license under French law and 00014 abiding by the rules of distribution of free software. You can use, 00015 modify and/ or redistribute the software under the terms of the CeCILL 00016 license as circulated by CEA, CNRS and INRIA at the following URL 00017 "http://www.cecill.info". 00018 00019 As a counterpart to the access to the source code and rights to copy, 00020 modify and redistribute granted by the license, users are provided only 00021 with a limited warranty and the software's author, the holder of the 00022 economic rights, and the successive licensors have only limited 00023 liability. 00024 00025 In this respect, the user's attention is drawn to the risks associated 00026 with loading, using, modifying and/or developing or reproducing the 00027 software by the user in light of its specific status of free software, 00028 that may mean that it is complicated to manipulate, and that also 00029 therefore means that it is reserved for developers and experienced 00030 professionals having in-depth computer knowledge. Users are therefore 00031 encouraged to load and test the software's suitability as regards their 00032 requirements in conditions enabling the security of their systems and/or 00033 data to be ensured and, more generally, to use and operate it in the 00034 same conditions as regards security. 00035 00036 The fact that you are presently reading this means that you have had 00037 knowledge of the CeCILL license and that you accept its terms. 00038 */ 00039 00040 #include "MixtureOfDiscreteDistributions.h" 00041 #include "../NumConstants.h" 00042 #include "../../Utils/MapTools.h" 00043 #include "../../Text/TextTools.h" 00044 00045 using namespace bpp; 00046 using namespace std; 00047 00048 MixtureOfDiscreteDistributions::MixtureOfDiscreteDistributions(const vector<DiscreteDistribution*>& distributions, 00049 const vector<double>& probas ) : 00050 AbstractParameterAliasable("Mixture."), 00051 AbstractDiscreteDistribution(1, "Mixture."), 00052 vdd_(), 00053 probas_(), 00054 vNestedPrefix_() 00055 { 00056 if (distributions.size() != probas.size()) 00057 { 00058 throw Exception("MixtureOfDiscreteDistributions. Distributions and probabilities vectors must have the same size (" + TextTools::toString(distributions.size()) + " != " + TextTools::toString(probas.size()) + ")."); 00059 } 00060 00061 size_t size = distributions.size(); 00062 for (size_t i = 0; i < size; i++) 00063 { 00064 if (distributions[i] == 0) 00065 throw Exception("MixtureOfDiscreteDistributions. Null DiscreteDistribution* in argument vector at index " + TextTools::toString(i)); 00066 } 00067 00068 for (size_t i = 0; i < size; i++) 00069 { 00070 probas_.push_back(probas[i]); 00071 } 00072 00073 double sum = VectorTools::sum(probas); 00074 if (fabs(1. - sum) > precision()) 00075 throw Exception("MixtureOfDiscreteDistributions. Probabilities must equal 1 (sum =" + TextTools::toString(sum) + ")."); 00076 00077 double y = 1; 00078 for (size_t i = 0; i < size - 1; i++) 00079 { 00080 addParameter_(new Parameter("Mixture.theta" + TextTools::toString(i + 1), probas[i] / y, &Parameter::PROP_CONSTRAINT_IN)); 00081 y -= probas[i]; 00082 } 00083 00084 00085 for (size_t i = 0; i < size; i++) 00086 { 00087 vdd_.push_back(distributions[i]->clone()); 00088 } 00089 00090 // Parameters 00091 00092 for (size_t i = 0; i < size; i++) 00093 { 00094 vNestedPrefix_.push_back(TextTools::toString(i + 1) + "_" + distributions[i]->getNamespace()); 00095 } 00096 00097 for (size_t i = 0; i < size; i++) 00098 { 00099 vdd_[i]->setNamespace("Mixture." + vNestedPrefix_[i]); 00100 } 00101 00102 for (size_t i = 0; i < size; i++) 00103 { 00104 addParameters_(vdd_[i]->getParameters()); 00105 } 00106 00107 updateDistribution(); 00108 } 00109 00110 MixtureOfDiscreteDistributions::MixtureOfDiscreteDistributions(const MixtureOfDiscreteDistributions& mdd) : 00111 AbstractParameterAliasable(mdd), 00112 AbstractDiscreteDistribution(mdd), 00113 vdd_(), 00114 probas_(), 00115 vNestedPrefix_() 00116 { 00117 for (size_t i = 0; i < mdd.vdd_.size(); i++) 00118 { 00119 probas_.push_back(mdd.probas_[i]); 00120 vdd_.push_back(mdd.vdd_[i]->clone()); 00121 vNestedPrefix_.push_back(mdd.vNestedPrefix_[i]); 00122 } 00123 } 00124 00125 MixtureOfDiscreteDistributions& MixtureOfDiscreteDistributions::operator=(const MixtureOfDiscreteDistributions& mdd) 00126 { 00127 AbstractParameterAliasable::operator=(mdd); 00128 AbstractDiscreteDistribution::operator=(mdd); 00129 vdd_.clear(); 00130 probas_.clear(); 00131 vNestedPrefix_.clear(); 00132 00133 for (size_t i = 0; i < mdd.vdd_.size(); i++) 00134 { 00135 probas_.push_back(mdd.probas_[i]); 00136 vdd_.push_back(mdd.vdd_[i]->clone()); 00137 vNestedPrefix_.push_back(mdd.vNestedPrefix_[i]); 00138 } 00139 00140 return *this; 00141 } 00142 00143 MixtureOfDiscreteDistributions::~MixtureOfDiscreteDistributions() 00144 { 00145 for (size_t i = 0; i < vdd_.size(); i++) 00146 { 00147 delete vdd_[i]; 00148 } 00149 00150 vdd_.clear(); 00151 } 00152 00153 void MixtureOfDiscreteDistributions::setNumberOfCategories(size_t nbClasses) 00154 { 00155 for (size_t i = 0; i < vdd_.size(); i++) 00156 { 00157 vdd_[i]->setNumberOfCategories(nbClasses); 00158 } 00159 00160 updateDistribution(); 00161 } 00162 00163 00164 void MixtureOfDiscreteDistributions::fireParameterChanged(const ParameterList& parameters) 00165 { 00166 AbstractDiscreteDistribution::fireParameterChanged(parameters); 00167 size_t size = vdd_.size(); 00168 double x = 1.0; 00169 for (size_t i = 0; i < size - 1; i++) 00170 { 00171 probas_[i] = getParameterValue("theta" + TextTools::toString(i + 1)) * x; 00172 x *= 1 - getParameterValue("theta" + TextTools::toString(i + 1)); 00173 } 00174 00175 probas_[size - 1] = x; 00176 00177 00178 for (size_t i = 0; i < size; i++) 00179 { 00180 vdd_[i]->matchParametersValues(parameters); 00181 } 00182 00183 updateDistribution(); 00184 } 00185 00186 void MixtureOfDiscreteDistributions::updateDistribution() 00187 { 00188 size_t size = vdd_.size(); 00189 distribution_.clear(); 00190 // calculation of distribution 00191 00192 for (size_t i = 0; i < size; i++) 00193 { 00194 vector<double> values = vdd_[i]->getCategories(); 00195 for (size_t j = 0; j < values.size(); j++) 00196 { 00197 distribution_[values[j]] = 0; 00198 } 00199 } 00200 00201 for (size_t i = 0; i < size; i++) 00202 { 00203 vector<double> values = vdd_[i]->getCategories(); 00204 vector<double> probas2 = vdd_[i]->getProbabilities(); 00205 for (size_t j = 0; j < values.size(); j++) 00206 { 00207 distribution_[values[j]] += probas2[j] * probas_[i]; 00208 } 00209 } 00210 00211 numberOfCategories_ = distribution_.size(); 00212 00213 // intMinMax_ 00214 00215 double uB, lB; 00216 uB = -NumConstants::VERY_BIG(); 00217 lB = NumConstants::VERY_BIG(); 00218 00219 bool suB = true, slB = true; 00220 00221 for (size_t i = 0; i < size; i++) 00222 { 00223 if (vdd_[i]->getLowerBound() <= lB) 00224 { 00225 lB = vdd_[i]->getLowerBound(); 00226 slB = vdd_[i]->strictLowerBound(); 00227 } 00228 if (vdd_[i]->getUpperBound() >= uB) 00229 { 00230 uB = vdd_[i]->getUpperBound(); 00231 suB = vdd_[i]->strictUpperBound(); 00232 } 00233 } 00234 00235 intMinMax_.setLowerBound(lB, slB); 00236 intMinMax_.setUpperBound(uB, suB); 00237 00238 // Compute midpoint bounds_: 00239 vector<double> values = MapTools::getKeys<double, double, AbstractDiscreteDistribution::Order>(distribution_); 00240 00241 bounds_.resize(numberOfCategories_ - 1); 00242 00243 // Fill from 0 to numberOfCategories_-1 with midpoints: 00244 for (size_t i = 0; i < numberOfCategories_ - 1; i++) 00245 { 00246 bounds_[i] = (values[i] + values[i + 1]) / 2.; 00247 } 00248 } 00249 00250 void MixtureOfDiscreteDistributions::setMedian(bool median) 00251 { 00252 if (median_ != median) 00253 { 00254 median_ = median; 00255 for (size_t i = 0; i < vdd_.size(); i++) 00256 { 00257 vdd_[i]->setMedian(median); 00258 } 00259 updateDistribution(); 00260 } 00261 } 00262 void MixtureOfDiscreteDistributions::discretize() 00263 { 00264 for (size_t i = 0; i < vdd_.size(); i++) 00265 { 00266 vdd_[i]->discretize(); 00267 } 00268 00269 updateDistribution(); 00270 } 00271 00272 double MixtureOfDiscreteDistributions::pProb(double x) const 00273 { 00274 double s = 0; 00275 for (size_t i = 0; i < vdd_.size(); i++) 00276 { 00277 s += probas_[i] * vdd_[i]->pProb(x); 00278 } 00279 return s; 00280 } 00281 00282 double MixtureOfDiscreteDistributions::qProb(double x) const 00283 { 00284 throw Exception("MixtureOfDiscreteDistributions::qProb to difficult to compute: not implemented"); 00285 return 0; 00286 } 00287 00288 double MixtureOfDiscreteDistributions::Expectation(double a) const 00289 { 00290 double s = 0; 00291 for (size_t i = 0; i < vdd_.size(); i++) 00292 { 00293 s += probas_[i] * vdd_[i]->Expectation(a); 00294 } 00295 return s; 00296 } 00297 00298 void MixtureOfDiscreteDistributions::restrictToConstraint(const Constraint& c) 00299 { 00300 for (size_t i = 0; i < vdd_.size(); i++) 00301 { 00302 vdd_[i]->restrictToConstraint(c); 00303 } 00304 00305 updateDistribution(); 00306 } 00307 00308 /******************************************************************************/ 00309 00310 void MixtureOfDiscreteDistributions::setNamespace(const string& prefix) 00311 { 00312 AbstractDiscreteDistribution::setNamespace(prefix); 00313 // We also need to update the namespace of the nested distributions: 00314 for (size_t i = 0; i < vdd_.size(); i++) 00315 { 00316 vdd_[i]->setNamespace(prefix + vNestedPrefix_[i]); 00317 } 00318 } 00319