bpp-core  2.1.0
MixtureOfDiscreteDistributions.cpp
Go to the documentation of this file.
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 
 All Classes Namespaces Files Functions Variables Typedefs Friends